Elasticsearch更深层次的亲子关系(孙子)

时间:2013-04-03 09:21:23

标签: elasticsearch

我需要索引3个级别(或更多)的child-parent。 例如,级别可能是作者,书籍和该书中的字符。

但是,当索引超过两个级别时,has_child和has_parent查询和过滤器出现问题。 如果我有5个分片,那么在运行" has_parent"时,我得到大约五分之一的结果。查询最低级别(字符)或第二级(书籍)上的has_child查询。

我的猜测是,一本书被其父级ID索引到一个分片,因此它将与他的父级(作者)一起驻留,但是一个角色根据书籍ID的哈希被索引到一个分片,这不一定符合本书编入索引的实际分片。

所以,这意味着同一作者的所有书籍都不一定存在于同一个碎片中(真正摧毁了整个孩子 - 父母的优势)。

我做错了吗?我怎么能解决这个问题,因为我真的需要复杂的查询,例如"作者用女性角色写作的书籍#34;例如。

我疯狂地表达了这个问题,在: 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": {}
            }
          }
        }
      ]
    }
  }
}'

只返回五分之一(大约)的字符。

2 个答案:

答案 0 :(得分: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 '{...}'

答案 1 :(得分:0)

对于爷爷文档,你需要将_id作为_routing。 对于父文档,只需使用_parent(grandpa._id)作为_routing。 对于子文档,只需使用grandpa._id作为_routing。