#Elasticsearch深刻:Reindex API

從本地重建索引

Reindex不會嘗試設置目標索引。它不會複製源索引的設置信息。您應該在運行_reindex操做以前設置目標索引,包括設置映射,分片數,副本等。html

_reindex的最基本形式只是將文檔從一個索引複製到另外一個索引。下面將文檔從twitter索引複製到new_twitter索引中:node

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同樣,_reindex獲取源索引的快照,但其目標索引必須是不一樣的索引,所以不會發生版本衝突。 dest元素能夠像索引API同樣進行配置,以控制樂觀併發控制。只需將version_type 空着(像上面同樣)或將version_type設置爲internal則Elasticsearch強制性的將文檔轉儲到目標中,覆蓋具備相同類型和ID的任何內容:git

POST _reindex
{
  "source": {
    "index": "twitter"
  },
  "dest": {
    "index": "new_twitter",
    "version_type": "internal"
  }
}
將version_type設置爲external將致使Elasticsearch從源文件中保留版本,建立缺失的全部文檔,並更新在目標索引中比源索引中版本更老的全部文檔:

 
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進程,但您能夠經過請求體設置"conflict":"proceed"來在衝突時進行計數:

POST _reindex
{
  "conflicts": "proceed",
  "source": {
    "index": "twitter"
  },
  "dest": {
    "index": "new_twitter",
    "op_type": "create"
  }
}
您能夠經過向source添加type或添加query來限制文檔。下面會將kimchy發佈的tweet複製到new_twitter中:

POST _reindex
{
  "source": {
    "index": "twitter",
    "type": "tweet",
    "query": {
      "term": {
        "user": "kimchy"
      }
    }
  },
  "dest": {
    "index": "new_twitter"
  }
}

source中的indextype均可以是一個列表,容許您在一個請求中從大量的來源進行復制。下面將從twitterblog索引中的tweetpost類型中複製文檔。它也包含twitter索引中post類型以及blog索引中的tweet類型。若是你想更具體,你將須要使用query。它也沒有努力處理ID衝突。目標索引將保持有效,但因爲迭代順序定義不正確,預測哪一個文檔能夠保存下來是不容易的。json

POST _reindex
{
  "source": {
    "index": ["twitter", "blog"],
    "type": ["tweet", "post"]
  },
  "dest": {
    "index": "all_together"
  }
}

還能夠經過設置大小限制處理的文檔的數量。下面只會將單個文檔從twitter複製到new_twitterapi

POST _reindex
{
  "size": 1,
  "source": {
    "index": "twitter"
  },
  "dest": {
    "index": "new_twitter"
  }
}

若是你想要從twitter索引得到一個特定的文檔集合你須要排序。排序使滾動效率更低,但在某些狀況下它是值得的。若是可能,更喜歡更多的選擇性查詢sizesort。這將從twitter復10000個文檔到new_twitter數組

POST _reindex
{
  "size": 10000,
  "source": {
    "index": "twitter",
    "sort": { "date": "desc" }
  },
  "dest": {
    "index": "new_twitter"
  }
} 

source部分支持搜索請求中支持的全部元素。例如,只使用原始文檔的一部分字段,使用源過濾以下所示:

POST _reindex
{
  "source": {
    "index": "twitter",
    "_source": ["user", "tweet"]
  },
  "dest": {
    "index": "new_twitter"
  }
}

update_by_query同樣,_reindex支持修改文檔的腳本。與_update_by_query不一樣,腳本容許修改文檔的元數據。此示例修改了源文檔的版本:服務器

POST _reindex
{
  "source": {
    "index": "twitter"
  },
  "dest": {
    "index": "new_twitter",
    "version_type": "external"
  },
  "script": {
    "inline": "if (ctx._source.foo == 'bar') {ctx._version++; ctx._source.remove('foo')}",
    "lang": "painless"
  }
} 

就像在_update_by_query中同樣,您能夠設置ctx.op來更改在目標索引上執行的操做:

noop
若是您的腳本決定沒必要進行任何更改,請設置 ctx.op ="noop" 。這將致使_update_by_query 從其更新中忽略該文檔。這個沒有操做將被報告在響應體的 noop 計數器上。

delete
若是您的腳本決定必須刪除該文檔,請設置ctx.op="delete"。刪除將在響應體的 deleted 計數器中報告。

將ctx.op設置爲其餘任何內容都是錯誤。在ctx中設置任何其餘字段是一個錯誤。

