9、REINDEX API Reindex要求為源索引中的所有文檔啟用_source。 不會配置目標索引,不會複製源索引的設置。你需要在reindex之前先指定 ,分片數量,副本數量等選項。 最常用的一種方式是複製一個索引。下例會將twitter索引中的文檔複製到new_twitter索引中: 返回 ...
9、REINDEX API
Reindex要求為源索引中的所有文檔啟用_source。
reindex
不會配置目標索引,不會複製源索引的設置。你需要在reindex之前先指定mapping
,分片數量,副本數量等選項。
_reindex
最常用的一種方式是複製一個索引。下例會將twitter索引中的文檔複製到new_twitter索引中:
POST _reindex
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter"
}
}
返回結果:
{
"took" : 147,
"timed_out": false,
"created": 120,
"updated": 0,
"deleted": 0,
"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": 120,
"failures" : [ ]
}
和 _update_by_query
API 一樣,_reindex從原索引獲取快照,但它的目標索引必須是不同的索引,所以不太可能發生版本衝突。dest元素可以向 index API 一樣配置,控制樂觀鎖。例如,省略version_type(和上述一樣)或者將其設置為internal,會導致Elasticsearch草率地將文檔轉儲到目標索引,從而恰巧覆蓋具有相同type和id的文檔:
POST _reindex
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter",
"version_type": "internal"
}
}
設置version_type
為external
會使Elasticsearch保存源文檔的version,創建任何不存在目標索引的文檔,並更新任何源文檔version比目標文檔version要大的文檔:
POST _reindex
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter",
"version_type": "external"
}
}
設置op_type
為create
會導致 _reindex
僅在目標索引中創建缺少的文檔。索引已存在的文檔都會導致版本衝突:
POST _reindex
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter",
"op_type": "create"
}
}
預設的版本衝突會導致_reindex
進程終止,你可以在請求體中設置"conflicts": "proceed"
來指示_reindex
繼續處理版本衝突之後的文檔。請務必註意,其他錯誤類型的處理不受“conflict”
參數的影響。當請求體中設置"conflicts": "proceed"
時,_reindex
進程將繼續發生版本衝突並返回遇到的版本衝突數:
POST _reindex
{
"conflicts": "proceed",
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter",
"op_type": "create"
}
}
你可以通過在source
欄位內添加type
欄位或query
欄位來限制文檔。如下例僅會將索引twitter
中的kimchy
複製到索引new_twitter
中:
POST _reindex
{
"source": {
"index": "twitter",
"type": "_doc",
"query": {
"term": {
"user": "kimchy"
}
}
},
"dest": {
"index": "new_twitter"
}
}
可以在source
欄位中同時列出type
和index
,允許在一個請求中複製大量數據。下例會複製來自twitter
索引和blog
索引的_doc
類型和post
類型的文檔:
POST _reindex
{
"source": {
"index": ["twitter", "blog"],
"type": ["_doc", "post"]
},
"dest": {
"index": "all_together",
"type": "_doc"
}
}
Reindex API 不會處理ID衝突,以最後寫入的文檔為準,但reindex的順序通常是不可預測,因此依賴此行為並不是一個好主意。應該使用腳本確保ID是唯一的。
也可以限制複製文檔的數量。下例僅僅從twitter
索引複製一個文檔到new_twitter
索引:
POST _reindex
{
"size": 1,
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter"
}
}
你可以指定設置sort參數指定排序規則。sort會降低scroll的效率,但是有時候必須使用。如果可以的話,最好限制size的大小。下例會從twitter
索引中複製10000個文檔到new_twitter
索引:
POST _reindex
{
"size": 10000,
"source": {
"index": "twitter",
"sort": { "date": "desc" }
},
"dest": {
"index": "new_twitter"
}
}
可以使用_source參數過濾欄位,例如,可以使用source
從twitter
索引中過濾一部分欄位,如下所示:
POST _reindex
{
"source": {
"index": "twitter",
"_source": ["user", "_doc"]
},
"dest": {
"index": "new_twitter"
}
}
_redix
和_update_by_query
一樣也支持腳本,它可以修改一個文檔,但和_update_by_query
有區別,這個script
僅允許修改文檔的metadata
:
POST _reindex
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter",
"version_type": "external"
},
"script": {
"source": "if (ctx._source.foo == 'bar') {ctx._version++; ctx._source.remove('foo')}",
"lang": "painless"
}
}
和_update_by_query
一樣,你可以設置ctx.op
改變在目標索引執行的操作:
- noop
- 設置 ctx.op = "noop",如果你的script確定文檔不需要索引到目標索引。這個空操作將會反映到響應體的noop計數器。
- delete
- 設置ctx.op = "delete",如果你的script確定必須要從目標索引中刪除文檔。刪除操作會反映到響應體的deleted計數器。
設置ctx.op為其他值會導致錯誤。
你甚至可以改變如下的元數據,但一定要小心地操作:
- _id
- _type
- _index
- _version
- _routing
- _parent
設置_version =null
或者從ctx
中清空它,等價於沒有在index 請求中發送version參數。不管目標索引文檔的版本或者你在_reindex請求中指定的版本類型是什麼,它都會導致目標索引的文檔被覆蓋。
預設情況下,如果_reindex查詢到一個指定了routing參數的文檔,在新文檔中也會保留該參數,除非你在script中改變它。你可以在dest
欄位設置routing從而改變這個設置:
keep
- 文檔的路由值在新索引中保持不變。這是預設值。
discard
- 原索引中文檔的routing值在新索引中變為null
=<some text>
- 文檔的路由值在新索引中變為指定值。
例如,你可以使用以下請求從源索引中複製所有公司名是cat的文檔到目標索引,並且指定它們的routing值都是cat:
POST _reindex
{
"source": {
"index": "source",
"query": {
"match": {
"company": "cat"
}
}
},
"dest": {
"index": "dest",
"routing": "=cat"
}
}
預設,_reindex每次scroll查詢的文檔數是1000。你可以在source元素中使用size參數改變這個大小:
POST _reindex
{
"source": {
"index": "source",
"size": 100
},
"dest": {
"index": "dest",
"routing": "=cat"
}
}
你也可以指定pipeline參數使用Ingest Node節點特性:
POST _reindex
{
"source": {
"index": "source"
},
"dest": {
"index": "dest",
"pipeline": "some_ingest_pipeline"
}
}
9.1 從遠程重建索引(Reindex from Remote)
reindex支持從遠程的集群中獲取源索引數據:
POST _reindex
{
"source": {
"remote": {
"host": "http://otherhost:9200",
"username": "user",
"password": "pass"
},
"index": "source",
"query": {
"match": {
"test": "data"
}
}
},
"dest": {
"index": "dest"
}
}
host
參數必須包含協議,主機和埠(例如:https://otherhost:9200)和可選路徑(例如https://otherhost:9200/proxy)。username
和 password
是可選的,當Elasticsearch節點需要basic auth時會使用它們。使用基本身份驗證時務必使用https,否則密碼將以純文本格式發送。有一系列設置可用於配置https
連接的行為。
遠程主機必須要在elasticsearch.yaml
使用reindex.remote.whitelist
屬性顯式指定允許連接的白名單。它可以是一個逗號分隔的列表((e.g. otherhost:9200, another:9200, 127.0.10.*:9200, localhost:*
)。白名單忽略協議,僅僅使用埠和主機。例如:
reindex.remote.whitelist: "otherhost:9200, another:9200, 127.0.10.*:9200, localhost:*"
必須將白名單配置在所有進行reindex的節點上。
這個特性可以和任何版本的遠程集群交互。允許你從任何版本的Elasticsearch升級到當前版本。
要將查詢發送到舊版的Elasticsearch,請將查詢參數直接發送到遠程主機。
從遠程群集執行reindex 不支持手動或自動切片。
遠程伺服器使用一個最大值是100mb的緩衝區。如果遠程索引包含非常大的文檔,你需要使用一個更小的批量大小(每一批的數量不要超過緩衝區大小),下麵的示例將批量大小設置為10:
POST _reindex
{
"source": {
"remote": {
"host": "http://otherhost:9200"
},
"index": "source",
"size": 10,
"query": {
"match": {
"test": "data"
}
}
},
"dest": {
"index": "dest"
}
}
你也可以使用socket_timeout
欄位指定請求的套接字進行讀取操作的超時時間,connect_timeout
欄位指定連接超時時間。預設都是30s。下例將套接字讀取超時設置為一分鐘,將連接超時設置為10秒:
POST _reindex
{
"source": {
"remote": {
"host": "http://otherhost:9200",
"socket_timeout": "1m",
"connect_timeout": "10s"
},
"index": "source",
"query": {
"match": {
"test": "data"
}
}
},
"dest": {
"index": "dest"
}
}
9.2 url參數(URL Parameters)
參考上一節
9.3 配置SSL參數(Configuring SSL parameters)
略
9.4 響應體(Response body)
json響應如下:
{
"took": 639,
"timed_out": false,
"total": 5,
"updated": 0,
"created": 5,
"deleted": 0,
"batches": 1,
"noops": 0,
"version_conflicts": 2,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": 1,
"throttled_until_millis": 0,
"failures": [ ]
}
- took
- 整個操作耗費的毫秒數
- timed_out
- 如果在執行 reindex 操作時出現超時,那麼這個標識將會返回 true
- total
- 成功執行操作的文檔的數量
- updated
- 成功的更新了多少個文檔
- ceated
- 成功的創建了多少個文檔
- deleted
- 成功的刪除了多少個文檔
- batches
- 回滾數
- verison_conflicts
- 操作過程中出現版本衝突的數量
- noops
- 由於 ctx.op=noop 設置造成的忽略的文檔數
- retries
- 重覆嘗試的次數,bulk 是批量更新操作重覆嘗試的次數,search 是查詢的重覆嘗試次數
- throthled_millis
- requests_per_second 參數引起的請求等待時間
- requests_per_second
- 在操作過程中,每秒執行的請求數
- throttled_until_millis
- 執行
reindex
時這個值始終0,只在在調用Task API時該值才有意義,它表示下一次(自紀元以來)為了符合requests_per_second
將再次執行請求的毫秒數。
- 執行
- failures
- 執行失敗的數組,包含在執行過程中任何不可恢復的錯誤。如果這個數組不是空的,那麼請求會因為這些失敗而中止。reindex 是使用批處理實現的,任何失敗都會導致整個執行被中止。可以使用conflicts參數來防止reindex在版本衝突時造成操作中止。
9.5 結合 taskAPi 使用(Works with the Task API)
您可以使用 Task API 獲取任何正在進行 update_by_query 請求的狀態:
GET _tasks?detailed=true&actions=*reindex
返回值:
{
"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/reindex",
"status" : {
"total" : 6154,
"updated" : 3500,
"created" : 0,
"deleted" : 0,
"batches" : 4,
"version_conflicts" : 0,
"noops" : 0,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": -1,
"throttled_until_millis": 0
},
"description" : "",
"start_time_in_millis": 1535149899665,
"running_time_in_nanos": 5926916792,
"cancellable": true,
"headers": {}
}
}
}
}
}
status:這個對象包含了當前任務的實際狀態。total
欄位是本次操作需要重新索引的文檔數。你可以通過 updated
, created
, and deleted
欄位估計處理進度。當以上幾個欄位的和等於 total
欄位時,請求就執行完畢了。
你可以使用 task id 查看某個任務。下例查看task id為 r1A2WoRbTwKZ516z6NEs5A:36619
的任務信息:
GET /_tasks/r1A2WoRbTwKZ516z6NEs5A:36619
該 API 可以與wait_for_comletion=false
集成使用,可以清晰的查看已完成任務的狀態。如果任務已經完成,並且在其上設置了wait_for_completion=false
,那麼請求將會返回結果或是錯誤欄位。此功能的代價是當wait_for_completion=false
時會在.tasks/task/${taskId}
目錄下會創建文檔。您可以根據需要刪除該文檔。
9.6 取消任務(Works with the Cancel Task API)
任何_update_by_query
操作都可以通過task cancel
API來取消,如:
POST _tasks/r1A2WoRbTwKZ516z6NEs5A:36619/_cancel
取消應該執行很快,但可能需要幾秒鐘。在此期間上面的 task status API將繼續列出該任務,直到它完全被取消了。
9.7 閾值(Rethrottling)
在正在執行的請求中,requests_per_second
的值可以在運行時通過_rethrotted
API進行修改:
POST _update_by_query/r1A2WoRbTwKZ516z6NEs5A:36619/_rethrottle?requests_per_second=-1
可以使用tasks API找到任務ID。
和 requests_per_seconds 參數設置一樣,rethrottling 參數可以是 - 1 (禁用限制)或是其他十進位數(如 1.7 或 12 )。rethrottling 參數能提高查詢速度且會立即生效,但是降低速度必須等到當前操作執行完後才起作用。這可以防止滾動超時
9.7.1 重建索引以更改欄位的名稱
_reindex可用於構建具有重命名欄位的索引副本。假設您創建一個包含如下所示文檔的索引:
POST test/_doc/1?refresh
{
"text": "words words",
"flag": "foo"
}
但你不喜歡flag
,並希望用tag
替換它。可以如下創建另一個索引:
POST _reindex
{
"source": {
"index": "test"
},
"dest": {
"index": "test2"
},
"script": {
"source": "ctx._source.tag = ctx._source.remove(\"flag\")"
}
}
查詢新的文檔:
GET test2/_doc/1
響應結果:
{
"found": true,
"_id": "1",
"_index": "test2",
"_type": "_doc",
"_version": 1,
"_seq_no": 44,
"_primary_term": 1,
"_source": {
"text": "words words",
"tag": "foo"
}
}
9.8 切片 (slicing)
Reindex 支持 sliced scroll 來使 reindex 操作並行進行。這能提高效率並且提供了一種將請求分解為較小的部分的便捷方式。
9.8.1 手動切片 (Manually slicing)
通過為每個請求提供切片 ID 和切片總數,手動將 _reindex 操作進行分解:
POST _reindex
{
"source": {
"index": "twitter",
"slice": {
"id": 0,
"max": 2
}
},
"dest": {
"index": "new_twitter"
}
}
POST _reindex
{
"source": {
"index": "twitter",
"slice": {
"id": 1,
"max": 2
}
},
"dest": {
"index": "new_twitter"
}
}
你可以這樣驗證上述 api 的結果:
GET _refresh
POST new_twitter/_search?size=0&filter_path=hits.total
返回如下的的結果:
{
"hits": {
"total": 120
}
}
9.8.2 自動切片 (Automatic slicing)
也可以讓 _reindex
自動並行地滾動切片。使用 slices
指定要使用的切片數:
POST _reindex?slices=5&refresh
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter"
}
}
您可以通過下列語句驗證運行結果:
POST new_twitter/_search?size=0&filter_path=hits.total
返回如下的的結果:
{
"hits": {
"total": 120
}
}
slices 設置為 auto 將允許 ElasticSearch 選擇要使用的切片數。此設置將使用一個分片一個切片,直至達到某個限制。如果存在多個源索引,它將根據具有最少分片的那個索引所擁有的分片數來作為切片數。
向_reindex
添加 slices
只會自動執行上一節中使用的手動過程,這意味著它有一些怪癖:
- 您可以在 Tasks API 中查看這些請求。這些子請求是具有
slices
請求的任務的 “子 " 任務。 - 僅使用
slices
獲取請求的任務狀態 (包含已完成切片的狀態)。 - 這些子請求可單獨定址,例如取消和重新限制。
- 使用
slices
重新處理請求將按比例重新調整未完成的子請求。 - 使用
slices
取消請求將取消每個子請求。 - 由於
slices
的性質,每個子請求都不會獲得完全均勻的文檔部分。這些切片文檔都會被處理,但某些切片可能比其他切片分到更大的文檔。 - 像
requests_per_second
這樣的參數和帶有size
的slices
請求 (按指定比例分配給每個子請求)。將其與上述關於分佈不均勻的點相結合,您應該得出結論,使用slices
的size
可能不會刪除指定大小的文檔。 - 每個子請求都會獲得和源索引略有不同的快照,儘管這些快照幾乎同時進行。
9.8.3 選擇 slices 的數量(Picking the number of slices)
如果 slices 設置為 auto,elasticsearch 將會自動為大多數索引選擇一個合理的數量。如果您設置手動切片或以其他方式來調整自動切片,請遵循以下準則:
當切片的數量等於索引的分片數時,查詢性能最好。如果這個數量太大(如 500), 請選擇一個較小的數字,因為太多的切片會影響性能。設置高於分片數的切片通常不會提高效率反而會增加開銷。
indexing 的性能與可用的切片數量呈正相關。
查詢或索引是否是影響此時運行時性能的主要原因,這取決於reindexed時的文檔和集群的資源。
9.9 重建更多的索引( Reindexing many indices)
如果你有很多索引要重新索引,通常最好一次重新索引它們,而不是使用全局模式來獲取許多索引。這樣的話如果reindex時有任何錯誤,您可以通過刪除部分已完成的索引,然後讓該索引重新執行一次reindex,從而恢復之前的流程。它還使得流程的並行化非常簡單:將索引列表拆分為reindex並並行運行每個列表。
One-off bash腳本似乎很適合這種操作:
for index in i1 i2 i3 i4 i5; do
curl -HContent-Type:application/json -XPOST localhost:9200/_reindex?pretty -d'{
"source": {
"index": "'$index'"
},
"dest": {
"index": "'$index'-reindexed"
}
}'
done
9.10 每日重覆指數( Reindex daily indices)
儘管有上述建議,您可以將_reindex與Painless結合使用新模板應用於現有文檔以實現每日重建索引。
假設您的索引由以下文檔組成:
PUT metricbeat-2016.05.30/_doc/1?refresh
{"system.cpu.idle.pct": 0.908}
PUT metricbeat-2016.05.31/_doc/1?refresh
{"system.cpu.idle.pct": 0.105}
metricbement- *索引的新模板已載入到Elasticsearch中,但它僅適用於新創建的索引。Painless 可用於reindex 已經存在的文檔並應用於新模板。
下麵的腳本從索引名稱中提取日期,並創建一個在原索引上附加了-1的新的索引。下例將metricbeat-2016.05.31
索引中的所有數據都重新編入metricbeat-2016.05.31-1
索引中。
POST _reindex
{
"source": {
"index": "metricbeat-*"
},
"dest": {
"index": "metricbeat"
},
"script": {
"lang": "painless",
"source": "ctx._index = 'metricbeat-' + (ctx._index.substring('metricbeat-'.length(), ctx._index.length())) + '-1'"
}
}
現在可以在* -1
索引中找到先前metricbeat
索引中的所有文檔:
GET metricbeat-2016.05.30-1/_doc/1
GET metricbeat-2016.05.31-1/_doc/1
以前的方法還可以與更改欄位名稱結合使用,以僅將現有數據載入到新索引中,並根據需要重命名任何欄位。
9.11 提取索引的隨機子集(Extracting a random subset of an index)
_reindex可用於提取索引的隨機子集以進行測試:
POST _reindex
{
"size": 10,
"source": {
"index": "twitter",
"query": {
"function_score" : {
"query" : { "match_all": {} },
"random_score" : {}
}
},
"sort": "_score" 【1】
},
"dest": {
"index": "random_twitter"
}
}
【1】:_reindex
預設按_doc
排序,除非您將排序覆蓋為_score
,否則random_score將不起作用。