【问题标题】:index Elasticsearch document with existing "id" field使用现有“id”字段索引 Elasticsearch 文档
【发布时间】:2017-12-14 13:42:42
【问题描述】:

我有想要索引到 Elasticsearch 中的文档,其中包含现有的唯一“id”字段。 我从 REST api 端点 ( eg.: http://some.url/api/products) 以无特定顺序获取一组文档,如果 Elasticsearch 中已经存在具有 _id 的文档,它应该更新并重新索引该文档。

如果 Elasticsearch 中不存在具有 _id 的文档,我想创建一个新文档,然后更新一个文档,如果它与 Elasticsearch 中的现有文档匹配。

这可以通过:

PUT products/product/un1qu3-1d-b718-105973677e95 { "id": "un1qu3-1d-b718-105973677e95", "state": "packaged" }

基本思想是使用提供的“id”字段来创建或更新文档。从文档字段中提取 _id 似乎已弃用 (link)。但是,使用 kibana 开发工具、邮递员或 cURL 请求,可以非常轻松地手动完成带有“id”字段的文档的索引/重新索引。 我想以编程方式对通过此 api 端点收到的文档进行(重新)索引。
是否可以使用logstash 或简单的cronjob 来实现这一点? Elasticsearch 是否为此提供任何功能?还是我需要编写一些自定义后端来实现这一点?

我想到了:

1) 使用我的文档的“id”字段将文档索引到 Elasticsearch 中或

2) 找到一个 Elasticsearch 查询,该查询首先搜索具有特定“id”字段的文档,然后更新该文档。

我无法找到任何一种方法的解决方案,也不知道好的方法会是什么样子。

谁能指出我如何实现这一目标的正确方向,提出更好的方法或提供解决方案?

非常感谢任何帮助!

更新

我在接受的答案的帮助下解决了这个问题。我使用了 Logstash,Http_poller 输入插件,这篇文章:https://www.elastic.co/blog/new-way-to-ingest-part-1 和这个 elastic.co 问题:https://discuss.elastic.co/t/upsert-with-logstash/59116

目前我的 logstash 输出如下所示:

output {
  elasticsearch {
    index => "products"
    document_type => "product"
    pipeline => "rename_id"
    document_id => "%{id}"
    doc_as_upsert => true
    action => "update"
  }

更新 2

为了完整起见,我添加了“rename_id”管道

{
  "rename_id": {
    "description": "_description",
    "processors": [
      {
        "set": {
          "field": "_id",
          "value": "{{id}}"
        }
      }
    ]
  }
}

它是这样工作的! 非常感谢!

【问题讨论】:

    标签: rest elasticsearch indexing cron logstash


    【解决方案1】:

    彼得,

    如果我理解正确,您希望将您的文档提取到弹性搜索中,并且将来会对这些文档进行一些更新?

    如果是这样的话, - 使用您的文档主键作为弹性文档的 ID。 - 您可以摄取具有更新值的整个文档,弹性将用新文档替换以前的文档。鉴于主键相同。具有相同 id 的旧文档将被删除。

    我们将这种方法用于搜索数据。

    【讨论】:

    • 我的设置的问题是,当我从 api 端点接收文档时,我不知道文档的“Id”字段。所以我不能事先指定它。它是我没有任何影响的第三方 api 端点。
    【解决方案2】:

    您可以使用摄取管道从正文和_create 端点中提取 id,以便仅在文档不存在时创建文档。小提示:如果您可以在客户端索引上指定 id 会更快,因为添加管道会增加一定的开销。

    PUT _ingest/pipeline/my_pipeline
    {
      "description": "_description",
      "processors": [
        {
          "set": {
            "field": "_id",
            "value": "{{id}}"
          }
        }
      ]
    }
    
    PUT twitter/tweet/1?op_type=create&pipeline=my_pipeline
    {
        "foo" : "bar",
        "id" : "123"
    }
    
    GET twitter/tweet/123
    
    # this call will fail
    PUT twitter/tweet/1?op_type=create&pipeline=my_pipeline
    {
        "foo" : "bar",
        "id" : "123"
    }
    

    【讨论】:

    • 直到现在我还没有听说过 Elasticsearchs _ingest 和 pipeline。非常感谢,我一定会试一试的。目前,一定的开销是可以的。我不完全理解的是你对specify the id on the client side 的意思。作为旁注,我对从中获取文档的第三方 api 端点没有任何影响,因此我事先不知道“id”字段。 @alr
    • @Peter plan 您的文件的唯一标识是什么?您如何知道是否要更新 elasticsearch 中的现有文档?如果您知道唯一标识符,则可以将其用作文档的 ID。
    【解决方案3】:

    您可以使用脚本来 UPSERT(更新或插入)您的文档

    PUT /products/product/un1qu3-1d-b718-105973677e95/_update
    {
       "script": {
          "inline": "ctx._source.state = \"packaged\"",
          "lang": "painless"
       },
       "upsert": {
          "id": "un1qu3-1d-b718-105973677e95",
          "state": "packaged"
       }
    }
    

    在上面的查询中找到 _id = "un1qu3-1d-b718-105973677e95" 的文档 如果它能够找到任何文档,那么它会将状态更新为“打包”,否则会创建一个带有字段“id”和“状态”的新文档(您可以插入任意数量的字段)。

    【讨论】:

      猜你喜欢
      • 2017-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多