Designing Data-Intensive Applications

Designing Data-Intensive Applications, Chapter 2. Data Models and Query Languages – 讀書筆記

Data model可用來隱藏不同階層的complexity,簡化開發上的複雜度。本章節主要著重在比較relational、document和graph的data models,並簡單討論相關的query languages。

Relational Model Versus Document Model

The Object-Relational Mismatch

物件導向程式語言的物件data model,和SQL model本質上就不太合。例如以Linkedin上的profile為例,每個人都會有一些唯一的數值,例如年齡和目前工作等等。但同時也有很多資料是非唯一的,例如工作經驗和已獲得證照等。為了處理這種one-to-many的關聯性,我們可能有幾種作法:

  1. 將共通的使用者資料normalized後存放在users的表格,然後以users的primary key user_id作為foreign key連結其他關聯的資料。
  2. 近期的SQL標準開始支援XML或JSON這類多層式的data type。善用這類data type亦可處理一對多資料。
  3. 將所有資料全部轉成JSON或XML形式,然後在存入text的column中。不過這類作法就無法善用database的query特性。

對於個人profile這種大多為self-contained的文件,Document-oriented的資料庫像MongoDB、RethinkDB、CouchDB和Esspresso等都很適合使用。若使用JSON結構儲存的話,應用程式query資料相較於標準multi-table的設計,JSON形式的locality會好一些(不需要透過多層的join得到結果)。

Many-to-One and Many-to-Many Relationships

以上述Linkedin profile為例,其他資料例如居住地、產業等資訊,使用text作為欄位的值是好的作法嗎?實務上free-text的作法會導致字元的不一致,而且若每個使用該資訊的地方都是直接採用text方式儲存,會導致資料庫到處有human-meaningful資料散落各處,若要更改也困難。反之若將這類資訊改用ID表示,則實際修改human-meaningful的資料則單純的多(畢竟只有一筆),而散落在各處的ID由於並沒有實質上的意義,所以不會遇到修改的問題。

這類many-to-one的關聯性,在document model的資料庫上就不太適用。就算初期能用,但隨著應用程式的發展,勢必會遇到一些困境。例如:

  1. 若原profile的organization或school資訊是單純以字串儲存,後期若想改為以entity方式呈現(能存放更多相關資料,例如organization的log等)
  2. 若每個profile想增加互相推薦機制,且每個推薦除了要能帶出推薦的內容外,還要帶入推薦人的照片等。

以上的修改,都會讓model變成many-to-many(每個人都可以互相推薦、公司有多人且每個人有多個公司等等)。這種類型的修改會讓document的model相當難修改。在電腦發展過去的歷史中,我們有兩種可能的解法:

THE NETWORK MODEL

