Elasticsearch 父子關係

_BKing發表於2020-12-01

 Elasticsearch的父子關係在一定場景下非常有利於我們進行關聯查詢,合理使用能加快我們的索引速度。

父子關係圖

對於Elasticsearch的 Parent and Child:

  1. 家庭關係:

 

 

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可能是管理關係的一種不錯選擇,但代價是很高的。必須意識到這種權衡,例如父子文件的物理儲存約束和增加的複雜性。另一個預防措施是避免多層父子關係,因為這將消耗更多的記憶體和計算量。這些都是我們在使用父子關係的時候必須要考慮到的相關內容,避免造成不必要的損失。二哈覺得大家還是要根據實際場景來選擇合適自己的,綜合考慮自己的需求,沒有什麼是一套全通的呀!ღゝ◡╹)ノ♡

二哈最近開通了公眾號呀,在這裡你可以收穫最新的資訊呀,千萬別錯過啦!

歡迎兄弟們關注關注。

 

 

相關文章