删除API
Posted 冰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了删除API相关的知识,希望对你有一定的参考价值。
Delete API
删除API允许根据ID从指定索引中删除一个类型化的JSON文档。
DELETE /twitter/_doc/1
返回结果如下:
{ "_index": "twitter", "_type": "_doc", "_id": "1", "_version": 3, "result": "deleted", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 2, "_primary_term": 8 }
Versioning
索引的每个文档都是版本化的。 删除文档时,可以指定版本,防止我们要删除的文档实际上已被删除,但是在这期间没有更改。 每个在文档上执行的写操作,包括删除,都会使其版本增加。 已删除文档的版本号在删除后短时间内保持可用,以允许控制并发操作。 删除文档版本保持可用的时间长度由 index.gc_deletes 索引设置确定,默认为60秒。
Routing
建立索引时使用了路由,那么删除文档,也必须提供路由值。 例如:
DELETE /twitter_01/_doc/2?routing=user1
返回结果如下:
{ "_index": "twitter_01", "_type": "_doc", "_id": "2", "_version": 2, "result": "deleted", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 1, "_primary_term": 2 }
以上将删除id为2的twitter_01,但会根据用户进行路由。 请注意,如果路由不正确,那么删除操作就会失败,文档不会被删除。
当_routing 映射设置为必须的,如果不指定路由值,删除API就会抛出RoutingMissingException并拒绝请求。
自动创建索引
如果使用外部版本,之前尚未创建索引,则删除操作会自动创建一个索引,并且如果之前未创建映射,还会为指定类型自动创建动态类型映射。
Distributed
通过hash计算出某个分片ID。 然后删除操作被重定向到该ID组中的主分片,并且被复制(如果需要)到该ID分组内的分片副本(有点不理解,应该是删除操作会在副本上执行一遍)。
等待活跃的Shards
在发出删除请求时,可以设置 wait_for_active_shards 参数,使得处理删除请求之前,必须满足最小数量的分片副本处于活动状态,否则会等待而不会马上执行删除,。 有关更多详细信息和用法示例,请参阅此处。
Refresh
控制此请求所做的更改对搜索是否可见。 请参阅。
Timeout
执行删除操作时,分配的主分片可能不可用。 造成这种情况的一些原因可能是主分片目前正在从存储中恢复或正在进行迁移。 默认情况下,删除操作将等待主分片最多1分钟,如果还是不可用则响应并显示错误。 timeout参数可用于显式指定它等待的时间。 以下是将其设置为5分钟的示例: DELETE /twitter/_doc/1?timeout=5m
Delete By Query API
_delete_by_query 的最简单用法是对每个匹配查询的文档执行删除操作。 这里是API:
POST twitter/_delete_by_query { "query": { "match": { "message": "some message" } } }
查询可以与Search API的方式相同,作为一个值传递给query键(就像上面这样)。 您也可以按照与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不是有效版本号,因此版本等于零的文档不能使用_delete_by_query进行删除,请求会失败。
在执行_delete_by_query过程中,会依次执行多个搜索请求,查找所有匹配文档并进行删除。每次找到一批文档时,会执行相应的批处理请求删除这些文档。如果搜索或批量请求被拒绝,_delete_by_query依赖默认策略重试拒绝的请求(最多10次,指数退避算法)。达到最大重试限制会导致_delete_by_query中止,这些失败的文档会响应在failures元素中。已执行的删除操作仍然有效。换句话说,该过程不会回滚,只能中止。
如果首次执行就失败而导致中止,所有失败都会在failures元素中返回;因此有可能存在相当多的失败实体。
如果您想计算版本冲突而不是导致它们中止,可以在url中设置conflicts=proceed 或者在请求正文中使用 "conflicts": "proceed"
向下面这样:
POST twitter/_doc/_delete_by_query?conflicts=proceed { "query": { "match_all": {} } }
也可以一次删除多个索引和多个类型的文档,索引和类型之间用/分隔。像search API一样:
POST twitter,blog/_docs,post/_delete_by_query { "query": { "match_all": {} } }
如果您提供了路由,那么路由将被复制给滚动查询,限制只有匹配该路由值的分片才能进行处理,从而提升查询效率:
POST twitter/_delete_by_query?routing=1 { "query": { "range" : { "age" : { "gte" : 10 } } } }
默认情况下,_delete_by_query使用1000的滚动批处理。您可以使用scroll_size 这个URL参数更改批处理大小:
POST twitter/_delete_by_query?scroll_size=5000 { "query": { "term": { "user": "kimchy" } } }
URL 参数
除了像pretty这样的标准参数之外,Delete By Query API也支持refresh,wait_for_completion,wait_for_active_shards,timeout and scroll。
发送refresh将刷新参与删除查询的所有分片。这与Delete API的refresh参数不同,后者只会刷新接收删除请求的分片。
如果请求包含wait_for_completion = false,则Elasticsearch将执行一些预先检查,发起请求,然后返回task,可与Tasks APIs 一起使用以取消或获取任务的状态。 Elasticsearch也会在.tasks/task/${taskId}中以文档的形式创建此任务的记录。保留或删除取决于你。当不需要的时候尽量删除它,以便Elasticsearch可以回收它使用的空间。
wait_for_active_shards控制在处理请求之前多少个分片副本必须处于活动状态。详情请看这里。timeout控制每个写请求等待不可用分片变得可用的时间。这恰恰也是他们在Bulk API中的工作方式。由于_delete_by_query使用滚动搜索,可以指定scroll参数来控制它保持“搜索上下文” 活着的(alive)时间,例如?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
响应的JSON向下面这样:
{ "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:如果在此处理中存在任何不可恢复的错误,则会出现在failures数组中。 如果非空,那么请求会因为那些失败而中止。 Delete-by-query是使用批处理实现的,任何故障都会导致整个进程中止,但当前批处理中的所有故障都会被收集到数组中。 您可以使用conflict选项来防止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" : "" } } } } }
返回的status对象包含实际状态。 它就像是total字段的重要补充。 total是reindex预期执行的操作总数。 可以通过添加更新,创建和删除字段来估算进度。 当他们的总数等于total字段,请求将完成。
使用任务ID,您可以直接查找任务:
GET /_tasks/taskId:1
该API的优点是它与wait_for_completion = false集成,以透明地返回已完成任务的状态。 如果任务完成并且wait_for_completion = false已设置,则它将返回results或error字段。 此功能的代价是会在.tasks/task/$ {taskId}处创建wait_for_completion = false的文档。 删不删除该文档取决于你。
Works with the Cancel Task API
任何通过查询删除的操作都可以使用Task Cancel API来取消:
POST _tasks/task_id:1/_cancel
可以使用上面的tasks API找到task_id。
取消应该会很快发生,但可能需要几秒钟。 上面的task status API将继续列出任务,直到它被唤醒以取消自己。
Rethrottling
运行中的查询删除,其中的request_per_second的值可以使用_rethrottle API更改:
POST _delete_by_query/task_id:1/_rethrottle?requests_per_second=-1
可以使用上面的tasks API找到task_id。
request_per_second就和在_delete_by_query API上设置一样,可以是-1来禁用限制,或者任何十进制数字如1.7或12来限制到相应的级别。 加快查询速度的Rethrottling会立即生效,但降低查询速度的rethrotting则在完成当前批次后生效。 这可以防止滚动超时。
Slicing
Delete-by-query支持切片滚动去并行化删除处理。这种并行化可以提高效率,并提供一种方便的方式将请求分解成更小的部分。
手动切片
为delete-by-query的每个请求手动提供一个切片ID和切片总数:
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 } }
自动切片
还可以让delete-by-query自动并行。 使用slices 指定要使用的切片数量:
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为auto将让Elasticsearch选择要使用的切片数量。该设置将使每个分片一个切片,直到某个限制。如果有多个源索引,它将根据分片数最少的索引来选择切片的数量。
向_delete_by_query添加slices只是使上述部分中使用的手动过程自动化,创建子请求,这意味着它有一些怪异:
- 可以在Tasks APIs中看到这些请求。这些子请求是具有slices请求的任务的“子”任务。
- 具有slices的请求,获取任务的状态只包含已完成切片的状态。
- 这些子请求可单独寻址,例如取消和重新限制。
- 限制带
slices
的请求将也会适当地限制未完成的子请求。 - 取消带slices的请求也将会取消每个子请求。
- 用切片取消请求将取消每个子请求。
- 由于切片的性质,每个子请求获得的文档不会被均匀分布。所有文档都将被寻址,但有些切片可能比其他切片大。 期望更大的切片具有更均匀的分布。
- 诸如request_per_second和size之类的参数,具有slices的请求会按比例分配给每个子请求。结合上面关于分布不均匀的观点,你应该得出结论:使用size和slices可能不会导致正确的size文档变为`_delete_by_query`ed (这句不通,贴个原文:the using size with slices might not result in exactly size documents being `_delete_by_query`ed.)。
- 每个子请求都会获取与索引略微不同的快照,尽管这些快照几乎都是在同一时间取得的。
选择切片的数量
如果是自动切片,将slices
设置为 auto
将为大多数索引选择合理的数字。如果是手动切片或调整自动切片,请采用这种方式。
当slices数等于索引中的分片数时,查询性能最为有效。如果这个数字很大(例如500),请选择一个较小的数字,因为太多的slices会损害性能。如果slices数高于分片数,通常不会提高效率反而会增加开销。
删除性能在可用资源与切片数量之间成线性变化。
无论是查询还是删除,影响性能的主要因素还是重建索引的文档和群集资源。
官方文档:
https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html
以上是关于删除API的主要内容,如果未能解决你的问题,请参考以下文章