0、題記
Elasticsearch多表關聯問題是討論最多的問題之一,如:博客和評論的關係,用戶和愛好的關係。html
多表關聯一般指:1對多,或者多對多關係在ES中的呈現。mysql
本文以星球問題爲出發點,引伸出ES多表關聯認知,分析了4種關聯關係的適用場景、優勢、缺點。sql
但願對你有所啓發,爲你的多表關聯方案選型、實戰提供幫助。數據庫
一、拋出問題
1.1 星球典型問題
1.2 社區典型問題
1.3 QQ羣典型問題
關係型數據庫中的多表之間的關聯查詢,ES中有什麼好的解決方案?
若是我把關聯關係的表遷移到ES中放到一個type下,文檔結構除了對象之間的嵌套還有什麼好的解決方案?json
二、基礎認知
2.1 關係型數據庫
關係數據庫是專門爲關係設計的,有以下特色:數組
能夠經過主鍵惟一地標識每一個實體(如Mysql中的行)。app
實體 規範化 。惟一實體的數據只存儲一次,而相關實體只存儲它的主鍵。只能在一個具體位置修改這個實體的數據。數據庫設計
實體能夠進行關聯查詢,能夠跨實體搜索。elasticsearch
支持ACID特性,即:單個實體的變化是 原子的 , 一致的 , 隔離的 , 和 持久的 。ide
大多數關係數據庫支持跨多個實體的 ACID 事務。
關係型數據庫的缺陷:
第一:全文檢索有限的支持能力。 這點,postgresql已部分支持,但相對有限。
第二:多表關聯查詢的耗時很長,甚至不可用。以前系統開發中使用過Mysql8個表作關聯查詢,一次查詢等待十分鐘+,基本不可用。
2.2 Elasticsearch
Elasticsearch ,和大多數 NoSQL 數據庫相似,是扁平化的。索引是獨立文檔的集合體。 文檔是否匹配搜索請求取決於它是否包含全部的所需信息和關聯程度。
Elasticsearch 中單個文檔的數據變動是知足ACID的, 而涉及多個文檔時則不支持事務。當一個事務部分失敗時,沒法回滾索引數據到前一個狀態。
扁平化有如下優點:
索引過程是快速和無鎖的。
搜索過程是快速和無鎖的。
由於每一個文檔相互都是獨立的,大規模數據能夠在多個節點上進行分佈。
2.3 Mysql VS Elasticsearch
mysql才擅長關係管理,而ES擅長的是檢索。
Medcl也曾強調:「若是可能,儘可能在設計時使用扁平的文檔模型。」 Elasticsearch的關聯存儲、檢索、聚合操做勢必會有很是大的性能開銷。
3 Elasticsearch關聯關係如何存儲
關聯關係仍然很是重要。某些時候,咱們須要縮小扁平化和現實世界關係模型的差別。
如下四種經常使用的方法,用來在 Elasticsearch 中進行關聯數據的管理:
3.1 應用端關聯
這是廣泛使用的技術,即在應用接口層面來處理關聯關係。
針對星球問題實踐,
存儲層面:獨立兩個索引存儲。
實際業務層面分兩次請求:
第一次查詢返回:Top5中文姓名和成績;
根據第一次查詢的結果,第二次查詢返回:Top5中文姓名和英文姓名;
將第一次查詢結果和第二次查詢結果組合後,返回給用戶。
即:實際業務層面是進行了兩次查詢,統一返回給用戶。用戶是無感知的。
適用場景:數據量少的業務場景。
優勢:數據量少時,用戶體驗好。
缺點:數據量大,兩次查詢耗時確定會比較長,影響用戶體驗。
引伸場景:關係型數據庫和ES 結合,各取所長。將關係型數據庫全量同步到 ES 存儲,不作冗餘存儲。
如前所述:ES 擅長的是檢索,而 MySQL 才擅長關係管理。因此能夠考慮兩者結合,使用 ES 多索引創建相同的別名,針對別名檢索到對應 ID 後再回 MySQL 查詢,業務層面經過關聯 ID join 出須要的數據。
3.2 寬表冗餘存儲
對應於官方文檔中的「Data denormalization」,官方直接翻譯爲:「非規範化你的數據」,總感受規範化是什麼鬼,很差理解。
通俗解釋就是:冗餘存儲,對每一個文檔保持必定數量的冗餘數據能夠在須要訪問時避免進行關聯。
這點經過logstash 同步關聯數據到ES時,一般會建議:先經過視圖對Mysql數據作好多表關聯,而後同步視圖數據到ES。此處的視圖就是寬表。
針對星球問題實踐:姓名、英文名、成績兩張表合爲一張表存儲。
適用場景:一對多或者多對多關聯。
優勢:速度快。由於每一個文檔都包含了所需的全部信息,當這些信息須要在查詢進行匹配時,並不須要進行昂貴的關聯操做。
缺點:索引更新或刪除數據,應用程序不得不處理寬表的冗餘數據;
因爲冗餘存儲,致使某些搜索和聚合操做可能沒法按照預期工做。
3.3 嵌套文檔(Nested)存儲
Nested類型是ES Mapping定義的集合類型之一,它是比object類型更NB的支持獨立檢索的類型。
舉例:有一個文檔描述了一個帖子和一個包含帖子上全部評論的內部對象評論。能夠藉助 Nested 實現。
實踐注意1:當使用嵌套文檔時,使用通用的查詢方式是沒法訪問到的,必須使用合適的查詢方式(nested query、nested filter、nested facet等),不少場景下,使用嵌套文檔的複雜度在於索引階段對關聯關係的組織拼裝。
推薦實踐:乾貨 | Elasticsearch Nested類型深刻詳解
實踐注意2:
index.mapping.nested_fields.limit 缺省值是50。
即:一個索引中最大容許擁有50個nested類型的數據。
index.mapping.nested_objects.limit 缺省值是10000。
即:1個文檔中全部nested類型json對象數據的總量是10000。
適用場景:1 對少許,子文檔偶爾更新、查詢頻繁的場景。
若是須要索引對象數組並保持數組中每一個對象的獨立性,則應使用嵌套 Nested 數據類型而不是對象 Oject 數據類型。
優勢:nested文檔能夠將父子關係的兩部分數據(舉例:博客+評論)關聯起來,能夠基於nested類型作任何的查詢。
缺點:查詢相對較慢,更新子文檔須要更新整篇文檔。
3.4 父子文檔存儲
注意:6.X以前的版本的父子文檔存儲在相同索引的不一樣type中。而6.X之上的版本,單索引下已不存在多type的概念。父子文檔Join的都是基於相同索引相同type實現的。
Join類型是ES Mapping定義的類型之一,用於在同一索引的文檔中建立父/子關係。 關係部分定義文檔中的一組可能關係,每一個關係是父名稱和子名稱。
實踐參考:Elasticsearch 6.X 新類型Join深刻詳解
適用場景:子文檔數據量要明顯多於父文檔的數據量,存在1 對多量的關係;子文檔更新頻繁的場景。
舉例:1 個產品和供應商之間是1對N的關聯關係。
當使用父子文檔時,使用has_child 或者has_parent作父子關聯查詢。
優勢:父子文檔可獨立更新。
缺點:維護Join關係須要佔據部份內存,查詢較Nested更耗資源。
4 小結
在Elasticsearch開發實戰中對於多表關聯的設計要突破關係型數據庫設計的思惟定式。
不建議在es作join操做,parent-child能實現部分功能,可是它的開銷比較大,若是可能,儘可能在設計時使用扁平的文檔模型。
儘可能將業務轉化爲沒有關聯關係的文檔形式,在文檔建模處多下功夫,以提高檢索效率。
Nested&Join父子文選型必須考慮性能問題。 nested 類型檢索使得檢索效率慢幾倍,父子Join 類型檢索會使得檢索效率慢幾百倍。
以上內容,實際官方文檔都有明確的描述。我把內容加上本身的理解,做了精煉和解讀。
再次強調:第一手資料的重要性。但本着「再顯而易見的道理,也有N多人不知道」的原則,必定要讀英文官方文檔,加深認知理解。
Elasticsearch多表關聯你是如何作的呢?歡迎留言寫下您的思考。
參考:
[1] https://www.elastic.co/guide/en/elasticsearch/guide/current/relations.html[2] rockybean 教程