Elasticsearch的父子關系在一定場景下非常有利於我們進行關聯查詢,合理使用能加快我們的索引速度。
父子關系圖
對於Elasticsearch的 Parent and Child:
-
家庭關系:

2.學校關系:

3.等等關系我們都可以用父子關系來表示,這非常有利於我們進行父子關系的查詢。
Parent and Child 有如下特點:
-
父子關系
-
每個父母有多個孩子
-
多個層次的親子關系
這里我們使用汽車關系來進行相關展示:


創建相關索引
PUT family_tree{"settings": {"index":{"number_of_shards":1,"number_of_replicas":0}},"mappings": {"properties": {"name":{"type": "text"},"price":{"type": "text"},"isSale":{"type": "boolean"},"relation_type":{"type": "join","eager_global_ordinals": true,"relations":{"parent":"child"}}}}}
注意:父子關系中使用 "eager_global_ordinals" 能加速join.
由於存儲的數據已被非規范化。因此聯接不能跨索引,子文檔和父文檔必須位於相同的索引和相同的分片中。父子關系需要在統一分片中:通過固定值來路由(routing)到同一個分片中。
分片規則:shard = hash(routing_value) % number_of_primary_shards
父節點插入數據
PUT family_tree/_doc/1?routing=Car{"name":"Car","price":"2000000","isSale":true,"relation_type":{"name":"parent"}}
子節點插入數據
PUT family_tree/_doc/2?routing=Car{"name":"Van","price":"10000","isSale":true,"relation_type":{"name":"child","parent":1}}PUT family_tree/_doc/3?routing=Car{"name":"Sedan","price":"10000","isSale":true,"relation_type":{"name":"child","parent":1}}PUT family_tree/_doc/4?routing=Car{"name":"SUV","price":"8000","isSale":true,"relation_type":{"name":"child","parent":1}}
注意:子文檔和父文檔必須位於同一分片上的限制。
查詢數據 — 搜索和過濾指定的父節點
獲取Car的所有子級:parent_id查詢可用於查找屬於特定父級的子級文檔。
GET /family_tree/_search?pretty=true{"query": {"parent_id":{"type":"child","id":"1"}}}
結果:以查找出屬於parent_id為 1 的所有子級文檔。
在這之前我們先為 Car 添加一個不再銷售的汽車類型:
PUT family_tree/_doc/5?routing=Car{"name":"Sports car","price":"30000000","isSale":false,"relation_type":{"name":"child","parent":1}}
1.用bool與must結合獲取所有未售 Car 的孩子:
GET /family_tree/_search{"query": {"bool": {"filter": {"term": {"isSale": "false"}},"must": [{"parent_id":{"type":"child","id":"1"}}]}}}
結果:從查詢到的結果中可以看到:只有"Sports car"符合我們查詢的條件。
2.我們也可以通過has_child查詢擁有子節點未銷售狀態的父節點信息:
GET /family_tree/_search?pretty{"query": {"has_child": {"type": "child","query": {"bool": {"must": [{"match": {"isSale": "false"}}]}}}}}
3.has_parent關鍵字可幫助我們獲取所有有父母且符合過濾條件的孩子信息。通過has_parent來查詢父節點狀態為在售的所有子節點信息:
GET /family_tree/_search?pretty{"query": {"has_parent": {"parent_type": "parent","query": {"match": {"isSale": "true"}}}}}
每個關系級別都會在查詢時增加內存和計算方面的開銷,不建議使用多個級別的關系模型。
本次收獲:
-
父子文檔必須索引到同一個分片中。
-
每個索引僅允許一個連接字段映射。
-
一個元素可以有多個子級,但只能有一個父級。
-
可以向已存在的聯接字段添加新關系。
-
也可以將子元素添加到現有元素中,但前提是該元素已經是父元素。
當索引時間性能比搜索時間性能更重要時,父子join可能是管理關系的一種不錯選擇,但代價是很高的。必須意識到這種權衡,例如父子文檔的物理存儲約束和增加的復雜性。另一個預防措施是避免多層父子關系,因為這將消耗更多的內存和計算量。這些都是我們在使用父子關系的時候必須要考慮到的相關內容,避免造成不必要的損失。二哈覺得大家還是要根據實際場景來選擇合適自己的,綜合考慮自己的需求,沒有什么是一套全通的呀!ღゝ◡╹)ノ♡
二哈最近開通了公眾號呀,在這里你可以收獲最新的資訊呀,千萬別錯過啦!
歡迎兄弟們關注關注。

