【问题标题】:Using a script to conditionally update a document in Elasticsearch使用脚本有条件地更新 Elasticsearch 中的文档
【发布时间】:2015-10-08 16:53:52
【问题描述】:

我有一个用例,其中并发更新请求会影响我的 Elasticsearch 集群。为了确保在较新的事件已经到达集群后,陈旧的事件(与较新的请求无关的事件)不会更新文档,我想通过我的更新请求传递一个脚本来比较一个字段确定传入的请求是否相关。请求如下所示:

curl -XPOST 'localhost:9200/test/type1/1/_update' -d '
{
  "script": " IF ctx._source.user_update_time > my_new_time THEN do not update ELSE proceed with update",
  "params": {
    "my_new_time": "2014-09-01T17:36:17.517""
   },
  "doc": {
    "name": "new_name"
   },
  "doc_as_upsert": true
}'

我在“脚本”字段中编写的伪代码是否可以在 Elasticsearch 中使用?如果是这样,我会喜欢语法方面的帮助(groovy、python 或 javascript)。

任何替代方法建议也将不胜感激。

【问题讨论】:

标签: groovy elasticsearch


【解决方案1】:

Elasticsearch 内置了 optimistic concurrency control+ herehere)。

它的工作方式是Update API 允许你们两个使用version 参数来控制是否应该继续更新。

以上面的例子为例,第一个索引/更新操作将创建一个带有version: 1 的文档。然后以您有两个并发请求的情况为例。组件 A 和 B 都将发送更新的文档,它们最初都使用 version: 1 检索了文档,并将在其请求中指定该版本(请参阅下面的查询字符串中的 version=1)。 当且仅当提供的版本与当前版本相同时,Elasticsearch 才会更新文档

组件 A 和 B 都发送这个,但是 A 的请求是第一个发出的:

curl -XPOST 'localhost:9200/test/type1/1/_update?version=1' -d '{
  "doc": {
    "name": "new_name"
   },
  "doc_as_upsert": true
}'

此时文档的版本将为 2,而 B 的请求将以 HTTP 409 Conflict 结束,因为 B 假设文档仍为版本 1,尽管同时由于 A 的请求而版本增加了。

B 绝对可以使用新版本(即 2)检索文档并再次尝试更新,但这次在 URL 中使用?version=2。如果是第一个到达ES,更新成功。

【讨论】:

  • 感谢@Val 的回答。我绝对考虑过为此依赖乐观并发控制。进行更新的机制充当中间人,我希望它不必在更新之前检索文档。我宁愿它只是发送更新,并让 Elacticsearch 决定更新是否相关。这个中间人只会知道文档的 ID,以及要放入的数据。
  • @bkahler 这是不可能的。您必须先检索文档,然后再写入。所有乐观锁都遵循这一原则。
【解决方案2】:

我觉得脚本应该是这样的:

"script": "if(ctx._source.user_update_time > my_new_time) ctx._source.user_update_time=my_new_time;"

"script": "ctx._source.user_update_time > my_new_time ? ctx.op=\"none\" : ctx._source.user_update_time=my_new_time"

【讨论】:

    猜你喜欢
    • 2016-10-29
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多