zoukankan      html  css  js  c++  java
  • 各式结构化数据 动态 接入-存储-查询 的处理办法 (第一部分)

    各式结构化数据的动态接入存储查询,这一需求相信有很多人都遇到过,随着实现技术路线选择的不同,遇到的问题出入大了,其解决办法也是大相径庭。数据存储在哪儿,是关系型数据库,还是NoSQL数据库,是MySQL还是Oracle,怎么建立索引,建立什么类型的索引,都是大学问。下面,我要把我对这一解决办法的思考总结一下,有成熟的也有不成熟的,希望大家一起共同探讨。
    关键词:结构化数据, 动态, 接入, 存储, 查询

     
    首先,我们得定义一下在本文中什么是结构化数据,这里的结构化数据主要是指扁平化的、可以由基础数据类型组合成的数据,例如:{"data":{"name":"wang anqi","age":28,"money":1653.35,"XX_date":"2013-12-3"}},它们是可以很容易存入关系型数据库的,我们要讨论的就是这种数据。对应的,非结构化数据这里是指那些需要存储在文件系统中的,不是扁平化的数据。
     
    那么,什么又是“各式结构化数据”呢,在本文中?这是一个数据集合,有可能集合中的每一条数据结构都是不尽相同的,例如:{"data":{"name":"wang anqi","age":28,"money":1653.35,"XX_date":"2013-12-3"}},和{"angel":{"address":"清凉山公园","user":289770363}}同时存在于一个数据集合中,它们结构不同,简单地说:第一条数据有四个属性,第二条数据只有两个属性,属性名称和类型都不一样。“各式”包括了不定数量的属性,不定的属性名称、不定的数据类型。
     
    解释清楚名词了,再解释一下动词:“动态接入”。在普遍情境下,你只会遇到将固定数据结构的数据存储入库,这里的入库主要还是指MySQL一类的关系型数据库。那么你可以选择使用Hibernate等ORM工具或不使用,来进行数据的存储读取,在使用ORM工具的情况下,要首先定义好数据的数据结构,写死在xml里或是java代码里。
     
    一般情况下,你是不会遇到这样的需求的:对于不能事先确定数据结构的数据,我要把它们存储到关系型数据库中,并提供“合法性检验”、“更新”、“查询”等基本数据操作。要说的是,如果要把它们存储到HBase这种NoSQL数据库中,那是再好不过的了,配合着HBase与Solr的集成(详见之前的博客:大数据架构-使用HBase和Solr将存储与索引放在不同的机器上),搜索也不是件难事,唯一可能出现的难点在于:Solr对于Schema中filedName的配置,因为结构是动态的,所以fildName也是动态的,这其实也是很好处理的,有位微软的同学已经跟我咨询过这个问题了;事实上,这样的例子是很常见的。
     
    但是往往,事与愿违,很有可能存在着其它的约束条件制约着你:必须使用关系型数据库,那么一整套解决办法是需要设计的。因为当你使用Hibernate时,你不能再把一个数据结构写死在代码里,因为它不是固定的,你该如何入库,该如何查询数据,这都是问题。
     
    要处理好“各式结构化数据动态接入管理”,应该分成以下几步:一、定义数据;二、动态管理;三、数据接入;四、数据查询。
     
    一、定义数据

     
    假如相关业务单位提供的有这么一类数据,这里用一条数据举例来说明:产品A 产品序列号为:A8815001 生产日期为:2013/12/09 13:33:33 供应商为:阿里巴巴 产品质量为:509g 是否合格为:是。我们可以从中大致看出各字段的数据类型,通过面向对象的方法定义出这么一个产品A类也很容易。现在我们要把这条数据存储到关系型数据库中,还是需要一引起先前处理的。 
     
    定义数据是基础,无论你的数据结构再怎么不固定,它也应该有个名字,它的属性也应该是由基础数据类型构成的。基础数据类型就像是构成世界万物的基本元素Ka、Ca、H、O等(请原谅我的灵感来自于《绝命毒师》),它们肯定是要事先定义好的,我们数据库中能够接入的数据必须由这些组成,如 StringIntegerLongBigDecimalBooleanCalendarDateTimeBlob等,Time是以什么样的格式存在的,18:09:32还是18:9:32.3?Date是以什么样的格式存在的,2000-10-8 18:09:32还是2000/10/8 18:9:32.3?
     
    因此基础数据类型,需要作为一项很重要的业务约定,同各个“干系人”共享。就是说,在这里,我定义的基础数据类型,并不是我一个人说的算了的,而是要同相关业务单位开会沟通,这些基础数据类型是否可以囊括它们提供的数据结构的所有内容。毕竟,要接入的数据类型是由他们提供的,他们事先也需要把各种数据类型定义好,比如上面的产品A的结构,都要以文档《产品A数据结构定义》的形式记录下来。在这一步需要产生一个文档,《基础数据定义文档》。
     
    光是有基础数据类型的概念还远远不够,可能在产品A的数据结构文档中,还定义了某一属性值是否可为空,它的取值范围是多少,以及其它业务相关的配置等等,那么就需要有一张数据定义表,来记录对数据的要求。举个例子,我们要接入管理的数据有:产品A,根据文档《产品A数据结构定义》和《基础数据定义文档》和《业务需求文档》,它的数据结构可以在数据库中被定义成这样:
     
    类型名称(DATA_TYPE) 属性中文名称(ATTR_CNAME) 属性名称(ATTR_NAME) 属性类型(ATTR_TYPE) 是否可空(IS_NULLABLE) 属性长度(ATTR_LENGTH) 是否可查(IS_SEARCHABLE) 属性约束(ATTR_RES) ......
    产品A 产品序列号 PRO_SEQ String F 32 T ^[sS]{0,32}$  
    产品A 生产日期 PRO_DATE Date F 19 T ^d{4}-d{2}-d{2}( )+d{2}(:d{2}){2}$  
    产品A 供应商 SUPPLY String T 60 T ^[sS]{0,60}$  
    产品A 产品质量 WEIGHT Integer F 5 T ^d{1,5}(.d*)?$  
    产品A 是否合格 IS_QUALIFIED Boolean T 1 F ^d{1,1}(.d*)?$  
    ......                
     
    说明一下,这是的“是否可查”表示的是是否可以针对此属性作为查询条件,进行数据搜索,这是业务相关的;这里的“属性约束”一列,它采用“正则表达式”的方式,在验证数据正确性时,将起到很大的作用。验证数据正确性这部分逻辑,放在数据接入中做。
    这样一来,我们就能把对“产品A”这种数据类型的具体的数据要求放在数据库中存储起来,我们估且把这些数据要求集合而成的表命名为:属性表(TBL_ATTRIBUTE),当然这是可以通过使用Hibernate的方式来进行增删改的操作的。别忘了,一个数据类型的增删改,还需要改一张表:数据类型管理表(TBL_DATATYPE),它存储了所有的被动态接入管理的数据类型,其表结构及其可能存储的数据内容如下所示:
     
    类型名称(DATA_TYPE) 表名(TABLE) 创建时间(CREATE_TIME) 修改时间(MODIFY_TIME) ......
    产品A TBL_PRO_A 2014/10/8 8:43:23 2014/10/8 15:2:12  
    产品B TBL_PRO_B 2014/10/8 10:16:56 2014/10/8 16:37:7  
    ......        
     
    二、动态管理

     
    定义完了要接入的数据类型,我们需要的是有这么一个函数来完成:addDataType(DataType dt, List<Attribute> attrList)的功能,只要我们定义好了DataType数据类型、List<Attribute>属性列表,那么我们就要能够动态地把这种数据类型加入“王安琪豪华数据”中进行管理。数据类型的管理容易,通过数据类型管理表(TBL_DATATYPE)和属性表(TBL_ATTRIBUTE),将传入的 DataType dt 和 List<Attribute> attrList 入库即可,主要的难点还是在于动态的把此种数据类型的存储表建立起来,因为每定义一种数据类型就要创建一张表。在这一步,我们需要产生或更新三张表:数据类型管理表(TBL_DATATYPE)、属性表(TBL_ATTRIBUTE)和产品A表(TBL_PRO_A)。
    对于举例的“产品A”,它生成的存储表中的内容应该是这样的:
     
    PRO_SEQ PRO_DATE SUPPLY WEIGHT IS_QUALIFIED
    A0001234567 2011-06-09 12:29:19 杭州诺基亚西门子科技有限公司 398 1
    Angel89Wang 2013-04-05 08:10:23 江苏金陵科技有限公司 125  
    ......        
     
    在填入这些数据之前,我们应该把这张表建立起来,建立的依据就是数据类型管理表(TBL_DATATYPE)和属性表(TBL_ATTRIBUTE)中对“产品A”的定义,要创建的表名为:TBL_PRO_A,各个列名为:PRO_SEQ(32字符串型)、PRO_DATE(时间型)、SUPPLY(60字符串型)、WEIGHT(5位整数型示)、IS_QUALIFIED(布尔型)。
     
    在这里,我使用的是Hibernate所支持的tableName.hbm.xml来动态生成表的,当然在此之前,需要先把tableName.hbm.xml文件按照定义的格式生成好。然后再调用SchemaUpdate schemaUpdate = new SchemaUpdate(config);

    schemaUpdate.execute(truetrue);来生成表。

     
    其实动态管理这一步,就不只是动态建表这么简单,上面说的比较狭隘,从广义上理解,它应该被分解为下面几个操作:1、动态创建;2、动态修改;3、动态删除。
     
    动态创建就是通过addDataType(DataType dt, List<Attribute> attrList)来实现的那么我们还需要:removeDataType(String dataTypeName)来实现动态删除,updateDataType(DataType dt, List<Attribute> attrList)来实现动态修改。
     
    动态创建就是刚刚说的那一部分,通过在数据类型管理表(TBL_DATATYPE)、属性表(TBL_ATTRIBUTE)中添加一个数据类型,并动态生成一张存储表。动态修改就比较麻烦了,数据类型管理表(TBL_DATATYPE)、属性表(TBL_ATTRIBUTE)中内容容易修改,可是如果数据存储表中存有数据,应该怎么处理。我采用了和一般数据库通用的处理方式,若表中有数据,则不给动态修改,必须通过删除再创建的方式来达到效果。动态删除,我采用的处理方式是,先删除此种数据类型定义,也即在数据类型管理表(TBL_DATATYPE)和属性表(TBL_ATTRIBUTE)把相应数据删除,然后再删除实际存储表中的数据。当然,具体的处理方法,还是要跟相关业务单位协商,了解他们的需求,如果他们就是不要删除数据存储表中的数据呢。
     
    态建表是这里比较容易出问题的地方,因为如果我们新建一种数据类型:“typeA”,然后再把这个数据类型删除,此时就要处理好它在Hibernate上下文中的位置,也要从Hibernate上下文中删除,据我所知,Hibernate对这个还没有支持,也可能是我才疏学浅,欢迎各位提供解决办法。
     
    存在问题
    1、数据字典问题
    数据字典是数据管理系统中经常使用的,这主要是用来保证灵活性的,它基本是由key-value键值对来实现的,在实际数据存储中存储key,但在显示时取出value用来显示。它的好处为:更改value不改key,可以做到显示灵活配置,比如TB在系统中原先显示为“淘宝”,后来想要它显示为“TaoBao”,那么只要在数据字典项中更改value值即可。
    那么问题就来了,假如数据类型A中某属性应用了某数据字典,key-value1,它要存储的是key,那么我们就还要对这一数据字典进行管理。在我们的系统中也要存在这份数据字典,并且指明此属性对应的数据字典是哪张表,哪一列为key,哪一列为value。这当然是可以实现的,稍微麻烦一些。
    再假如数据类型A中某属性应用了某数据字典,key-value1,数据类型B中某属性应用了key-value2,它们的数据字典还可能相同的地方,比如value值都是相同的,为了节约存储空间,我们把这两个数据字典整合进一张表中key1-key2-value,处理方法如上,实现可以,但麻烦。数据字典问题不止是存在于定义数据和动态管理这两个步骤中,下面的数据接入、数据查询遇到的问题将更加棘手。
    处理办法:
    a、唯一化key。
    b、你的建议。
     
    2、动态建表问题
    上面说了,在删除数据类型时,要在Hibernate上下文中处理好它,但是没有找到好的解决办法。欢迎不吝赐教。
    处理办法:
    a、悬而未决,你的建议。
     
    上面讲了一、定义数据,二、动态管理,还有:三、数据接入,四、数据查询 两个步骤,将在以后的文章中详细说明。





  • 相关阅读:
    tensorflow2.0 GPU和CPU 时间对比
    第一次使用FileZilla Server
    PremiumSoft Navicat 15 for Oracle中文破解版安装教程
    Unmapped Spring configuration files found. Please configure Spring facet or use 'Create Default Context' to add one including all unmapped files.
    ng : 无法加载文件 D: odejs ode_global g.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。
    angular
    Github上优秀的go项目
    win10---file explore 中remove quick access folder
    react--useEffect使用
    linux---cat 和 grep 的妙用
  • 原文地址:https://www.cnblogs.com/wgp13x/p/4019600.html
Copyright © 2011-2022 走看看