Delete By Query API
_delete_by_query 的简单用法,就是在查询匹配到的每个文档上执行删除。例如:
POST twitter/_delete_by_query
{
"query": { ①
"match": {
"message": "some message"
}
}
}
①:查询必须是有效的键值对,
query
是键,这和Search API
是同样的方式。在search api
中q
参数和上面效果是一样的。
返回如下内容:
{
"took" : 147,
"timed_out": false,
"deleted": 119,
"batches": 1,
"version_conflicts": 0,
"noops": 0,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": -1.0,
"throttled_until_millis": 0,
"total": 119,
"failures" : [ ]
}
_delete_by_query
在索引启动时获取索引的快照,并使用internal
版本控制删除它找到的内容。这意味着如果文档在拍摄快照的时间和处理删除请求之间发生更改,则会出现版本冲突。当版本匹配时,文档将被删除。
由于
internal
版本控制不支持将值0作为有效版本号,因此无法使用版本等于0的文档删除,_delete_by_query
并且将使请求失败。
在_delete_by_query
执行期间,顺序执行多个搜索请求以便找到要删除的所有匹配文档。每次找到一批文档时,都会执行相应的批量请求以删除所有这些文档。如果搜索或批量请求被拒绝,则_delete_by_query
依赖于默认策略来重试被拒绝的请求(最多10次,指数后退)。达到最大重试次数限制会导致_delete_by_query
中止,并failures
在响应中返回所有失败。已执行的删除仍然有效。换句话说,该过程不会回滚,只会中止。当第一个失败导致中止时,失败的批量请求返回的所有失败都将返回到failures
元件; 因此,可能存在相当多的失败实体。
如果您想计算版本冲突而不是让它们中止,那么请conflicts=proceed
在URL或"conflicts": "proceed"
请求正文中设置。
下面仅仅只是删除索引twitter
中类型tweet
的所有数据:
POST twitter/tweet/_delete_by_query?conflicts=proceed
{
"query": {
"match_all": {}
}
}
一次删除多个索引中的多个类型中的数据,也是可以的。例如:
POST twitter,blog/tweet,post/_delete_by_query
{
"query": {
"match_all": {}
}
}
如果你提供了routing
,接着这个路由会被复制给scroll query
,根据匹配到的路由值,来决定哪个分片来处理:
POST twitter/_delete_by_query?routing=1
{
"query": {
"range" : {
"age" : {
"gte" : 10
}
}
}
}
默认情况下,_delete_by_query
自上而下批量1000条数据,你也可以在URL中使用参数scroll_size
:
POST twitter/_delete_by_query?scroll_size=5000
{
"query": {
"term": {
"user": "kimchy"
}
}
}
URL参数
除了标准的参数,如pretty
,删除通过查询API也支持refresh
,wait_for_completion
,wait_for_active_shards
,timeout
和scroll
。
发送refresh
请求将在请求完成后刷新查询删除中涉及的所有分片。这与Delete API的refresh
参数不同,后者仅导致接收删除请求的分片被刷新。
如果请求包含,wait_for_completion=false
则Elasticsearch将执行一些预检检查,启动请求,然后返回task
可与Tasks API 一起使用以取消或获取任务状态的请求。Elasticsearch还将创建此任务的记录作为文档.tasks/task/${taskId}
。这是你的保留或删除你认为合适。完成后,删除它,以便Elasticsearch可以回收它使用的空间。
wait_for_active_shards
控制在继续请求之前必须激活碎片的副本数量。详情请见此处 。timeout
控制每个写入请求等待不可用分片变为可用的时间。两者都完全适用于 Bulk API中的工作方式。由于_delete_by_query
采用滚动搜索,你还可以指定scroll
参数来控制多长时间保持“搜索上下文”活着,例如?scroll=10m
,默认情况下它是5分钟。
requests_per_second
可以被设置为任何正十进制数(1.4
,6
, 1000
等)和节流速率_delete_by_query
通过填充每个批次由一等待时间发出的删除操作的批次。可以通过设置requests_per_second
为禁用限制-1
。
通过在批处理之间等待来完成限制,以便在_delete_by_query
内部使用的滚动 可以被赋予考虑填充的超时。填充时间是批量大小除以requests_per_second
写入所花费的时间之间的差异。默认情况下,批处理大小为1000
,因此如果requests_per_second
设置为500
:
target_time = 1000 / 500 per second = 2 seconds
wait_time = target_time - write_time = 2 seconds - .5 seconds = 1.5 seconds
由于批处理是作为单个_bulk
请求发出的,因此大批量数据将导致Elasticsearch创建许多请求,然后等待一段时间再开始下一组。这是“突发”而不是“平滑”。默认是-1
。
Response body
{
"took" : 147,
"timed_out": false,
"total": 119,
"deleted": 119,
"batches": 1,
"version_conflicts": 0,
"noops": 0,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": -1.0,
"throttled_until_millis": 0,
"failures" : [ ]
}
took
整个操作从开始到结束的毫秒数。
timed_out
true
如果在通过查询执行删除期间执行的任何请求超时 ,则将此标志设置为。
total
已成功处理的文档数。
deleted
已成功删除的文档数。
batches
通过查询删除拉回的滚动响应数。
version_conflicts
按查询删除的版本冲突数。
noops
对于按查询删除,此字段始终等于零。它只存在,以便通过查询删除,按查询更新和reindex API返回具有相同结构的响应。
retries
通过查询删除尝试的重试次数。bulk
是重试的批量操作search
的数量,是重试的搜索操作的数量。
throttled_millis
请求睡眠符合的毫秒数requests_per_second
。
requests_per_second
在通过查询删除期间有效执行的每秒请求数。
throttled_until_millis
在按查询响应删除时,此字段应始终等于零。它只在使用Task API时有意义,它指示下一次(自纪元以来的毫秒数),为了符合,将再次执行受限制的请求requests_per_second
。
failures
如果在此过程中存在任何不可恢复的错误,则会出现故障数组。如果这是非空的,那么请求因为那些失败而中止。逐个查询是使用批处理实现的,任何故障都会导致整个进程中止,但当前批处理中的所有故障都会被收集到数组中。您可以使用该conflicts
选项来防止reindex在版本冲突中中止。
Works with the Task API
你可以使用Task API
来获取任何一个正在运行的delete-by-query
请求的状态。
GET _tasks?detailed=true&actions=*/delete/byquery
返回如下内容:
{
"nodes" : {
"r1A2WoRbTwKZ516z6NEs5A" : {
"name" : "r1A2WoR",
"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/delete/byquery",
"status" : { ①
"total" : 6154,
"updated" : 0,
"created" : 0,
"deleted" : 3500,
"batches" : 36,
"version_conflicts" : 0,
"noops" : 0,
"retries": 0,
"throttled_millis": 0
},
"description" : ""
}
}
}
}
}
①这个对象包含实际的状态。响应体是
json
格式,其中total
字段是非常重要的。total
表示期望执行reindex
操作的数量。你可以通过加入的updated
、created
和deleted
字段来预估进度。但它们之和等于total
字段时,请求将结束。
使用task id
可以直接查找此task
。
GET /_tasks/taskId:1
这个api
的优点是它整合了wait_for_completion=false
来透明的返回已完成任务的状态。如果此任务完成并且设置为wait_for_completion=false
,那么其将返回results
或者error
字段。这个特性的代价就是当设置wait_for_completion=false
时,会在.tasks/task/${taskId}
中创建一个文档。当然你也可以删除这个文档。
Works with the Cancel Task API
任何一个Delete By Query
都可以使用Task Cancel API
来取消掉:
POST _tasks/task_id:1/_cancel
可以使用上面的task api
来找到task_id
;
取消应该尽快发生,但是也可能需要几秒钟,上面的task 状态 api
将会进行列出task
直到它被唤醒并取消自己。
Rethrottling
requests_per_second
的值可以在使用_rethrottle
参数的正在运行的delete by query
api上进行更改:
POST _delete_by_query/task_id:1/_rethrottle?requests_per_second=-1
使用上面的tasks API
来查找task_id
就像在_delete_by_query
中设置一样,requests_per_second
可以设置-1
来禁止这种限制或者任何一个10进制数字,像1.7
或者12
来限制到这种级别。加速查询的Rethrottling
会立即生效,但是缓慢查询的Rethrottling
将会在完成当前批处理后生效。这是为了防止scroll timeouts
。
Manually slicing
Delete-by-query
支持Sliced Scroll
,其可以使你相对容易的手动并行化进程:
POST twitter/_delete_by_query
{
"slice": {
"id": 0,
"max": 2
},
"query": {
"range": {
"likes": {
"lt": 10
}
}
}
}
POST twitter/_delete_by_query
{
"slice": {
"id": 1,
"max": 2
},
"query": {
"range": {
"likes": {
"lt": 10
}
}
}
}
你可以通过以下方式进行验证:
GET _refresh
POST twitter/_search?size=0&filter_path=hits.total
{
"query": {
"range": {
"likes": {
"lt": 10
}
}
}
}
像下面这样只有一个total
是合理的:
{
"hits": {
"total": 0
}
}
Automatic slicing
你也可以使用Sliced Scroll
让delete-by-query api
自动并行化,以在_uid
上切片:
POST twitter/_delete_by_query?refresh&slices=5
{
"query": {
"range": {
"likes": {
"lt": 10
}
}
}
}
你可以通过以下来验证:
POST twitter/_search?size=0&filter_path=hits.total
{
"query": {
"range": {
"likes": {
"lt": 10
}
}
}
}
像下面的total
是一个合理的结果:
{
"hits": {
"total": 0
}
}
添加slices
,_delete_by_query
将会自动执行上面部分中使用手动处理的部分,创建子请求这意味着有些怪事:
- 你可以在
Tasks APIs
中看到这些请求。这些子请求是使用了slices
请求任务的子任务。 - 为此请求(使用了
slices
)获取任务状态仅仅包含已完成切片的状态。 - 这些子请求都是独立寻址的,例如:取消和
rethrottling
. - Rethrottling the request with slices will rethrottle the unfinished sub-request proportionally.
- 取消
slices
请求将会取消每个子请求。 - 由于
slices
的性质,每个子请求并不会得到完全均匀的文档结果。所有的文档都将要处理,但是有些slices
(切片)会大些,有些会小些。希望大的slices
(切片)有更均匀的分配。 - 在
slices
请求中像requests_per_second
和size
参数,按比例分配给每个子请求。结合上面的关于分配的不均匀性,你应该得出结论:在包含slices
的_delete_by_query
请求中使用size
参数可能不会得到正确大小的文档结果。 - 每个子请求都会获得一个略微不同的源索引快照,尽管这些请求都是大致相同的时间。
Picking the number of slices
这里我们有些关于slices
数量的建议(如果是手动并行的话,那么在slice api
就是max
参数):
- 不要使用大数字。比如500,将会创建相当大规模的
CPU
震荡。
这里说明下震荡(thrashing)的意思:cpu
大部分时间都在进行换页,而真正工作时间却很短的现象称之为thrashing (震荡)
- 从查询性能角度来看,在源索引中使用多个分片是更高效的。
- 从查询性能角度来看,在源索引中使用和分片相同的数量是更高效的。
- 索引性能应该在可利用
slices
之间进行线性扩展。 - 索引(插入)或查询性能是否占主导地位取决于诸多因素,比如:重新索引文档和集群进行重新索引。