數(shù)據(jù)模型應(yīng)該是軟件開發(fā)中最重要的部分,它不僅對軟件編碼方式,而且對如何思考待解決的問題都有深遠(yuǎn)的影響.
數(shù)據(jù)模型
關(guān)系模型
在關(guān)系模型中,數(shù)據(jù)被組織成關(guān)系,在SQL中被稱為表.每個(gè)關(guān)系都是元組的無需集合.
優(yōu)點(diǎn):
- 存在模式的規(guī)范.關(guān)系模型中支持一系列范式,更好的組織數(shù)據(jù).
- 關(guān)系模型可以支持多對一,多對多的關(guān)系表示,只需要進(jìn)行join操作就行.
- 關(guān)系模型使用的查詢語言是聲明式的,開發(fā)者無需關(guān)系具體的執(zhí)行步驟.
缺點(diǎn):
- 關(guān)系和對象不是一一對應(yīng)的.在面向?qū)ο缶幊讨?應(yīng)用代碼中的對象需要與關(guān)系模型中的表,行,列進(jìn)行轉(zhuǎn)換,這里需要一個(gè)叫做ORM的中間層.
- 不支持?jǐn)?shù)據(jù)的嵌套,沒辦法滿足局部最優(yōu)性的優(yōu)化.
文檔數(shù)據(jù)庫模型
文檔數(shù)據(jù)庫是一種層次模型:在父記錄中保存了嵌套記錄(一對多的關(guān)系),而不是單獨(dú)保存在表中.
優(yōu)點(diǎn):
- 文檔數(shù)據(jù)庫對保存的數(shù)據(jù)沒有模式限制,但是包含隱式的模式.
- 文檔數(shù)據(jù)庫保存的數(shù)據(jù)可以直接映射為應(yīng)用代碼中使用的數(shù)據(jù)結(jié)構(gòu).
- 在訪問整個(gè)文檔中大部分?jǐn)?shù)據(jù)時(shí),具有局部性性能優(yōu)勢.
- 數(shù)據(jù)支持嵌套,可以通過引用指向其他數(shù)據(jù).
- 針對數(shù)據(jù)格式改變時(shí),只需要使用新格式生成新文檔,應(yīng)用程序處理讀取就文檔的情況就可以了.
缺點(diǎn):
- 不支持join操作,所以幾乎無法表示多對多的關(guān)系.
- 修改時(shí)會(huì)整個(gè)重寫文檔.如果文檔太大則有些浪費(fèi).
圖狀數(shù)據(jù)模型
如果大多是數(shù)據(jù)直接沒有什么關(guān)系,或者最多有一對多的關(guān)系,那么文檔模型是合適的.
如果數(shù)據(jù)之間大部分都存在關(guān)系,可以是一對多,多對多的關(guān)系,數(shù)據(jù)見關(guān)系比較簡單的時(shí)候可以使用關(guān)系模型.
如果數(shù)據(jù)間存在很復(fù)雜的關(guān)聯(lián)關(guān)系,那么使用圖數(shù)據(jù)模型就是很自然的事情.例如:社交網(wǎng)絡(luò),Web圖,地鐵圖等.
圖數(shù)據(jù)模型中包含兩個(gè)元素:頂點(diǎn),邊.所以有很多種圖數(shù)據(jù)模型存在.
圖數(shù)據(jù)模型優(yōu)點(diǎn):
- 任何頂點(diǎn)可以連接到其他任何頂點(diǎn).沒有模式限制.
- 給定一個(gè)頂點(diǎn)可以快速獲取它的出邊和入邊.
- 通過對不同類型的關(guān)系使用不同的標(biāo)簽,可以在單個(gè)圖中存儲多種不同類型的信息.
我們先看看屬性圖模型.
屬性圖模型
屬性圖模型中,每個(gè)頂點(diǎn)包括:
- 唯一標(biāo)志符.
- 出邊集合.
- 入邊集合.
- 屬性集合(KV對).
每個(gè)邊包括:
- 唯一標(biāo)志符.
- 邊開始的頂點(diǎn)(尾部頂點(diǎn)).
- 邊結(jié)束的頂點(diǎn)(頭部頂點(diǎn)).
- 描述兩個(gè)頂點(diǎn)間關(guān)系的標(biāo)簽.
- 屬性的集合(KV對).
三元存儲
三元存儲包含:主體,謂語,客體三部分.
主體是圖中的頂點(diǎn),客體則是下面兩種的一種:
- 原始數(shù)據(jù)類型中的值.這種情況下謂語和客體相當(dāng)于主體屬性中的鍵值對.例如:(lucy, age, 33)
- 圖中另一個(gè)頂點(diǎn).此時(shí),謂語為圖中的邊,主體為尾部頂點(diǎn),客體為頭部定點(diǎn).例如:(lucy, marriedTo, alain).
查詢語言
命令式
針對文檔型數(shù)據(jù)庫,由于數(shù)據(jù)的組織方式是樹狀結(jié)構(gòu),所以開發(fā)出來了命令式查詢語言CODASYL
記錄之間的鏈接不是外鍵的方式,而是類似于編程語言中的指針.訪問記錄的唯一方式是從根出發(fā),沿著相關(guān)的鏈接依次訪問. 即應(yīng)用程序需要管理完整的訪問路徑.
需要告訴計(jì)算機(jī)以特定的順序執(zhí)行某些操作.
聲明式
聲明式語言則只需要指定所需的數(shù)據(jù)模式,結(jié)果需要滿足什么條件,以及如何轉(zhuǎn)換數(shù)據(jù)就行了.不需要執(zhí)行查詢操作的每一個(gè)步驟. SQL就是典型的聲明式查詢語言.
使用聲明式查詢語言,可以將數(shù)據(jù)庫引擎的實(shí)現(xiàn)細(xì)節(jié)隱藏起來,使在查詢語句不改變的情況下,優(yōu)化數(shù)據(jù)庫成為可能.
聲明式語言支持并行執(zhí)行.命令式則需要處理更多的細(xì)節(jié).
mapReduce查詢
MapReduce是一種編程模型,用于在許多機(jī)器上處理海量的數(shù)據(jù).
MapReduce既不是命令式,也不是聲明式:查詢邏輯需要使用代碼片段來表示,依賴于用戶編寫的map reduce兩個(gè)函數(shù).這兩個(gè)函數(shù)需要指定處理的方式.
例如MongoDB中MapReduce的功能:
db.observations.mapReduce(
function map() {
var year = this.observationTimeStamp.getFullYear();
var month = this.observationTimeStamp.getMonth() + 1;
emit(year + "-" + month, this.numAnimals); // 生成KV對 例如:(2020-01,100)
},
function reduce(key, values) {
return Array.sum(values); // 根據(jù)鍵將所有的值求和.
},
{
query:{family: "Sharks"},
out: "monthlySharkReport"
}
);
注意:map,reduce兩個(gè)函數(shù)必須為純函數(shù),即不能帶有副作用.
圖狀數(shù)據(jù)模型聲明式查詢語言
屬性圖: Cypher
Cypher是屬性圖的聲明式查詢語言的一種.我們先來看看如何創(chuàng)建數(shù)據(jù).
CREATE
(NAmerica:Location {name:'North America', type:'contient'}),
(USA:Location {name:'United States', type:'country'}),
(Idaho:Location {name:'Idaho', type:'state'}),
(Lucy:Persion {name:'Lucy', age:33}),
(Idaho)-[:WITHIN]->(USA)-[:WITHIN]->(NAmerica),
(Lucy)-[:BORN_IN]->(Idaho)
使用(NAmerica:Location {name:'North America', type:'contient'})的語句定義圖中的頂點(diǎn).使用(Lucy)-[:BORN_IN]->(Idaho)的語句定義一個(gè)標(biāo)簽為BORN_IN的邊,其中(Lucy)是尾部頂點(diǎn),(Idaho)是頭部定點(diǎn).
使用Cypher進(jìn)行查詢:
示例使用MATCH語句查詢了從USA移民到歐洲的所有人員.
MATCH
(person)-[:BORN_IN]->()-[:WITHIN*0]->(us:Location {name:'United States'}),
(person)-[:LIVES_IN]->()-[:WITHIN*0]->(eu:Location {name:'Europe'})
RETURN person.name
解釋:
找到滿足以下兩個(gè)條件的任何頂點(diǎn).
- person有一個(gè)到其他頂點(diǎn)的出邊BORN_IN.從該頂點(diǎn)開始沿著這條邊,可以沿著一系列出邊WITHIN,直到最終到達(dá)類型為Location的頂點(diǎn),neme屬性為'United States'.
- 同一個(gè)person頂點(diǎn)也有一個(gè)出邊LIVES_IN.從該頂點(diǎn)開始沿著這條邊,可以雁陣一系列出邊WITHIN,直到最終到達(dá)類型為Location的頂點(diǎn),neme屬性為'Europe'.
對于這樣的頂點(diǎn),返回它的name屬性.
三元存儲:SPARQL
SPARQL 是一種采用RDF數(shù)據(jù)模型的三元存儲查詢語言.
其中RDF是資源描述框架,它榮不同的網(wǎng)站以一致的格式發(fā)布數(shù)據(jù),這樣來自不同網(wǎng)站的數(shù)據(jù)自動(dòng)合并成一個(gè)數(shù)據(jù)網(wǎng)絡(luò),形成一種互聯(lián)網(wǎng)級別包含所有數(shù)據(jù)的數(shù)據(jù)庫.
RDF數(shù)據(jù)模型示例
RDF可以采用XML的方式編寫:
<rdf:RDF xmlns="urn:example:"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<Location rdf:nodeID="idaho">
<name>Idaho</name>
<type>state</type>
<within>
<Location rdf:nodeID="usa">
<name>United States</name>
<type>country</type>
<within>
<Location rdf:nodeID="namerica">
<name> North America</name>
<type>continent</type>
</Location>
</within>
</Location>
<within>
</Location>
<Person rdf:nodeID="lucy">
<name>Lucy</name>
<bornIn rdf:nodeID="idaho"/>
</Person>
</ref:RDF>
還有更簡單的Turtle/N3這種格式:
@prefix : <urn:exmaple:>.
_:lucy a :Person; :name "Lucy"; :bornIn _:idaho.
_:idaho a :Location; :name "Idaho"; :type "state"; :within _:usa.
_:usa a :Location; :name "United States"; :type "country"; :within _:namerica.
_:namerica a :Location; :name "North America"; :type "continent".
SPARQL查詢語言.
同樣我們使用SPARQL查詢從USA移民到歐洲的人員.
PREFIX : <urn:example:>
SELECT ?personName WHERE {
?person :name ?personName.
?person :bornIn / :within* / :name "United States".
?person :livesIn / :within* / :name "Europe".
}