我们在设计一个信息系统时必然涉及到数据的存储,而数据存储用得最多的就是关系数据库。通常我们会将数据按业务分类,并设计相应的表,然后将对应的信息保存到相应的表中。比如一个企业信息管理系统,我们需要保存员工基本信息:工号、姓名、性别、出生日期等等;我们就会建立一个对应的员工(staff)表。像通过关系型数据库的二维表结构(行和列)来逻辑表示数据结构,并且数据结构变化不会经常性发生,我们称之为结构化数据。相比之下,比如员工的声音,图像等数据,因为不同员工之间可能存在很大的差异,我们很难用某种特定逻辑结构来进行描述,因此称之为非结构化数据。在关系数据库中通常使用blob(二进制编码)来进行进行非结构化数据。
半结构化数据,是介于结构化和非结构化之间的数据。它是结构化的数据,但是结构变化很大。因为我们要了解数据的细节所以不能将数据简单的组织成一个文件按照非结构化数据处理,由于结构变化很大也不能够简单的建立一个表和它对应。
比如员工的简历,它不像员工基本信息那样一致,每个员工的简历大不相同。有的员工的简历很简单,比如只包括教育情况;有的员工的简历却很复杂,比如包括工作情况、婚姻情况、出入境情况、户口迁移情况、党籍情况、技术技能等等。还有可能有一些我们没有预料的信息。通常我们要完整的保存这些信息并不是很容易的,因为我们不会希望系统中的表的结构在系统的运行期间进行变更。
随着互联网技术(尤其是移动互联网,物联网)的飞快发展,使得数据的差异性变大,因此非结构化数据的数量日趋增大。这时,主要用于管理结构化数据的关系数据库的局限性暴露地越来越明显。因而,数据库技术相应地进入了“后关系数据库时代”,发展进入基于网络应用的非结构化数据库时代。所谓非结构化数据库, 是指数据库的变长纪录由若干不可重复和可重复的字段组成,而每个字段又可由若干不可重复和可重复的子字段组成。简单地说,非结构化数据库就是字段可变的数 据库。比如NoSQL数据库MongoDB,全文搜索数据看Elastic Search等。
半结构化数据中结构模式附着或相融于数据本身,数据自身就描述了其相应结构模式。具体来说,半结构化数据具有下述特征:
(1)数据结构自描述性。结构与数据相交融,在研究和应用中不需要区分“元数据”和“一般数据”(两者合二为一)。
(2)数据结构描述的复杂性。结构难以纳入现有的各种描述框架,实际应用中不易进行清晰的理解与把握。
(3)数据结构描述的动态性。数据变化通常会导致结构模式变化,整体上具有动态的结构模式。
常规的数据模型例如E-R模型、关系模型和对象模型恰恰与上述特点相反,因此可以成为结构化数据模型。而相对于结构化数据,半结构化数据的构成更为复杂和不确定,从而也具有更高的灵活性,能够适应更为广泛的应用需求。
化解为结构化数据
这种方法通常是对现有的信息进行粗略的统计整理,总结出信息所有的类别同时考虑系统真正关心的信息。对每一类别建立一个子表。比如上面提到员工简历我们可以建立教育情况子表、工作情况子表、党籍情况子表等等,并在主表中加入一个备注字段,将其它系统不关心的信息和一开始没有考虑到的信息保存在备注中。
优点:查询统计比较方便。
缺点:不能适应数据的扩展,不能对扩展的信息进行检索,对项目设计阶段没有考虑到的同时又是系统关心的信息的存储不能很好的处理。
用XML格式来组织并保存到CLOB字段中
XML很适合存储半结构化的数据,只需要将不同类别的信息保存在XML的不同的节点中就可以了。
优点:能够灵活的进行扩展,信息进行扩展时只要更改对应的DTD或者XSD。
缺点:查询效率比较低,要借助XPATH来完成查询统计。
用JSON格式来组织并保存到CLOB字段中
JSON非常适合存储半结构化的数据,只需要将不同类别的信息保存在JSON的不同的节点中就可以了。
优点:能够灵活的进行扩展,信息进行扩展时只要在应用程序来控制JSON对应的Schema。
缺点:查询效率比较低,要通过数据库本身提供的JSON处理方法来完成查询统计。
Elastic Search可以用来保存json类型的半结构化的数据,并提供更具json的schema定义的字段进行信息查询。
它首先定义了一个通用的文档格式(包含_index,_type,_id, _version,_score,_source等),然后我们可以根据业务需要来定义自己的schema,把数据保存到_source字段。
比如:
{
"_index": "deltadata_v1", ---- common fields
"_type": "_doc", ---- common fields
"_id": "share_issued_and_asset_raised-F00001468C-20200730", ---- common fields
"_version": 1, ---- common fields
"_score": null, ---- common fields
"_source": { ----- 根据需要自定义自己的数据格式,在自己的schema中,也可以根据不同的数据类型,来动态的设置data字段的schema
"kafkaWorkflow": "share_issued_and_asset_raised",
"instrumentId": "F00001468C",
"asOfDate": 20200730,
"updatedOn": 1596182547005,
"kafkaTimestamp": 1596182540033,
"data": {
"PreferredAssetRaised": null,
"ShareOutstanding": 3704772.13,
"SharePubliclyTraded": null,
"AssetRaised": null,
"NumberOfShareHolder": null,
"CommonShareOutstanding": null,
"IPOValue": "0",
"ShareAuthorized": null,
"CommonAssetRaised": null
}
}
}
数据保存到数据库之后,我们可以根据自己定义的json schema进行内容检索,例如
GET /deltadata/_doc/_search?pretty&version=true
{
"query": {
"bool": {
"must": [
{ "match": { "kafkaWorkflow": "share_issued_and_asset_raised" }
}
]
}
},
"sort": {"updatedOn": { "order": "desc" }}
}