我想将文档移动到新的id
,以便在文档API中的另一个url
处可用。有两种方法可以做到这一点:
1
2
方法1可能导致文档未在搜索中返回。方法2可能导致文档在搜索中被多次返回。
有什么方法可以解决这个问题吗?
答案 0 :(得分:3)
创建(索引)或删除文档时,这仅在索引刷新后的搜索中反映出来。所以在实践中你的方法都有相同的结果: 直到索引刷新
当您快速连续执行索引和删除操作时,甚至可能在单个批量请求中,操作的顺序并不重要。默认情况下,刷新间隔为一秒,因此差异将保持最长时间。您可以通过在索引上发出刷新命令来立即强制刷新:
curl -XPOST http://127.0.0.1:9200/testidx/_refresh
以下最后一节提供了事件顺序的说明。
通过添加网址参数refresh=true
,也可以在批量请求后强制刷新。因此,如果您确实需要更改文档的ID,请按以下步骤操作:
示例:
将文件从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