查询更新接口是2.3.0增加新接口,这个接口目前是实验性的。此接口可能会在未来的版本中改变。此接口在索引中更新每一个文档,而文档的内容并没有改变的情况下使用,这在增加新的属性或者修改映射的时候非常有用。例如:
请求:POST /twitter/_update_by_query?conflicts=proceed
返回结果为:
{ "took" : 639, "updated": 1235, "batches": 13, "version_conflicts": 2, "failures" : [ ] }
_update_by_query当系统开始或者正在用内部版本号进行索引的时候获得一个索引的快照,当快照被处理时或者当索引请求被处理时,如果文档发生了变化,系统将会产生版本冲突。当匹配版本的文档更新后,文档的版本号会递增。当更新和查询失败时,_update_by_query将会中止并在返回值中返回失败的原因。已执行的更新将会保持。也就是说,这个过程是不回滚的,只有中止。当第一条失败时,会导致程序中止,这意味着所有的更新失败,这时候会返回大量的失败元素。
如果你想当版本冲突时只进行简单的计数,而不中止,可以在url中设置 conflicts=proceed或者在请求内容中设置"conflicts": "proceed",在api中,可以只针对索引中的一个类型进行操作,例如:
请求:POST /twitter/tweet/_update_by_query?conflicts=proceed
同样可以采用DSL语法进行查询,例如:
请求:POST /twitter/_update_by_query?conflicts=proceed
{ "query": { "term": { "user": "kimchy" } } }
这里的搜索和其他搜索的语法是一致的。
之前介绍的都是没有改变文档内容的,其实_update_by_query是可以在支持脚本对文档内容的更新。例如:
请求:POST /twitter/_update_by_query
{ "script": { "inline": "ctx._source.likes++" }, "query": { "term": { "user": "kimchy" } } }
这个接口可以在多个索引和多个类型的中同时操作,例如:
请求:POST /twitter,blog/tweet,post/_update_by_query
同时,也可以指定路由查询,例如:
请求:POST /twitter/_update_by_query?routing=1
默认情况下,_update_by_query采用滚动100批次。你可以在URL参数用scroll_size来改变批次的大小,例如:
请求:POST /twitter/_update_by_query?scroll_size=1000
除了标注的参数外,_update_by_query还支持refresh, wait_for_completion, consistency, timeout.
刷新(refresh)操作只是当请求完成时在索引更新时所有分片,这不同于更新索引时的刷新,索引的时候当收到新的数据的时候,只针对当前数据分片进行刷新。如果请求中包含wait_for_completion=false,Elasticsearch将进行执行前检查,启动请求,然后返回任务,用这个任务可以取消操作或获得任务的状态。一旦请求完成任务就结束了,唯一有记录的地方是在elasticsearch日志文件中有任务的执行结果,这个问题将在以后的版本修复。一致性(consistency)控制每次请求时有多少分片的拷贝被响应,超时控制每次请求等待的时间。在Bulk API中可以精确的知道他们是如何工作的。超时控制多久每批等待成为目标碎片。
响应介绍,每次响应的内容大概是:
{ "took" : 639, "updated": 0, "batches": 1, "version_conflicts": 2, "failures" : [ ] }
took:从开始到结束的整个操作的毫秒数。
updated:已成功更新的文档数。
batches:滚动响应的数量。
version_conflicts:通过查询命中更新的版本冲突的数量。
failures:所有索引失败的数组。如果这是非空的,则请求中止。
当查询更新操作发生后,可以使用任务接口来获取它们的状态,例如:
请求:POST /_tasks/?pretty&detailed=true&action=*byquery
响应:
{ "nodes" : { "r1A2WoRbTwKZ516z6NEs5A" : { "name" : "Tyrannus", "transport_address" : "127.0.0.1:9300", "host" : "127.0.0.1", "ip" : "127.0.0.1:9300", "attributes" : { "testattr" : "test", "portsfile" : "true" }, "tasks" : { "r1A2WoRbTwKZ516z6NEs5A:36619" : { "node" : "r1A2WoRbTwKZ516z6NEs5A", "id" : 36619, "type" : "transport", "action" : "indices:data/write/update/byquery", "status" : { "total" : 6154, "updated" : 3500, "created" : 0, "deleted" : 0, "batches" : 36, "version_conflicts" : 0, "noops" : 0 }, "description" : "" } } } } }
该对象包含实际状态。里面有个重要的参数是total,预计重建执行总的操作数。你可以通过添加更新、创建和删除字段来估计这个进展。当它们的总和等于总的列时,该请求将完成。
当创建了一个没有动态映射的索引,如果有新的数据内容,系统会添加新的映射值来匹配数据中的多个字段,例如:
请求:PUT test,数据结构只有test
{ "mappings": { "test": { "dynamic": false, "properties": { "text": {"type": "string"} } } } }
插入数据:
请求:POST test/test?refresh
{ "text": "words words", "flag": "bar" }
然后得到数据结构:
请求:PUT test/_mapping/test
{ "properties": { "text": {"type": "string"}, "flag": {"type": "string", "analyzer": "keyword"} } }
这个时候会自动添加一个flag映射。
但这个时候查询数据,不会找到任何值:
请求:POST test/_search?filter_path=hits.total
参数:
{ "query": { "match": { "flag": "bar" } } }
返回:
{ "hits" : { "total" : 0 } }
这个时候我们可以用更新的查询请求来获得数据,例如:
请求:POST test/_update_by_query?refresh&conflicts=proceed
POST test/_search?filter_path=hits.total
参数:
{ "query": { "match": { "flag": "foo" } } }
返回:
{ "hits" : { "total" : 1 } }
赛克蓝德(secisland)后续会逐步对Elasticsearch的最新版本的各项功能进行分析,近请期待。也欢迎加入
secisland公众号进行关注。