想一想可能性!只要當心點,有很大的力量...你能夠改變:

_id
_type
_index
_version
_routing
_parent

將_version設置爲null或從ctx映射清除就像在索引請求中不發送版本同樣。這將致使目標索引中的文檔被覆蓋,不管目標版本或_reindex請求中使用的版本類型如何。

默認狀況下,若是_reindex看到具備路由的文檔,則路由將被保留,除非腳本被更改。您能夠根據dest請求設置routing來更改:併發

  • keep:將批量請求的每一個匹配項的路由設置爲匹配上的路由。默認值。
  • discard:將批量請求的每一個匹配項的路由設置爲null
  • =<某些文本>:將批量請求的每一個匹配項的路由設置爲`=`以後的文本。

例如,您可使用如下請求將source索引的全部公司名稱爲cat的文檔複製到路由設置爲catdest索引。less

POST _reindex
{
  "source": {
    "index": "source",
    "query": {
      "match": {
        "company": "cat"
      }
    }
  },
  "dest": {
    "index": "dest",
    "routing": "=cat"
  }
}

默認狀況下,_reindex批量滾動處理大小爲1000.您能夠在source元素中指定size字段來更改批量處理大小:dom

POST _reindex
{
  "source": {
    "index": "source",
    "size": 100
  },
  "dest": {
    "index": "dest",
    "routing": "=cat"
  }
}

Reindex也可使用[Ingest Node]功能來指定pipeline, 就像這樣:

POST _reindex
{
  "source": {
    "index": "source"
  },
  "dest": {
    "index": "dest",
    "pipeline": "some_ingest_pipeline"
  }
}

從遠程重建索引

Reindex支持從遠程Elasticsearch羣集重建索引:

POST _reindex
{
  "source": {
    "remote": {
      "host": "http://otherhost:9200",
      "username": "user",
      "password": "pass"
    },
    "index": "source",
    "query": {
      "match": {
        "test": "data"
      }
    }
  },
  "dest": {
    "index": "dest"
  }
}

host參數必須包含schemehostport(例如 https:// otherhost:9200)。用戶名和密碼參數是可選的,當它們存在時,索引將使用基本認證鏈接到遠程Elasticsearch節點。使用基本認證時請務必使用https,密碼將以純文本格式發送。

必須在elasticsearch.yaml中使用reindex.remote.whitelist屬性將遠程主機明確列入白名單。它能夠設置爲容許的遠程hostport組合的逗號分隔列表(例如otherhost:9200,another:9200,127.0.10.*:9200,localhost:*)。白名單忽略了scheme ——僅使用主機和端口。

此功能應適用於您可能找到的任何版本的Elasticsearch的遠程羣集。這應該容許您從任何版本的Elasticsearch升級到當前版本,經過從舊版本的集羣從新創建索引。

要啓用發送到舊版本Elasticsearch的查詢,query參數將直接發送到遠程主機,無需驗證或修改。

來自遠程服務器的從新索引使用默認爲最大大小爲100mb的堆棧緩衝區。若是遠程索引包含很是大的文檔,則須要使用較小的批量大小。下面的示例設置很是很是小的批量大小10

POST _reindex
{
  "source": {
    "remote": {
      "host": "http://otherhost:9200"
    },
    "index": "source",
    "size": 10,
    "query": {
      "match": {
        "test": "data"
      }
    }
  },
  "dest": {
    "index": "dest"
  }
}

也可使用socket_timeout字段在遠程鏈接上設置socket的讀取超時,並使用connect_timeout字段設置鏈接超時。二者默認爲三十秒。此示例將套接字讀取超時設置爲一分鐘,並將鏈接超時設置爲十秒:

POST _reindex
{
  "source": {
    "remote": {
      "host": "http://otherhost:9200",
      "socket_timeout": "1m",
      "connect_timeout": "10s"
    },
    "index": "source",
    "query": {
      "match": {
        "test": "data"
      }
    }
  },
  "dest": {
    "index": "dest"
  }
}

Reindex API

1. URL參數

除了標準參數像pretty以外,「Reindex API」還支持refreshwait_for_completionwait_for_active_shardstimeout以及requests_per_second

發送refresh將在更新請求完成時更新索引中的全部分片。這不一樣於 Index API 的refresh參數,只會致使接收到新數據的分片被索引。

若是請求包含wait_for_completion=false,那麼Elasticsearch將執行一些預檢檢查、啓動請求、而後返回一個任務,能夠與Tasks API一塊兒使用來取消或獲取任務的狀態。Elasticsearch還將以.tasks/task/${taskId}做爲文檔建立此任務的記錄。這是你能夠根據是否合適來保留或刪除它。當你完成它時,刪除它可讓Elasticsearch回收它使用的空間。

wait_for_active_shards控制在繼續請求以前必須有多少個分片必須處於活動狀態,詳見這裏timeout控制每一個寫入請求等待不可用分片變成可用的時間。二者都能正確地在Bulk API中工做。

requests_per_second能夠設置爲任何正數(1.4,6,1000等),來做爲「delete-by-query」每秒請求數的節流閥數字,或者將其設置爲-1以禁用限制。節流是在批量批次之間等待,以便它能夠操縱滾動超時。等待時間是批次完成的時間與request_per_second * requests_in_the_batch的時間之間的差別。因爲分批處理沒有被分解成多個批量請求,因此會致使Elasticsearch建立許多請求,而後等待一段時間再開始下一組。這是「突發」而不是「平滑」。默認值爲-1。

2. 響應體

JSON響應相似以下:

{
  "took" : 639,
  "updated": 0,
  "created": 123,
  "batches": 1,
  "version_conflicts": 2,
  "retries": {
    "bulk": 0,
    "search": 0
  }
  "throttled_millis": 0,
  "failures" : [ ]
}
  • took:從整個操做的開始到結束的毫秒數。
  • updated:成功更新的文檔數。
  • upcreateddated:成功建立的文檔數。
  • batches:經過查詢更新的滾動響應數量。
  • version_conflicts:根據查詢更新時,版本衝突的數量。
  • retries:根據查詢更新的重試次數。bluk 是重試的批量操做的數量,search 是重試的搜索操做的數量。
  • throttled_millis:請求休眠的毫秒數,與`requests_per_second`一致。
  • failures:失敗的索引數組。若是這是非空的,那麼請求由於這些失敗而停止。請參閱 conflicts 來如何防止版本衝突停止操做。

3. 配合Task API使用

您可使用Task API獲取任何正在運行的重建索引請求的狀態:

GET _tasks?detailed=true&actions=*/update/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/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
          },
          "description" : ""
        }
      }
    }
  }
}

