【问题标题】:elastic search, is it possible to update nested objects without updating the entire document?弹性搜索,是否可以在不更新整个文档的情况下更新嵌套对象?
【发布时间】:2013-08-21 14:29:40
【问题描述】:

我正在索引一组文档(将它们想象为论坛帖子),其中包含一个嵌套对象,该对象是与该帖子相关的用户。我的问题是用户字段可能会更新,但由于帖子没有更改,它们不会重新索引并且用户嵌套对象变得过时。有没有办法在不重新索引整个文档的情况下更新嵌套对象?或者唯一的解决方案是每次用户更改时重新索引用户的所有相关帖子?

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    遗憾的是,elasticsearch 无法在不重新索引整个文档的情况下仅更新文档的一部分。所以,是的,您需要重新索引整个文档以更改嵌套部分。

    如果您手头没有完整的文档来重新发送,您可以使用update API 发送需要更改的部分,但请注意存在性能问题。

    【讨论】:

    • 这不是真的。 Elasticsearch 非常有能力更新部分文档,并且也可以根据条件更新。查看elasticsearch.org/guide/en/elasticsearch/reference/current/…中的upsert
    • 如果您阅读@vaidik 的问题,您会看到他在询问是否在不重新索引的情况下更新嵌套文档。除非 elasticsearch 最近发生了变化,否则您不能只重新索引文档的一部分。我还链接到更新 API。来自文档本身:“请注意,此操作仍然意味着文档的完整重新索引,它只是删除了一些网络往返并减少了获取和索引之间版本冲突的可能性。需要启用 _source 字段才能使此功能起作用。 "
    • 我将编辑我的答案的语言,因为我看到它可能会被误解。
    • @ramseykhalaf 我无法确认您关于使用更新 API 链接上的嵌套文档重新索引整个文档的说法。但是当你去亲子时确认:elastic.co/guide/en/elasticsearch/guide/current/…
    【解决方案2】:

    您可以使用更新 API。

    curl -XPOST localhost:9200/docs/posts/post/_update -d '{
        "script" : "ctx._source.nested_user = updated_nested_user",
        "params" : {
            "updated_nested_user" : {"field": "updated"}
        }
    }'
    

    查看SO answer了解完整详情。

    请注意,更新脚本支持条件逻辑,如 here 所示。因此,您可以在用户更改时标记论坛帖子,然后遍历帖子以仅更新用户更改的帖子。

    curl -XPOST 'localhost:9200/docs/posts/post/_update' -d '{
        "script" : "ctx._source.tags.contains(tag) ? "ctx._source.nested_user = updated_nested_John" : ctx.op = "none"",
        "params" : {
            "tag": "updated_John_tag",
            "updated_nested_John" : {"field": "updated"}
        }
    }'
    

    更新

    也许我的三元运算符示例不完整。问题中没有提到这一点,但假设用户在应用程序的单独部分更改他们的信息,最好将这些更改应用到一个脚本中的论坛帖子。尝试直接检查用户字段,而不是使用标签:

    curl -XPOST 'localhost:9200/docs/posts/post/_update' -d '{
        "script" : "ctx._source.nested_user.contains(user) ? "ctx._source.nested_user = updated_nested_John" : ctx.op = "none"",
        "params" : {
            "user": "John",
            "updated_nested_John" : {"field": "updated"}
        }
    }'
    

    不过,如前所述,这可能比重新索引完整帖子要慢。

    【讨论】:

    • 2 件事:+= 会将新用户附加到(现在正在增长的)嵌套用户数组中。另外,你为什么要浏览所有标记它们要更新的帖子,然后在第二遍更新它们?
    • @ScottRice Elasticsearch 如何知道要替换哪个嵌套对象?换句话说,在上面的例子中,Elasticsearch 如何知道你想要替换当前的 John 对象(而不是说,“Sally”对象)?每个嵌套文档都有一些键吗?
    • 嗨,我使用循环遍历嵌套文档 for (int i = 0; i
    • @PeteyPabPro 的评论似乎尚未得到解决。我也很想知道如何更新特定的嵌套文档。在上面的示例中,"user": "John"pertain 与哪个字段相关,ES 如何“知道”它被用作此处嵌套文档的 ID?
    【解决方案3】:

    @Scott Rice 关于如何在这种情况下使用部分更新的回答非常有用,而@ramseykhalaf 的回答更正确,因为如果不重新索引这是不可能的。如果我们进行部分更新,无论如何我们都会重新索引整个文档。

    但是取决于对“重新索引”是什么的理解。

    如果我们将重新索引定义为“将整个文档重新提交到 ES”——那么我们可以在这个意义上将解决方案称为部分更新而不需要重新索引。 如果我们将重新索引定义为“重新计算数据结构,以便有效地搜索索引中的更新文档”(这是我理解的更正确的定义),那么它总是会发生。

    请注意,部分更新后,整个旧文档副本将保留在索引中,标记为已删除(直到下一次从头开始重新索引或“优化”)。

    为避免这种情况,可以使用子父关系来代替嵌套对象。可以在不接触父文档的情况下添加/删除/更新子级(但这当然有其成本 - 在内存中维护子-父关系林等)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-25
      相关资源
      最近更新 更多