【问题标题】:Elasticsearch deeper level Parent-child relationship (grandchild)Elasticsearch 更深层次的父子关系(孙子)
【发布时间】:2013-04-03 09:21:23
【问题描述】:

我需要索引 3 个级别(或更多)的子父级。 例如,级别可能是作者、一本书和该书中的人物。

但是,当索引超过两个级别时,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": {}
            }
          }
        }
      ]
    }
  }
}'

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

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    您是对的,只有当给定父级的所有子级都与父级位于同一分片中时,父/子关系才有效。 Elasticsearch 通过使用 parent 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 '{...}'
    

    【讨论】:

    • 在 URL 上使用路由参数。请参阅此处的路由部分 - elasticsearch.org/guide/reference/api/index_
    • 谢谢。我也可以以某种方式在后期数据中指定这个吗?专门针对bulk_index,我想在哪里为每个文档指定路由?
    • 是的,您可以将 _routing 字段添加到 _bulk 项。见elasticsearch.org/guide/reference/api/bulk的路由部分
    • 我想知道你是否可以澄清这个问题是如何发生的 - 如果孩子被路由到与父母相同的分片,而孙子被路由到与孩子相同的分片,不应该是“亲戚”都在同一个分片上?
    • 我最近遇到了同样的问题。想确认超过 2 个级别的父/子关系是否是映射数据的可接受方式。它以最少的冗余完成了我的工作,但是否有任何我应该注意的重大权衡(除了由于相同分片引起的搜索开销)。
    【解决方案2】:

    对于祖父文档,您需要获取 _id 作为 _routing。 对于父亲文档,只需使用 _parent (grandpa._id) 作为 _routing。 对于子文档,只需使用 grandpa._id 作为 _routing。

    【讨论】:

      猜你喜欢
      • 2017-10-06
      • 2016-02-13
      • 1970-01-01
      • 2016-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-17
      • 2016-10-05
      相关资源
      最近更新 更多