我正在使用嵌套对象索引一组文档(将它们想象为论坛帖子),该对象是与该帖子相关的用户。我的问题是用户字段可能会更新,但由于帖子没有更改,因此不会重新编制索引,用户嵌套对象也会过时。有没有办法更新嵌套对象而无需再次重新索引整个文档?或者唯一的解决方案是每次用户更改时重新索引用户的所有相关帖子?
答案 0 :(得分:22)
您可以使用Update 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"}
}
}'
如上所述,这可能比重新索引完整帖子的操作更慢。
答案 1 :(得分:9)
遗憾的是,如果不重新索引整个文档,elasticsearch不能仅更新文档的一部分。所以,是的,您需要重新索引整个文档以更改嵌套部分。
如果您没有整个文档可以重新发送,您可以使用update API发送需要更改的部分,但请注意是否存在性能问题。
答案 2 :(得分:5)
@Scott Rice对如何在此上下文中使用部分更新的回答非常有用,而@ramseykhalaf的回答更正确,因为如果没有重新索引,这是不可能的。如果我们进行部分更新,我们无论如何都要重新索引整个文档。
然而,取决于对什么"重新索引"的理解。是。
如果我们将重建索引定义为"将整个文档重新提交给ES" - 然后我们可以在没有重新索引的情况下调用部分更新解决方案。 如果我们将重建索引定义为"重新计算数据结构,以便有效地搜索索引中的更新文档" (这是我理解的更正确的定义),然后它总会发生。
请注意,部分更新后,整个旧文档副本将保留在索引中,标记为已删除(直到下一个完整的重新索引从头开始或"优化")。
为避免这种情况,可以使用子父关系代替嵌套对象。可以添加/删除/更新子项而无需触及父文档(但这当然有成本 - 在内存中维护子父关系林等。)