本节书摘来自华章出版社《大数据系统构建:可扩展实时数据系统构建原理与最佳实践》一书中的第2章,第2.1节,南森·马茨(Nathan Marz) [美] 詹姆斯·沃伦(JamesWarren) 著 马延辉 向 磊 魏东琦 译,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
第2章
大数据的数据模型
本章内容
数据的属性
基于事实的数据模型
大数据基于事实的模型的优点
图模式
在第1章中,你看到了使用传统工具构建数据系统时所走入的误区,然后我们回到基本原理,以获得更好的设计。可以看到,每一个数据系统都可以被定义为数据上用来计算的函数,并且你学习了Lambda架构的基础,这种架构提供了一种用来实时声明任意数据上的任意函数的可行性方法。
Lambda架构的核心是主数据集,这在图2-1中是突出显示的。在Lambda架构中,主数据集是计算系统中的事实来源。即使失去了所有的服务层数据集和速度层数据集,你仍然可以从主数据集中重构应用程序。这是因为由服务层来服务的批处理视图是由主数据集上的函数生成的,并且由于速度层只基于近期的数据,它可以在几个小时内进行自动重构。
主数据集是Lambda架构中唯一不能受损的部分。过载的机器、失效的磁盘以及停电都可能导致错误的发生,动态数据系统中的人为错误是内在风险且可能无法避免。你必须仔细设计主数据集,以避免所有这些情况下的数据损坏,因为容错对于长时间运行的数据系统能够正常工作是至关重要的。
对于主数据集,我们将探讨两个方面:所使用的数据模型以及如何物理地存储主数据集。本章介绍主数据集的数据模型的设计以及一个数据模型应有的属性。第3章介绍如何物理地存储主数据集。
在本章,你应掌握如下内容:
掌握数据的关键属性
查看这些属性如何维护基于事实的模型
查看主数据集基于事实的模型的优点
使用图模式表示基于事实的模型
下面从具有普遍性的术语数据展开讨论。
2.1 数据的属性
按照本书的侧重点,我们将围绕一个示例应用程序展开讨论。假设你正在设计下一个大型社交网络—FaceSpace。当一个新的用户(名叫Tom)加入这个网站时,他开始邀请他的朋友和家人。关于Tom这个用户,你应该存储什么信息?你有很多选择,其中包括以下几种:
Tom朋友和非朋友事件的序列
Tom当前朋友的列表
Tom现在朋友的数量
图2-2展示了这些选项和它们之间的关系。
这个例子说明了信息的依赖性。请注意,每一层的信息可以从前一个(其左边)获取到,但这是一个单向的过程。从朋友和非朋友事件的序列,你可以确定其他的数量。但是如果你只有朋友的数量,就不可能准确地知道他们是谁。同样,从当前朋友的列表中,不可能确定Tom是Jerry以前的一个朋友,或者近来Tom的社交圈子有所增长。
概念的依赖性决定了我们将要使用的术语定义:
信息是与大数据系统相关的知识的一般集合。这是“数据”一词的口语化表达。
数据是指不能来源于任何其他东西的信息。数据是衍生一切的公理。
查询是向数据“询问”的问题。例如,你通过查询财务交易历史来确定自己目前的银行账户余额。
视图是来自基础数据的信息,用来协助完成特定类型的查询。
图2-3展示了FaceSpace的数据、视图和查询这些术语的信息依赖性。
注意,一个人的数据可以成为另一个人的视图,这是很重要的。假设FaceSpace已成为一个非常成功的网站,并且现有某第三方广告商创建了一个网络爬虫,用来从该网站的用户资料中获取人口统计信息。FaceSpace可以完全访问Tom所提供的信息—比如他完
整的出生年月日(1984年3月13日)。但Tom对他的年龄很敏感,他只会让3月13日这一信息出现在自己的公开资料中。从FaceSpace的角度来看,Tom的生日是一个视图,因为生日来自他的出生日期,但对广告商来说这已经是数据了,这是因为他们只掌握Tom很有限的信息。这种关系如图2-4所示。
通过建立一个共享的词汇库,我们现在可以介绍数据的关键属性:原始性、不变性和永久性(或“数据的永恒真实性”)。这三个关键属性是理解大数据系统的基础。
如果你有关系型数据库的知识背景,这可能会让你感到困惑。典型的表现就是你会通过不断更新和总结信息来反映当前世界的状态,而不关心不变性或永久性。但这种方法限制了你可以利用数据回答的问题,并且对于避免错误和损坏来说也不够“鲁棒”。通过实现大数据世界里的关键属性,你会构建一个鲁棒性更高的系统,获得更强大的功能。
下面将深入讨论数据的原始性。
2.1.1 数据是原始的
数据系统根据已经获取到的信息回答问题。当设计大数据系统时,你希望它能够回答尽可能多的问题。在FaceSpace示例中,这一社交网络所拥有的数据比广告商的数据更有价值,因为你可以据此推断出更多关于Tom的信息。我们将这个属性通俗地称为数据的原始性。如果可以,你需要存储可以获得的最原始的数据。所存储的数据越原始,可以问的问题就越多。
FaceSpace示例有助于说明数据原始性的价值,但是现在让我们通过另一个例子来更好地理解这个观点。股市交易价格是信息的来源,每天都有数以百万计的股票和数十亿的美元在转手。随着这些海量交易的发生,我们每天都会记录股票的历史价格,包括开盘价、最高价、最低价和收盘价。但这些数据通常无法描述股市的大局,并且可能会改变你对某些事情的看法。如图2-5所示,它记录了当Google针对竞争对手发布了新产品时,Google、Apple和Amazon的股票在一天之内的价格数据。
这份数据表明,Amazon可能没有受到Google公告的影响,因为它的股票价格只有轻微波动。这份数据还表明,Google的公告对Apple完全没有影响,或者说造成了积极的影响。
但是如果可以访问以更细时间粒度存储的数据,你就能得到关于那一天所发生事件更清晰的总体图像,并据此进一步探究潜在的因果关系。图2-6实时描述了三家公司股票价格的相对变化,这表明Amazon和Apple确实受到了这份公告的影响,且Amazon比Apple受到的影响更大。
还要注意的是,额外的数据可以阐述一些你可能在查看原来每天的股票价格概要时没有考虑到的新方向。例如,更细粒度的数据让你怀疑Amazon是否受到了更大的影响,因为Google的新产品与Amazon在平板电脑和云计算市场都产生了竞争。
存储原始数据有巨大的价值,因为你很少提前想好所有问题的答案。通过尽可能地保存原始数据,你可以充分利用自己的能力来获得新的见解,因为汇聚、重写或删除信息限制了数据可以告诉你答案的数量。交易数据通常需要很多的原始数据—有时是海量数据。而大数据技术就是用来管理PB和EB级别的数据。具体来说,它们是以一种分布式的、可扩展的方式管理数据,同时提供直接对数据进行查询的能力。
尽管概念很简单,但你并不总是清楚应该存储什么信息以作为原始数据。下面将提供几个例子来帮助和引导你做出这个决定。
1.非结构化的数据比规范化的数据更原始
在决定存储什么原始数据时,一个常见的令人困惑之处就是解析和语义规范化之间的界线。语义规范化是将任意格式的信息变成结构化形式的数据的过程。
例如,FaceSpace可能会请求Tom给出自己所处的地理位置。他可能会输入该字段的任何信息,如San Francisco(旧金山)、CA、SF、North Beach(北滩)等。语义规范化算法会尝试将输入数据匹配为已知的地方,如图2-7所示。
如果遇到非结构化位置的字符串形式的数据,那么随后在调整算法时你应该存储非结构化的字符串形式,还是语义规范化的形式?我们认为最好存储非结构化的字符串,因为
语义规范化算法可能随着时间的推移有所改进。如果存储的是非结构化的字符串,那么随后在调整算法时你就可以重新规范化数据。在前面的示例中,你可以随后调整算法来识别North Beach在San Francisco附近,或者将相关信息作为他用。
如果出现下述情况,需要存储非结构化数据:作为经验法则,如果用于提取数据的算法简单、准确,比如从HTML页面中提取年龄信息,那么应该存储该算法的结果。如果出于改进或扩大的需求,算法经常要变化,那么应该存储非结构化数据。
2.更多的信息并不意味着更原始的数据
通常人们会很容易地认为,更多的数据相当于更原始的数据,但事实并非总是如此。假设Tom是一个博主,他想将自己的文章添加到FaceSpace资料中。当Tom提供了他博客的URL地址时,你究竟应该存储什么?
存储博客记录的纯文本无疑是一种可能性。但Tom特意强调了任何斜体、黑体、大字体的短语—在文本分析中,它们可能是有用的。例如,你可以使用这些额外的信息作为索引,使得FaceSpace可以被搜索到。因此我们认为,与ASCII的文本字符串相比,带注释的文本记录是一种形式更为原始的数据。
此外,你也可以存储Tom博客完整的HTML。然而,这会在总字节数、配色方案、网站样式方面存储相当多的数据,并且该网址的JavaScript代码不能用来获得任何关于Tom的额外信息。它们只是作为网站内容的容器,而不应该作为原始数据的一部分。
2.1.2 数据是不可变的
如果你精通关系型数据库,想必会觉得不可变的数据似乎是一个奇怪的概念。毕竟在关系型数据库和大多数其他数据库中,更新是最基本的操作之一。但就不变性来说,你不会更新或删除数据,你只是添加更多的数据。通过对大数据系统使用不可变模式,你将获得两个至关重要的优势:
容忍人为错误—这是不可变模式最重要的优势。正如第1章所讨论的,容忍人为错误是数据系统的基本属性。人都会犯错误,你必须对这种错误所带来的影响予以限制,并且需要有恢复机制。对于可变的数据模型,一个错误会导致数据的丢失,因为在数据库中,值会被覆盖掉;而对于不可变的数据模型,没有数据会丢失。如果写入坏数据,更早些(好)的数据单元仍然存在。修复数据系统只是删除损坏的数据单元,并重新计算由主数据集生成的视图。
简易性—可变的数据模型意味着数据必须以某种方式被索引,这样特定的数据对象才可以被获取和更新。相反,对于不可变的数据模型,你只需要能够添加新的数据单元到主数据集中。这样数据就不需要索引,这是一种巨大的简化。在第3章中你会看到,存储主数据集和使用普通文件一样简单。
当与可变的数据模式进行比较时,保持数据不可变的优势就会变得很明显。图2-8所示的基本可变模式可以为FaceSpace所用。
如果Tom搬到Los Angeles(洛杉矶),你就要更新突出显示的记录,以反映他目前所处的位置—但在这个过程中,你也会失去Tom之前在San Francisco的所有信息。
对于不可变模式,情况则完全不同。不可变模式并不是存储当前系统的快照,这是可变模式做的。不可变模式是每次用户信息有变化时,就创建一个单独的记录。完成该项工作需要两个变化:第一,用一个单独的表追踪用户信息的每个字段;第二,当信息真实时,及时将每个数据的单元和一个时刻连接在一起。图2-9显示了存储FaceSpace信息所对应的不可变模式。
Tom于2012年4月4日注册了FaceSpace,并提供了他的个人信息。你首先了解到,这些数据的时间戳反映了记录的时间。当他后来于2012年6月17日搬到了Los Angeles时,你需要在位置表中添加一个新的记录,时间戳是他改变个人资料的时间,如图2-10所示。
现在有Tom的两个位置记录(用户ID 为3),并且因为数据单元与特定的时间绑定,所以它们都是真实的。Tom的当前位置涉及对数据的简单查询:查看所有位置,并选择有最近时间戳的位置。通过在一个单独的表中保存每个字段,你只需要记录更改的信息。这需要更少的存储空间,并保证每条记录都是新的信息,而不仅仅是从最后一条记录转入。
不可变模式的代价之一是它比可变模式使用了更多的存储。首先,用户ID对于每一个属性都是特定的,而不像可变模式那样一行一个。此外,存储的是所有时间段的事件,而不是系统的当前状态。但是被称作“大数据”并不是毫无原因的。你应该充分利用大数据技术的能力来存储海量数据,以获得不变性的优势。当然,也不能夸大一个简单而较能容忍人为错误的主数据集的重要性。
2.1.3 数据是永远真实的
不变性的主要结果是,每一块数据都是永远真实的。也就是说,一块数据一旦真实,那么就必须始终真实。如果不具备这个性质,数据的不可变性就无从谈起了。你已经了解了通过打上时间戳来标记一块数据—这是一种使数据永远真实的可行方法。
这种思路和你在学校学历史是一样的。由于“1776年7月4日,美国包括13个州”这一信息总是正确的,因此“自那时以来州的数量已经增加”的事实就被捕获到额外的(也是永久的)数据中了。
一般来说,通过添加新的不变的和永远真实的数据,主数据集会持续增长。但是在一些特殊的情况下,你需要删除数据,这些情况和数据的永远真实性并不矛盾。具体情况如下:
垃圾回收—当执行垃圾回收操作时,你应删除所有价值较低的数据单元。你可以使用垃圾回收,来实现控制主数据集增长的数据保留策略。例如,你可以决定实现一个策略,即每人每年仅保留一个位置,而不是每次用户更改位置的全部历史。
法规—在特定条件下,政府法规可能会要求清除数据库中的数据。
在这两种情况下,删除数据不是对数据真实性的声明。相反,它是对数据价值的声明。虽然数据永远是正确的,但是你可能更愿意“忘记”一些信息,要么是因为你必须这么做,要么是因为相对于所花费的存储成本它不能实现足够的价值。
我们将使用数据的这些关键属性,继续引入另一个数据模型。
删除不可变数据?
你可能会疑惑,我们怎么才能删除不可变的数据。从表面上看,这似乎是矛盾的。一个很重要的方面是要区分对待,这里所说的“删除”是一种特殊的和少见的情况。在正常使用中,数据是不可变的,并且需要通过采取一些强制策略(如设置适当的权限),来确保其不可变。由于删除数据的情况很少发生,因此要非常谨慎地确保它能够安全删除。首先需要生成“坏的”数据被过滤掉的主数据集的另一个副本,其次运行分析工作来验证正确的数据是被过滤后的,最后再取代主数据集的旧版本—通过上述操作步骤来完成数据删除是最安全的方式。