Network model是由CODASYL(Conference on Data Systems Languages的committee標準化的,主要是把樹狀結構(每筆資料只能有一個parent)的特性擴展為多個多個parents,而這些連結則須application code另外以類似pointer的形式儲存。基於這樣的結構,要存取每筆資料,都需要從root開始沿著往下找。這路徑又稱為access path。

此類型model若因access path變化而要改變query和update的code,會需要改變所有使用到access path的code,因此維護起來較為複雜。

THE RELATIONAL MODEL

不同於network model,relation database選擇把資料以”開放”的table形式儲存,而在存取的時候才藉由query optimizer決定query的順序及使用的index等”access path”資訊。和Network Model相比,兩者最大的差異在於relational model的access path是由query optimizer自動決定,而非application developer,大幅減低開發複雜度。

Relational Model將access path的複雜度藏在一個general-purpose optimizer,而不像Network Model每個access path都須”手刻”。以長遠來說,雖然query optimizer建造起來不容易,但若成功運作確實有它的效益在。

COMPARISON TO DOCUMENT DATABASES

目前Document和Relational databases在處理one-to-many的資料雖然不同,但是在many-to-one或many-to-many的情境下,主要都還是用unique identifier作為資料連結(在document database稱為document reference,relational database稱為foreign key)。

Relational Versus Document Databases Today(Data Model Only)

WHICH DATA MODEL LEADS TO SIMPLER APPLICATION CODE?

如果你的application使用的資料就是tree結構的,那document model使用上就相對把資料散落在各table的relational model有優勢。

但若有many-to-many relationships的情境,document model就顯的較不適合。即使denormalize資料,application仍須維護資料的consistency。若在勢必需要join的情境,也只能仰賴application透過多次的queries取得資料後,再由application自行join。這種作法除了複雜外,效率也較差。

整體來說並沒有哪種model一定會有比較簡潔的application code。但普遍來說,若是高度相關連的資料,document model勢必會較難處理。

SCHEMA FLEXIBILITY IN THE DOCUMENT MODEL

JSON和XML的資料結構雖然允許動態的schema,但實務上其實並沒有真正動態的schema,只有schema-on-write(relational database的作法,schema檢查發生在寫入資料時)或schema-on-read(schema的檢核發生在資料被application讀取的時候)。兩者的差異很像是程式語言做runtime或compile-time檢查的討論。

schema-on-read在以下情境會特別有優勢:

  1. 有多種不同類型的objects,且分散儲存在各自的table並無好處。
  2. 資料結構是由外部不可空的系統決定。

在上述情境下,有固定schema產生的缺點可能比優點還多。但除此之外,多數時候schema-on-write仍有相當優勢。

DATA LOCALITY FOR QUERIES

若application存取資料都是一次要拿取整個document的話,document model在storage locality的特性就比relational model好。不過若讀取其實只需要一大份document裡面的少量欄位,讀取大型document就變得浪費資源。在更新document的部份,也會因更新少量欄位的資料而須重寫整筆document。基於上述原因,一般來說會建議document盡量維持小一些。受限於這些考量,document database在實務上的使用性就相對低一些。

CONVERGENCE OF DOCUMENT AND RELATIONAL DATABASES

近代Relational Database都已開始支援XML和JSON格式的欄位,而Document database也都逐漸開始支援類似join的功能(MongoDB可支援client-side join,但會效率會慢一些)。顯然Document和Relational databases是越來越相似,提供developer更多混合的選擇。

Query Languages for Data

Relational model的興起也一起帶起了新的資料query方式 – SQL。SQL是一個declarative query language,使用者只須描述想要資料的形式、pattern、條件等等,無須管實務上是如何運作的,就能取得資料。相較於須自行指定須如何一步一步取得資料的imperative language(CODASYL),SQL的抽象化對於developer來說顯的更易用。

Graph-Like Data Models

雖然Relational database仍能處理many-to-many relationships,但若發現資料的形式有相當複雜的many-to-many關聯,那把資料model成graph就相對更合理。

Graph包含兩種物件:vertices和edges。一般Graph可以適合用來描述社群、網際網路、道路等資料。資照需求的不同,一個Graph也可以將不同類型的資料都放在一起,例如Facebook就利用Graph將people, locations, events, checkins和comments組成一個大的Graph。

本章節主要討論property graph model(例如Neo4j, Titan和InfiniteGraph)和triple-store model(例如Datomic, AllegroGraph等)。

Property Graphs

Property graph model每個vertex都包含有:

  • 一個unique identifier
  • 一組outgoing edges
  • 一組incoming edges
  • 一組properties(key-value pairs)

每個edge都包含有:

  • 一個unique identifier
  • edge開始的vertex(the tail vertex)
  • edge結束的vertex(the head vertex)
  • 一個label描述兩個vertices的關係
  • 一組properties(key-value pairs)

事實上可以把property graph model想像成是用relational database分別用vertices和edges兩個tables存放相關資訊。

Triple-Stores

Triple-store model的概念大致與property graph model一致,差別只在於使用不同的文字來描述類似的概念。

在triple-store中,所有的資訊都是由三個部份組成的statement: (subject, predicate, object)。triple-store model同時用這樣的statement來描述properties和關聯的vertices。如果是properties的話,predicate和object的部份就為properties的資訊,反之若為vertices則存放該vertex的資訊。

我跳過了哪些內容?

第二章有很大一段在說明Graph相關models的query languages,像是Datalog、Cypher和SPARQL。不過由於內容都止於簡單的語法說明,過於粗淺,因此個人覺得對於實務上的設計幫助有限。但這不代表這類語言或model不重要,只是如果會需要用到這類model或languages的話,還是要實際拿幾個來動手玩玩會比較有感。

參考書籍

Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems,第二章

Add a Comment

Your email address will not be published. Required fields are marked *