数据工程设计模式——数据基础

105 阅读12分钟

引言(Introduction)

本章将帮助读者理解数据工程师用来表示与组织数据的各类数据类型机制。我们将以电商应用为例,进一步讲解数据基础。同时,读者还将接触数据建模(data modeling)的概念以及数据的结构化程度(structuredness)

结构(Structure)

本章将涵盖以下主题:

  • 电商应用示例
  • 结构化数据与表格化表示
  • 半结构化数据与 JSON 数据格式
  • 非结构化数据与二进制数据格式
  • 事务型数据与分析型数据

目标(Objectives)

在本章结束时,我们将能够理解如何把领域数据概念映射到合适的数据类型,如何定义数据结构,以及如何将数据以应用所需的特定格式进行表示。我们也将获得对事务型数据分析型数据的概念性理解。

电商应用示例(E-commerce application example)

考虑一个电商应用:某个卖家希望在其网站展示商品,多个用户会执行注册、登录、购买、退货、求助等操作。现代应用中,每个动作往往包含多个步骤,需要前端界面后端应用服务器之间的复杂交互。

例如,在注册新用户时,前端需要检查用户填写的邮箱地址是否已被注册;底层数据系统需要生成一个唯一标识符,供各子系统唯一识别用户;随后生成用户档案并存入后端数据库。数据工程师需要识别并设计底层数据系统,以确保功能正确、性能可靠且可扩展,从而带来良好的用户体验。在该用例分析中,我们已将用户档案(user profile)识别为一个实体

再看购买商品这一更复杂的多步骤流程。完成购买所需的最小步骤列表如下:

  1. 在搜索框中搜索商品并获取列表;
  2. 选择要购买的商品及数量;
  3. 将商品加入购物车并检查库存;
  4. 接收收货地址并校验配送可达性;
  5. 处理支付、处理支付失败并最终确认订单;
  6. 发货。

每一步都需要读取数据存储中的数据,并将该步的结果写回底层数据存储,供后续步骤继续处理。

例如,第 1 步需要根据搜索查询读取商品目录;第 3 步需要检查用户指定数量是否在库存中可用,并将条目加入购物车。这里,购物车是第 3 步的产出,会被第 5 步用于订单最终确认。在该用例分析中,我们进一步识别出**商品库存(product inventory)购物车(shopping cart)**等实体。

数据建模概览(Overview of data modeling)

聚焦上述示例,我们识别出一组数据对象(data objects) ,如用户档案商品目录商品库存购物车。数据对象代表将被一个或多个数据处理器创建、存储、修改与访问的逻辑数据单元,并可在处理器之间传递。识别并定义数据对象的过程称为数据建模(data modeling)

在识别出数据对象后,下一步是为其定义属性及其所属位置/关联。例如,用户档案应包含:用户名(或 ID)、邮箱、手机号、邮寄地址等;商品目录应包含:商品 ID、商品名称、品牌、价格等。

表 8.1 展示了商品目录中商品的属性及其对应的数据类型

属性名(Property name)数据类型(Data type)
标识符(id)String
名称(Name)String
品牌(Brand)String
价格(Price)Integer

表 8.1:商品目录属性及其数据类型

下面给出商品目录的一个示例定义:

class Product (
    var id: String,
    var name: String,
    var brand: String, 
    var price: Int
)

在该示例中,目录中的每个商品有四个属性:前三个(idnamebrand)用 String 表示,第四个(price)用整数表示。为属性分配正确的数据类型非常重要,这样才能对其执行特定操作。例如,价格是数字,那么在结算时就可以按百分比打折

数据建模取决于应用需求以及底层数据存储技术。高层看,数据建模包括以下任务:

  • 识别并定义数据对象
  • 识别数据对象之间的关系
  • 定义数据对象的存储与检索机制

我们将在本章及后续章节讨论这些任务。

结构化数据与表格化表示(Structured data and tabular data representation)

表格表示结构化数据并使用 SQL 检索的历史可以追溯到 20 世纪 70 年代,这也是关系型数据库管理系统(RDBMS)的核心能力。MySQL 是最流行的 RDBMS 之一,免费开源。MySQL 允许用户创建表、视图、索引来存取结构化数据。

