各式結構化數據 動態 接入-存儲-查詢 的處理辦法 (第一部分)


各式結構化數據的動態接入存儲查詢,這一需求相信有很多人都遇到過,隨着實現技術路線選擇的不同,遇到的問題出入大了,其解決辦法也是大相徑庭。數據存儲在哪兒,是關系型數據庫,還是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等(請原諒我的靈感來自於《絕命毒師》),它們肯定是要事先定義好的,我們數據庫中能夠接入的數據必須由這些組成,如  String Integer Long BigDecimal Boolean Calendar Date Time Blob 等, 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 ^[\s\S]{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 ^[\s\S]{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、懸而未決,你的建議。
 
上面講了 一、定義數據,二、動態管理, 還有: 三、數據接入, 四、數據查詢 兩個步驟,將在以后的文章中詳細說明。






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM