4、Delete By Query API
_delete_by_query API
可以删除某个匹配条件的文档:
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
在查找的时候会先获取索引的快照,并删除那些使用内部版本类型的文档。这意味着如果文档在获取快照和处理删除请求之间被修改了,就会造成版本号冲突。
当版本匹配时,文档将被删除。
因为内部版本不支持0,所以使用
_delete_by_query
将无法删除版本号为0的文档。
_delete_by_query
执行期间,会分多次顺序查询要删除的文档。每次查询完之后就会使用批处理一次性删除本批次的文档。如果在这个过程中的某次搜索或删除操作失败,默认会重试10次(速度呈指数下降)。当重试次数达到最大值的时候,_delete_by_query
操作就会终止,并在响应中返回所有失败(failures
字段)信息。已经执行的删除操作依然是生效的。换句话说,这个处理过程是不会回滚的,只会中止。因此其中的一些文档有可能删除失败。
如果你不想因为版本冲突导致操作中断,你可以在url中设置conflicts=proceed
或者在请求体中设置conflicts:proceed
。
下例将删除twitter索引里面的所有tweets:
POST twitter/_doc/_delete_by_query?conflicts=proceed
{
"query": {
"match_all": {}
}
}
你也可以一次删除多个索引和多个类型的文档:
POST twitter,blog/_docs,post/_delete_by_query
{
"query": {
"match_all": {}
}
}
如果你提供routing
参数,该参数会被放在到scroll
查询中,只删除满足routing条件的分片中的文档。
POST twitter/_delete_by_query?routing=1
{
"query": {
"range" : {
"age" : {
"gte" : 10
}
}
}
}
默认情况下,_delete_by_query使用scroll query api
查询1000个文档,你可以指定scroll_size
参数来修改它:
POST twitter/_delete_by_query?scroll_size=5000
{
"query": {
"term": {
"user": "kimchy"
}
}
}
4.1 URL参数(URL Parameters)
_delete_by_query
API 同样支持refresh
, wait_for_completion
, wait_for_active_shards
,timeout
,scroll
、pretty
等参数。
- refresh参数:执行完删除操作后刷新_delete_by_query中查询涉及的分片。与delete API不同,delete API只会刷新接收到删除请求的分片。refresh参数不支持wait_for。
- wait_for_completion:如果请求中wait_for_completion=false,那么elasticsearch将会执行预检查、执行请求,然后返回可与任务API一起使用的任务,以取消或获取任务的状态。elasticsearch还将在.task/task/${taskId}处创建此任务的记录文档。您可以根据需要保留或删除该文档。用完删除后,elasticsearch可以回收其占用的空间。
- wait_for_active_shards:控制在执行请求之前必须有多少个分片是活跃状态的。
- timeout:控制每个请求等待不可用的分片的时间。因为_delete_by_query使用scroll查询,所以您可以通过设置scroll参数来控制search context保持活动的时间,如scroll=10m。默认为5分钟。
- requests_per_second:可以设置成任意正数(如1.4,6,1000等),并且通过设置等待的时间来控制_delete_by_query批量操作执行删除操作的速率。设置requests_per_second设置为-1表示停用该限制。
速率限制是通过在批量处理之间等待来完成的,这样就可以为_delete_by_query内部使用的回滚指定一个考虑填充的超时时间。填充时间是批处理大小除以requests_per_second与写入时间只差。默认情况下,批处理大小为1000,因此如request_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。
4.2 响应体(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:如果在执行 delete by query 操作时出现超时,那么这个标识将会返回true
- total:成功执行操作的文档的数量
- deleted:成功删除的文档数量
- batches : 回滚数
- version_conflicts:操作过程中出现版本冲突的数量
- noops:执行
_delete_by_query
时这个值始终是0,之所以存在是因为_delete_by_query、update_by_query、reindex APIs
都返回相同的响应结构。 - retries:在操作过程中重试的次数,bulk是批量删除操作重复尝试的次数,search是查询的重复尝试次数
- throttled_millis:满足requests_per_second参数的请求休眠的毫秒数
- requests_per_second:在操作过程中,每秒执行的请求数
- throttled_until_millis:执行
_delete_by_query
时这个值始终0,只在在调用Task API时该值才有意义,它表示下一次(自纪
元以来)为了符合requests_per_second
,将再次执行请求的毫秒数。 - failures:执行失败的数组,包含在执行过程中任何不可恢复的错误。如果这个数组不是空的,那么请求会因为这些失败而中
止。_delete_by_query是使用批处理实现的,任何失败都会导致整个执行被中止。可以使用conflicts参数来防止
reindex在版本冲突时造成操作中止。
4.3 结合taskAPi使用(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" : ""
}
}
}
}
}
status:这个对象包含了当前任务的实际状态。total
字段是本次操作需要重新索引的文档数。你可以通过updated
, created
, and deleted
字段估计处理进度。当以上几个字段的和等于total
字段时,请求就执行完毕了。
你可以使用 task id 查看某个任务:
GET /_tasks/r1A2WoRbTwKZ516z6NEs5A:36619
如果在执行delete_by_query
的时候指定了wait_for_completion=false
参数,就可以通过该API查看任务的执行情况。
该 API 可以与wait_for_comletion=false
集成使用,以便能清晰的返回已完成任务的状态。如果任务已经完成,并且在其上设置了wait_for_completion=false
,那么请求将会返回结果或是错误字段。此功能的成本是当wait_for_completion=false
时在.tasks/task/${taskId}
目录下会创建文档。您可以根据需要删除该文档。
4.4 取消任务(Works with the Cancel Task API)
任何delete_by_query
操作都可以通过task cancel
API来取消,如:
POST _tasks/r1A2WoRbTwKZ516z6NEs5A:36619/_cancel
取消应该执行很快,但可能需要几秒钟。在次期间上面的 task status API将继续列出该任务,直到它完全被取消了。
4.5 阈值(Rethrottling)
在正在执行的请求中,requests_per_second
的值可以在运行时通过_rethrotted
API进行修改:
POST _delete_by_query/r1A2WoRbTwKZ516z6NEs5A:36619/_rethrottle?requests_per_second=-1
可以使用tasks API找到任务ID。
4.6 切片(slicing)
delete_by_query 支持 sliced scroll 来使删除操作并行进行,这能提高效率并且能提供一种将请求分解为较小的部分的便捷方式。
4.6.1 手动切片(Manually slicing)
通过为每个请求提供切片ID和切片总数,手动将_delete_by_query 操作进行分解:
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
}
}
}
}
你可以这样验证上述api的结果:
GET _refresh
POST twitter/_search?size=0&filter_path=hits.total
{
"query": {
"range": {
"likes": {
"lt": 10
}
}
}
}
返回如下的的结果:
{
"hits": {
"total": 0
}
}
4.6.2 自动切片(Automatic slicing)
也可以让delete by query 自动并行地滚动切片。使用slices
指定要使用的切片数:
POST twitter/_delete_by_query?refresh&slices=5
{
"query": {
"range": {
"likes": {
"lt": 10
}
}
}
}
你可以这样验证上述api的结果:
POST twitter/_search?size=0&filter_path=hits.total
{
"query": {
"range": {
"likes": {
"lt": 10
}
}
}
}
返回如下的的结果:
{
"hits": {
"total": 0
}
}
将 slices 设置为 auto 将允许 ElasticSearch 选择要使用的切片数。此设置将使用每个分片一个切片,直至达到某个限制。如果存在多个源索引,它将根据具有最小分片数的索引选择切片数。
向_delete_by_query添加slices
只会自动执行上一节中使用的手动过程,这意味着它有一些怪癖:
- 您可以在 Tasks API 中查看这些请求。这些子请求是具有
slices
请求的任务的“子"任务。 - 仅使用
slices
获取请求的任务状态(包含已完成切片的状态)。 - 这些子请求可单独寻址,例如取消和重新限制。
- 使用
slices
重新处理请求将按比例重新调整未完成的子请求。 - 使用
slices
取消请求将取消每个子请求。 - 由于
slices
的性质,每个子请求都不会获得完全均匀的文档部分。这些切片文档都会被处理,但某些切片可能比其他切片分到更大的文档。 - 像
requests_per_second
这样的参数和带有size
的slices
请求(按指定比例分配给每个子请求)。将其与上述关于分布不均匀的点相结合,您应该得出结论,使用slices
的size
可能不会删除指定大小的文档。 - 每个子请求都会获得和源索引略有不同的快照,尽管这些快照几乎同时进行。
4.6.3 选择slices的数量
如果设置 slices
为自动切片,它将为大多数索引选择一个合理的数字。如果您是手动切片或以其他方式来调整自动切片,请使用以下准则:
当切片数等于索引中的分片数时,查询性能最有效。如果该数字很大(例如500),请选择一个较小的数字,因为太多的切片会影响性能。设置高于分片数量的切片通常不会提高效率,反而会增加开销。
删除性能随着可用资源的切片数线性扩展。
查询或删除是否支配运行时的性能取决于重新索引的文档和群集资源。