商品目录为例,可在 MySQL 中如下表示:

CREATE TABLE product (
    Id VARCHAR(64),
    Name VARCHAR(255),
    Brand VARCHAR(128),
    Price INT
);

这里,VARCHAR(*) 表示字符串数据类型。

要可视化该 product 表中的数据,可参见表 8.2。该可视化强调两个概念:其一,列内所有条目的数据类型相同;其二,目录中的每个商品在表的所有列上都有合适的取值。这两点共同构成数据所需的结构性。若你的数据具备这些特征,就可以将其视为结构化数据,并选择使用传统 RDBMS进行存储与检索,如下表所示:

IdNameBrandPrice
“Id-0001”“Smartphone A 1.1”“Brand X”239
“Id-0002”“Smartphone B 3.2”“Brand Y”459
“Id-0003”“Smartphone C 8.0”“Brand Z”999

表 8.2:商品目录(Product catalog)

我们将在第 9 章《数据库与事务型数据》中对此进行详细讨论。

半结构化数据与 JSON 数据格式(Semi-structured data and JSON data format)

进入 21 世纪初,技术行业迎来范式转移:互联网更易获取,大量创新型 Web 应用涌现。社交媒体不仅让用户每日消费互联网内容,也让他们持续产出数据——社交帖子、商品评价等日益普遍。

与此同时,大型企业为支持更高频的业务创新,要求底层数据模型更频繁地变化。结构化数据的局限在于强约束的模式(schema) ,难以适应需求的快速变更,于是半结构化数据开始流行。

继续以商品目录为例:现代用户在购买前希望看到详尽的商品信息,但不同品类的属性差异很大。

  • 智能手机:屏幕尺寸、内存、处理器等;
  • 冰箱:容量、门数、除霜方式等。
    电商网站往往售卖上百种品类,并希望快速上新。在此情境下,严格的模式约束会适得其反,半结构化模型更易快速适配

JSON 数据格式(JSON data format)

最流行的半结构化数据格式之一是 JSON(JavaScript Object Notation) 。它是人类可读的开放标准,广泛用于存储与传输数据,现代应用几乎都在使用。

仍以商品目录为例,若希望在目录中存储商品详情,可如下表示:

产品 1 – 智能手机

{
  "Id": "Id-0001",
  "Name": "Smartphone A 1.1",
  "Brand": "Brand X",
  "Price": 239,
  "Details": {
    "Size": 5.4,
    "Memory": "256 GB",
    "Processor": "Proc-A"
  }
}

产品 2 – 冰箱

{
  "Id": "Id-0105",
  "Name": "Refrigerator M",
  "Brand": "Brand K",
  "Price": 1025,
  "Details": {
    "Capacity": 210,
    "doors": 2,
    "defrost": "auto"
  }
}

在上述示例中,手机与冰箱都用 JSON 表示。JSON 以及基于 JSON 的半结构化系统允许我们无需强制模式就能存储并访问“手机的尺寸”“冰箱的容量”等属性。

结构化 vs. 半结构化 数据模型(Structured vs. semi-structured data model)

如上所示,JSON 提供了现代应用所需的模式灵活性。对比之下,结构化模型的模式更刚性。继续以商品目录为例:假设网站最初仅售卖智能手机,则产品属性与类型会专为手机设计,如表 8.3 所示:

表 8.3:智能手机的商品目录模式(Product catalog schema for smartphones)

属性名(Property name)数据类型(Data type)
标识符(id)String
名称(Name)String
品牌(Brand)String
价格(Price)Integer
尺寸(Size)浮点数(Floating point number)
内存(Memory)String
处理器(Processor)String

对应的 SQL 表可能为(7 列):

CREATE TABLE product (
    Id VARCHAR(64),
    Name VARCHAR(255),
    Brand VARCHAR(128),
    Price INT,
    Size FLOAT,
    Memory VARCHAR(32),
    Processor VARCHAR(64)
);

现在若要在目录中新增冰箱品类(属性如容量、门数、除霜模式等),需要在不影响手机属性的前提下增加新列,可通过 ALTER TABLE 实现:

ALTER TABLE Product
ADD COLUMN Capacity INT,
ADD COLUMN Doors INT,
ADD COLUMN Defrost VARCHAR(32);

