如何将文档移动到不同的ID

时间:2014-08-25 10:15:29

标签: elasticsearch

我想将文档移动到新的id,以便在文档API中的另一个url处可用。有两种方法可以做到这一点:

1

  • 删除旧ID
  • 的文档
  • 使用新ID
  • 创建文档

2

  • 使用新ID
  • 创建文档
  • 删除旧ID
  • 的文档

方法1可能导致文档未在搜索中返回。方法2可能导致文档在搜索中被多次返回。

有什么方法可以解决这个问题吗?

3 个答案:

答案 0 :(得分:3)

创建(索引)或删除文档时,这仅在索引刷新后的搜索中反映出来。所以在实践中你的方法都有相同的结果: 直到索引刷新

  • 旧文档将在搜索中返回,但使用文档API(GET / indexname / type / id)无法使用
  • 新文档将使用文档API提供,但不会显示在搜索中。

当您快速连续执行索引和删除操作时,甚至可能在单个批量请求中,操作的顺序并不重要。默认情况下,刷新间隔为一秒,因此差异将保持最长时间。您可以通过在索引上发出刷新命令来立即强制刷新:

curl -XPOST http://127.0.0.1:9200/testidx/_refresh

以下最后一节提供了事件顺序的说明。

通过添加网址参数refresh=true,也可以在批量请求后强制刷新。因此,如果您确实需要更改文档的ID,请按以下步骤操作:

  1. (可选)禁用自动索引刷新
  2. 发出批量请求
    1. 创建新文档
    2. 删除旧文档
    3. REFRESH指数
  3. 重新启用自动索引刷新(如果在1中禁用)。
  4. 示例:

    将文件从ID 77移至ID 99:

    curl -XPOST localhost:9200/testidx/foo/_bulk?refresh=true --data-binary @bulk.json
    

    文件bulk.json包含类似

    的内容
    {"index": {"_id": "123"}}
    { ... old document source ... }
    {"delete": {"_id": "99"}}
    

    但是,您真的需要更改ID,还是可以围绕该要求进行设计?也许不以这种方式使用文档API,而是在每个文档中包括例如"path"字段,并基于该字段制作URL方案(基于搜索API)。然后,您可以通过使用新的"path"字段更新文档来移动(更改URL路径)文档。

    搜索索引刷新插图

    首先添加doc 77并将其显示在搜索中:

    + curl -XPUT 'http://127.0.0.1:9200/testidx/foo/77' -d '{"boo": "baa"}'
    {
      "_index" : "testidx",
      "_type" : "foo",
      "_id" : "77",
      "_version" : 1,
      "created" : true
    }
    
    + curl -XPOST http://127.0.0.1:9200/testidx/_refresh
    {"_shards":{"total":10,"successful":5,"failed":0}}
    
    + curl -XGET 'http://127.0.0.1:9200/testidx/foo/_search'
    {
      "took" : 1,
      "timed_out" : false,
      "_shards" : {
        "total" : 5,
        "successful" : 5,
        "failed" : 0
      },
      "hits" : {
        "total" : 1,
        "max_score" : 1.0,
        "hits" : [ {
          "_index" : "testidx",
          "_type" : "foo",
          "_id" : "77",
          "_score" : 1.0,
          "_source":{"boo": "baa"}
        } ]
      }
    }
    
    + curl -XPUT 'http://127.0.0.1:9200/testidx/_settings' -d '{"settings": { "index.refresh_interval": "-1"}}'
    {
      "acknowledged" : true
    }
    

    然后添加新的文档99:

    + curl -XPUT 'http://127.0.0.1:9200/testidx/foo/99' -d '{"boo": "baa"}'
    {
      "_index" : "testidx",
      "_type" : "foo",
      "_id" : "99",
      "_version" : 1,
      "created" : true
    }
    

    99尚未出现在搜索中:

    + curl -XGET 'http://127.0.0.1:9200/testidx/foo/_search'
    {
      "took" : 0,
      "timed_out" : false,
      "_shards" : {
        "total" : 5,
        "successful" : 5,
        "failed" : 0
      },
      "hits" : {
        "total" : 1,
        "max_score" : 1.0,
        "hits" : [ {
          "_index" : "testidx",
          "_type" : "foo",
          "_id" : "77",
          "_score" : 1.0,
          "_source":{"boo": "baa"}
        } ]
      }
    }
    

    ...但文档API中有:

    + curl -XGET 'http://127.0.0.1:9200/testidx/foo/99'
    {
      "_index" : "testidx",
      "_type" : "foo",
      "_id" : "99",
      "_version" : 1,
      "found" : true,
      "_source":{"boo": "baa"}
    }
    

    删除77后,搜索仍会显示77(但不是99):

    + curl -XDELETE 'http://127.0.0.1:9200/testidx/foo/77'
    {
      "found" : true,
      "_index" : "testidx",
      "_type" : "foo",
      "_id" : "77",
      "_version" : 2
    }
    
    + curl -XGET 'http://127.0.0.1:9200/testidx/foo/_search'
    {
      "took" : 0,
      "timed_out" : false,
      "_shards" : {
        "total" : 5,
        "successful" : 5,
        "failed" : 0
      },
      "hits" : {
        "total" : 1,
        "max_score" : 1.0,
        "hits" : [ {
          "_index" : "testidx",
          "_type" : "foo",
          "_id" : "77",
          "_score" : 1.0,
          "_source":{"boo": "baa"}
        } ]
      }
    

    但文档API不再具有77:

    + curl -XGET 'http://127.0.0.1:9200/testidx/foo/77'
    {
      "_index" : "testidx",
      "_type" : "foo",
      "_id" : "77",
      "found" : false
    }
    

    但刷新后,搜索结果反映了当前内容:

    + curl -XPOST http://127.0.0.1:9200/testidx/_refresh
    {"_shards":{"total":10,"successful":5,"failed":0}}
    
    + curl -XGET 'http://127.0.0.1:9200/testidx/foo/_search'
    {
      "took" : 1,
      "timed_out" : false,
      "_shards" : {
        "total" : 5,
        "successful" : 5,
        "failed" : 0
      },
      "hits" : {
        "total" : 1,
        "max_score" : 1.0,
        "hits" : [ {
          "_index" : "testidx",
          "_type" : "foo",
          "_id" : "99",
          "_score" : 1.0,
          "_source":{"boo": "baa"}
        } ]
      }
    }
    

答案 1 :(得分:2)

不幸的是,没有办法在ElasticSearch中使'批量'请求成为原子。您是否考虑过将可搜索的id字段与_id分开?然后,您可以通过更新“id”属性来简单地对该文档运行更新。

ES中有一个功能可能是一个解决方案,但我还没有尝试过。 ES允许您将_id字段映射到文档中的属性字段。这样做可以让您搜索属性,就像直接查询id一样。我不知道如果您尝试更新映射字段会发生什么。您可以在这里找到更多信息:

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-id-field.html

答案 2 :(得分:2)

更多涉及,但如果您要定期执行此操作,则可以使用索引别名。基本上,您将更改应用程序以使用索引别名作为抽象级别。然后,您将创建一个新索引,加载所有现有文档并进行要进行的ID更改。最后,您将更改索引别名以指向新索引 - 这将以原子方式发生,以便不会出现停机。

此处描述了类似的过程(它专注于更改映射,但也可以处理文档更改):

http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/

有关索引别名的更多信息:

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-aliases.html