刪除API

Delete API

刪除API容許根據ID從指定索引中刪除一個類型化的JSON文檔。html

DELETE /twitter/_doc/1

返回結果以下:node

{
  "_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

創建索引時使用了路由,那麼刪除文檔,也必須提供路由值。 例如:api

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並拒絕請求。elasticsearch

自動建立索引

若是使用外部版本,以前還沒有建立索引,則刪除操做會自動建立一個索引,而且若是以前未建立映射,還會爲指定類型自動建立動態類型映射。ide

Distributed

經過hash計算出某個分片ID。 而後刪除操做被重定向到該ID組中的主分片,而且被複制(若是須要)到該ID分組內的分片副本(有點不理解,應該是刪除操做會在副本上執行一遍)。oop

等待活躍的Shards

在發出刪除請求時,能夠設置 wait_for_active_shards 參數,使得處理刪除請求以前,必須知足最小數量的分片副本處於活動狀態,不然會等待而不會立刻執行刪除,。 有關更多詳細信息和用法示例,請參閱此處post

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

相關文章
相關標籤/搜索