2013-04-03 56 views
17

我需要索引3個級別(或更多)的孩子父母。 例如,關卡可能是作者,書籍和該書中的角色。Elasticsearch更深層次親子關係(孫子)

但是,當索引超過兩級時,has_child和has_parent查詢和過濾器存在問題。 如果我有5個分片,當在最低級別(字符)上運行「has_parent」查詢或在第二級別(書籍)上運行has_child查詢時,我會得到大約五分之一的結果。

我的猜測是,一本書通過它的父母id被索引到一個分片,因此將與他的父母(作者)一起居住,但是一個字符被索引到基於書籍ID的哈希的分片,不一定符合該書索引的實際碎片。

所以,這意味着同一作者的所有書籍的性格不一定在相同的碎片中(真的會削弱整個孩子 - 父母的優勢)。

我做錯了什麼?我如何解決這個問題,因爲我真的需要複雜的查詢,例如「哪些作者用女性角色書寫書籍」。

我狂表示該問題,在一個要點是: https://gist.github.com/eranid/5299628

底線是,如果我有一個映射:

"author" : {   
     "properties" : { 
    "name" : { 
     "type" : "string" 
    } 
     } 
    }, 
"book" : {   
     "_parent" : { 
    "type" : "author" 
     }, 
     "properties" : { 
    "title" : { 
     "type" : "string" 
    } 
     } 
    }, 

"character" : {  
     "_parent" : { 
    "type" : "book" 
     }, 
     "properties" : { 
    "name" : { 
     "type" : "string" 
    } 
     } 
    } 

和5個碎片索引,我無法使用「的查詢has_child」和 「has_parent」

查詢:

curl -XPOST 'http://localhost:9200/index1/character/_search?pretty=true' -d '{ 
    "query": { 
    "bool": { 
     "must": [ 
     { 
      "has_parent": { 
      "parent_type": "book", 
      "query": { 
       "match_all": {} 
      } 
      } 
     } 
     ] 
    } 
    } 
}' 

僅返回字符的第五個(大約)。

回答

25

你是對的,父母/子女關係只有在給定父母的所有孩子都與父母在同一個分片中時才能起作用。 Elasticsearch通過使用父id作爲路由值來實現這一點。它在一個層面上效果很好。然而,它在第二個連續的水平上破裂。當你有父母/子女/孫子女的關係時,家長根據他們的ID進行路由,子女將根據父母的ID(作品)進行路由,但是隨後孫子們會根據子女的ID進行路由,最終會出現錯誤的分片。爲了證明其放在例子,讓我們假設我們索引3個文件:

curl -XPUT localhost:9200/test-idx/author/Douglas-Adams -d '{...}' 
curl -XPUT localhost:9200/test-idx/book/Mostly-Harmless?parent=Douglas-Adams -d '{...}' 
curl -XPUT localhost:9200/test-idx/character/Arthur-Dent?parent=Mostly-Harmless -d '{...}' 

Elasticsearch利用價值Douglas-Adams來計算路由的文檔Douglas-Adams - 難怪這裏。對於文檔Mostly-Harmless,Elasticsearch認爲它具有父項Douglas-Adams,因此它再次使用Douglas-Adams來計算路由並且一切都很好 - 相同的路由值意味着相同的分片。但對於文檔Arthur-Dent Elasticsearch認爲它具有父項Mostly-Harmless,因此它使用值Mostly-Harmless作爲路由,結果文檔Arthur-Dent最終出現在錯誤的分片中。

對此的解決方案是等於祖父母的ID孫子顯式地指定路由值:

curl -XPUT localhost:9200/test-idx/author/Douglas-Adams -d '{...}' 
curl -XPUT localhost:9200/test-idx/book/Mostly-Harmless?parent=Douglas-Adams -d '{...}' 
curl -XPUT localhost:9200/test-idx/character/Arthur-Dent?parent=Mostly-Harmless&routing=Douglas-Adams -d '{...}' 
+0

很酷。我如何指定? – eran

+4

在URL上使用路由參數。請參閱此處的路由部分 - http://www.elasticsearch.org/guide/reference/api/index_/ – imotov

+0

謝謝。我可以在後期數據中以某種方式指定它嗎?專門爲bulk_index,我想爲每個文檔指定路由? – eran

0

對於爺爺的文檔,你需要得到_id作爲_routing。 對於父文檔,只需使用_parent(grandpa._id)作爲_routing。 對於兒童文檔,只需使用grandpa._id作爲_routing。

+0

困惑我。 –