而若使用 JSON半结构化模型,就无需执行此类 ALTER TABLE,因为 JSON 不强制模式

除上述差异外,结构化(SQL)模型的模式刚性还带来其他限制:

  1. 列值不适用性与存储浪费:同一张产品表中包含多品类数据时,并非所有列对所有品类都有效。例如,手机行中的 DefrostDoors 列无意义,造成存储空间低效;而 JSON 模型无需额外列,避免了额外存储。
  2. 变更成本高ALTER TABLE 通常开销大,尤其当为新列指定默认值时,需要更新既有行,甚至可能在重建表时导致应用停机。而 NoSQL 提供的 JSON 数据模型由于模式灵活,无需执行 ALTER TABLE

选型建议(Choosing a data model)

选择契合需求的数据模型至关重要:

  • 结构化模型因强制模式而更健壮、错误更少
  • 半结构化模型因模式灵活而更易适配变化

二者在底层存储与检索软件上也常不同;一旦系统围绕某种模型设计完成,迁移通常耗时且昂贵。因此,在设计大型数据系统时,应尽早做出正确的数据模型选择。

非结构化数据与二进制数据格式(Unstructured data and binary data format)

在智能手机普及的时代,人人都是“摄影师、摄像师”。每天都会产生海量非结构化数据:文本、图像、视频等。许多现代场景需要低成本存储并在需要时高效检索这些数据。非结构化数据通常体量更大,通常存放于数据湖(多以对象存储为后端),而不是传统数据库或数据仓库。文本、图片与视频在写入数据湖前,会被编码为二进制格式

现代应用广泛利用 AI/ML 从非结构化数据中提取智能。例如,电商网站上的商品评论(文本)可用于情感分析;聚合结果可帮助识别净负向评价的商品并下架。又如,若用户想通过上传相似图片来搜索商品,数据工程师可以使用向量数据库以图搜图管线来实现。关于这类业务用例所用的数据工程模式,将在第 16 章《领域特定模式》中学习。

事务型数据与分析型数据(Transactional and analytical data)

日常业务操作产生(或为其所需)的数据称为事务型数据。事务型数据通常存放在事务型数据库中,其对应的应用称为 OLTP(联机事务处理)应用。延续电商示例,用户注册、订单确认、记录支付失败等日常活动都依赖事务型数据。由于需要极低时延的存取以保障用户体验,故此类数据使用事务数据库存储。对电商网站而言,事务数据读写的质量与速度直接决定用户交互体验。

与之相对,分析型数据经过筛选与整备,用于分析、商业智能(BI)、战略决策等特定场景。以“下架净负评商品”为例,工程与业务协作可如下实施:

  1. 明确识别净负评所需的信息子集(例如只需商品 ID评论,无需完整商品详情)。
  2. 构建 ETL 管道,将筛选与整备后的数据存入分析型存储
  3. 执行情感分析,并保存其输出结果
  4. 运行分析查询,得到净负向反馈商品清单。

以上过程体现了事务型分析型数据的差异。执行数据分析的用户应用称为 **OLAP(联机分析处理)**应用。第 2 章《数据工程模式、术语与技术栈》与第 3 章《批量摄取与处理》将进一步讨论与 OLTP/OLAP 相关的概念与模式。

下表(表 8.4)概括了事务型与分析型数据系统的差异(详细差异见第 10 章《数据仓库与数据分析》):

表 8.4:OLTP 与 OLAP 系统差异概览

维度OLTP 系统OLAP 系统
数据来源通常由面向用户的日常业务应用产生通常从 OLTP 系统摄取作为后续分析输入
存储介质多为事务型数据库多为数据仓库
典型使用者终端用户数据分析师
时延需求极低时延(直接影响用户体验)较高时延可接受(可降低软硬件成本)

结语(Conclusion)

本章通过引入数据建模,奠定了数据工程基础;结合示例,理解了结构化、半结构化、非结构化数据及其建模方式,以实现业务目标;并介绍了事务型数据分析型数据的概念。

下一章将讨论关系型与 NoSQL 数据库事务数据语义,以及 OLTP 应用常用的设计模式