① 此對象包含實際狀態。它就像是響應json,重要的添加total字段。 total是重建索引但願執行的操做總數。您能夠經過添加的updatedcreateddeleted的字段來估計進度。當它們的總和等於total字段時,請求將完成。

使用任務id能夠直接查找任務:

GET /_tasks/taskId:1

這個API的優勢是它與wait_for_completion=false集成,以透明地返回已完成任務的狀態。若是任務完成而且wait_for_completion=false被設置,那麼它將返回resultserror字段。此功能的成本是wait_for_completion=false.tasks/task/${taskId}建立的文檔,由你本身刪除該文件。

4. 配合取消任務API使用

全部重建索引都能使用Task Cancel API取消:

POST _tasks/task_id:1/_cancel 

可使用上面的任務API找到task_id。

取消應儘快發生,但可能須要幾秒鐘。上面的任務狀態API將繼續列出任務,直到它被喚醒取消自身。

5. 重置節流閥

request_per_second的值能夠在經過查詢刪除時使用_rethrottle API更改:

POST _update_by_query/task_id:1/_rethrottle?requests_per_second=-1 

可使用上面的任務API找到task_id。

就像在_update_by_query API中設置它同樣,request_per_second能夠是-1來禁用限制,或者任何十進制數字,如1.7或12,以節制到該級別。加速查詢的會當即生效,可是在完成當前批處理以後,減慢查詢的纔會生效。這樣能夠防止滾動超時。

6. 修改字段名

_reindex可用於使用重命名的字段構建索引的副本。假設您建立一個包含以下所示的文檔的索引:

POST test/test/1?refresh
{
  "text": "words words",
  "flag": "foo"
} 

可是你不喜歡這個flag名稱,而是要用tag替換它。 _reindex能夠爲您建立其餘索引:

POST _reindex
{
  "source": {
    "index": "test"
  },
  "dest": {
    "index": "test2"
  },
  "script": {
    "inline": "ctx._source.tag = ctx._source.remove(\"flag\")"
  }
} 

如今你能夠獲得新的文件:

GET test2/test/1 

{
  "found": true,
  "_id": "1",
  "_index": "test2",
  "_type": "test",
  "_version": 1,
  "_source": {
    "text": "words words",
    "tag": "foo"
  }
} 

