Elasticsearch 父子關係

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

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

歡迎兄弟們關注關注。

 

 

Tags: