elasticsearch 基礎 —— Delete By Query API
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
之間進行線性擴充套件。 - 索引(插入)或查詢效能是否占主導地位取決於諸多因素,比如:重新索引文件和叢集進行重新索引。