通过查询更新插入

mlo*_*iro 5 elasticsearch

我正在尝试创建或更新一个我没有 ID 的文档。所以我目前正在做的是搜索/获取现有的(或不存在的)文档,更新它并将其推回,它正在工作。

但我想一次性完成这一切。

我读过有关通过查询更新的信息,它看起来不适用于这种情况。我也尝试过使用脚本,但只找到了更新参考(所以我需要ID)。

不确定这在 ES 上是否可行。

非常感谢任何帮助/提示。

谢谢


更多信息:

就我而言,我与 ID 没有直接关系,这就是我打算通过查询更新的原因

我的文档很简单,如下所示:

{
  "text": "some text",
  "type": "a real type",
  "occurences": 2
}
Run Code Online (Sandbox Code Playgroud)

所以我必须通过文本键和键入键来匹配它。如果不存在则添加一个新文档(出现次数为1),如果找到则更新出现次数更新为 3。

根据 的文档update_by_query,应该可以执行以下操作:

POST /test/type/_update_by_query?conflicts=proceed
{
  "query": {
    "bool": {
      "must": [
         {"match_phrase": {"text": "some text"}},
         {"match_phrase": {"type": "a real type"}}
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

但我不知道如何离开这里。

Dan*_*iny 4

当我使用动态生成的 id 而不存储它们时,我偶然发现了确切的问题。

我相信这是不可能在一个查询中完成的,但您可以使用_update_by_query并检查响应正文中的更新计数,如果它为 0 那么您可以安全地插入新实例。

所以在你的情况下它会是这样的:

    POST /test/type/_update_by_query
    {
      "script": {
        "inline": "ctx._source.occurences++"
      },
      "query": {
        "bool": {
          "must": [
             {"match_phrase": {"text": "some text"}},
             {"match_phrase": {"type": "a real type"}}
          ]
        }
      }
    }
Run Code Online (Sandbox Code Playgroud)

响应可能是:

  {
           "took": 2,
           "timed_out": false,
           "total": 0,
           "updated": 0,
           "deleted": 0,
           "batches": 0,
           "version_conflicts": 0,
           "noops": 0,
           "retries": {
              "bulk": 0,
              "search": 0
           },
           "throttled_millis": 0,
           "requests_per_second": -1,
           "throttled_until_millis": 0,
           "failures": []
 }
Run Code Online (Sandbox Code Playgroud)

检查:if(response.updated == 0) 像这样。True => 安全插入新对象。(同时检查是否有冲突)

POST /test/type/
{
  "text": "some text",
  "type": "a real type",
  "occurences": 1
}
Run Code Online (Sandbox Code Playgroud)

否则什么也不做,并且您的出现次数已更新。

使用此解决方案,您可能会遇到竞争条件,并且您将得到 version_conflicts。如果您遇到此问题,您可以做 3 件事。

  1. 使用队列和工作线程来运行一个又一个的请求。
  2. 使用简单的查询来获取 ids 并使用 upserts,您可以在其中指定冲突和许多其他事情的重试次数。也可以选择批量更新。
  3. 使用这些选项:

    waitForCompletion:true,冲突:“继续”,刷新:true

这将导致请求挂起,直到解决为止,因此响应时间会更长,并且它将等待完成并阻塞。每次索引后刷新也是非常糟糕的做法,因为它会重新索引您的数据。这将导致版本更新,并且您将不再有版本冲突。