或者你能夠經過tag進行任何你想要的搜索。

7. 手動切片

重建索引支持滾動切片,您能夠相對輕鬆地手動並行化處理:

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"
  }
} 

您能夠經過如下方式驗證:

GET _refresh
POST new_twitter/_search?size=0&filter_path=hits.total 

其結果一個合理的total像這樣:

{
  "hits": {
    "total": 120
  }
}

8. 自動切片

你還可讓重建索引使用切片的_uid來自動並行的滾動切片

POST _reindex?slices=5&refresh
{
  "source": {
    "index": "twitter"
  },
  "dest": {
    "index": "new_twitter"
  }
} 

您能夠經過如下方式驗證:

POST new_twitter/_search?size=0&filter_path=hits.total 

其結果一個合理的total像這樣:

{
  "hits": {
    "total": 120
  }
}

slices添加到_reindex中能夠自動執行上述部分中使用的手動過程,建立子請求,這意味着它有一些怪癖:

  • 您能夠在Task API中看到這些請求。這些子請求是具備slices請求任務的「子」任務。
  • 獲取slices請求任務的狀態只包含已完成切片的狀態。
  • 這些子請求能夠單獨尋址,例如取消和重置節流閥。
  • slices的重置節流閥請求將按相應的從新計算未完成的子請求。
  • slices的取消請求將取消每一個子請求。
  • 因爲slices的性質,每一個子請求將不會得到徹底均勻的文檔部分。全部文件都將被處理,但有些片可能比其餘片大。預期更大的切片能夠有更均勻的分佈。
  • 帶有slices請求的request_per_secondsize的參數相應的分配給每一個子請求。結合上述關於分佈的不均勻性,您應該得出結論,使用切片大小可能不會致使正確的大小文檔爲_reindex
  • 每一個子請求都會得到源索引的略有不一樣的快照,儘管這些都是大體相同的時間。

9. 挑選切片數量

在這一點上,咱們圍繞要使用的slices數量提供了一些建議(好比手動並行化時,切片API中的max參數):

  • 不要使用大的數字,500就能形成至關大的CPU抖動。
  • 從查詢性能的角度來看,在源索引中使用分片數量的一些倍數更爲有效。
  • 在源索引中使用徹底相同的分片是從查詢性能的角度來看效率最高的。
  • 索引性能應在可用資源之間以slices數量線性擴展。
  • 索引或查詢性能是否支配該流程取決於許多因素,如正在重建索引的文檔和進行reindexing的集羣。

10. 索引的平常重建

您可使用_reindexPainless組合來從新每日編制索引,以將新模板應用於現有文檔。 假設您有由如下文件組成的索引:

PUT metricbeat-2016.05.30/beat/1?refresh
{"system.cpu.idle.pct": 0.908}

PUT metricbeat-2016.05.31/beat/1?refresh
{"system.cpu.idle.pct": 0.105}

metricbeat-*索引的新模板已經加載到Elaticsearch中,但它僅適用於新建立的索引。Painless可用於從新索引現有文檔並應用新模板。

下面的腳本從索引名稱中提取日期,並建立一個附帶有-1的新索引。來自metricbeat-2016.05.31的全部數據將從新索引到metricbeat-2016.05.31-1

POST _reindex
{
  "source": {
    "index": "metricbeat-*"
  },
  "dest": {
    "index": "metricbeat"
  },
  "script": {
    "lang": "painless",
    "inline": "ctx._index = 'metricbeat-' + (ctx._index.substring('metricbeat-'.length(), ctx._index.length())) + '-1'"
  }
}

來自上一個度量索引的全部文檔如今能夠在*-1索引中找到。

GET metricbeat-2016.05.30-1/beat/1
GET metricbeat-2016.05.31-1/beat/1

之前的方法也能夠與更改字段的名稱一塊兒使用,以便將現有數據加載到新索引中,但若是須要,還能夠重命名字段。

11. 提取索引的隨機子集

Reindex可用於提取用於測試的索引的隨機子集:

POST _reindex
{
  "size": 10,
  "source": {
    "index": "twitter",
    "query": {
      "function_score" : {
        "query" : { "match_all": {} },
        "random_score" : {}
      }
    },
    "sort": "_score"    //①
  },
  "dest": {
    "index": "random_twitter"
  }
}

① Reindex默認按_doc排序,因此random_score不會有任何效果,除非您將排序重寫爲_score

相關文章
相關標籤/搜索