Reindex API
1. Reindex 基本概念
Reindex API最重要的作用是将文档从一个索引复制到另一个索引中。例如:
POST localhost:9200/_reindex
{
"source": { //源索引
"index": "twitter"
},
"dest": { //目标索引
"index": "new_twitter"
}
}
上述请求表示将twitter索引中的内容拷贝到new_twitter索引下。
返回结果如下:
{
"took": 13058,
"timed_out": false,
"total": 20872,
"updated": 0,
"created": 20872,
"deleted": 0,
"batches": 209,
"version_conflicts": 0,
"noops": 0,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": -1,
"throttled_until_millis": 0,
"failures": []
}
Reindex只会拷贝索引中的文档,但是不会拷贝索引的其他信息,比如mapping,setting等,因此在执行Reindex API前应该要将目标索引的mapping,setting等都创建好。
1.1 版本控制以及version_type
和Update By Query 以及 Delete By Query相同,在执行Reindex请求前它会创建一份源文档的快照,但是因为Reindex操作的目标索引不同于源文档所在索引,因此发生版本冲突的可能性很低。
在不指定version_type或者将version_type指定为internal(内部)的情况下,对于目标索引不存在的文档,会使用源索引中的文档进行创建(不保留源文档的版本号),而对于目标索引和源索引中type和id相同的文档,会使用源索引中的文档进行更新,目标索引中的文档版本号自增1。再次执行Reinde 请求:
POST localhost:9200/_reindex
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter",
"version_type": "internal" //不指定version_type和指定version_type为internal的情况相同
}
}
结果为:
{
"took": 3701,
"timed_out": false,
"total": 20872,
"updated": 20872,
"created": 0,
"deleted": 0,
"batches": 21,
"version_conflicts": 0,
"noops": 0,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": -1,
"throttled_until_millis": 0,
"failures": []
}
如果将version_type指定为external,那么对于目标索引中不存在的文档会进行创建,同时保留源文档的版本号,对于目标索引中存在的文档,如果源文档中的版本号比目标索引中的高就进行更新,否则发生版本冲突。再次执行请求:
{
"source":{
"index":"twitter"
},
"dest":{
"index":"new_twitter",
"version_type":"external"
}
}
结果为:
{
"took": 212,
"timed_out": false,
"total": 20872,
"updated": 0,
"created": 0,
"deleted": 0,
"batches": 1,
"version_conflicts": 1000,
"noops": 0,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": -1,
"throttled_until_millis": 0,
"failures": [
{
"index": "new_twitter",
"type": "_doc",
"id": "9XLT52MB6Q8m_suv-5fg",
"cause": {
"type": "version_conflict_engine_exception",
"reason": "[_doc][9XLT52MB6Q8m_suv-5fg]: version conflict, current version [2] is higher or equal to the one provided [1]",
"index_uuid": "A5okOutnSOGPnpy-2d-jpA",
"shard": "0",
"index": "new_twitter"
},
"status": 409
},
......
]
}
在默认情况下,一旦发生版本冲突,那么整个Reindex操作就会中断,如果希望在发生版本冲突的时候不中断操作,conflicts,proceed,例如:
POST localhost:9200/_reindex
{
"conflicts": "proceed",
"source":{
"index":"twitter"
},
"dest":{
"index":"new_twitter",
"version_type":"external"
}
}
结果为:
{
"took": 2691,
"timed_out": false,
"total": 20872,
"updated": 0,
"created": 0,
"deleted": 0,
"batches": 21,
"version_conflicts": 20872,
"noops": 0,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": -1,
"throttled_until_millis": 0,
"failures": []
}
1.2 put if absent
如果将op_type
设为create,那么当目标索引中文档不存在的时候会创建文档,如果文档存在(type和id相同)则造成版本冲突。为了实现put-if-absent的功能,同时避免版本冲突造成操作中断,可以将conflicts设为proceed:
{
"conflicts": "proceed",
"source":{
"index":"twitter"
},
"dest":{
"index":"new_twitter",
"op_type": "create"
}
}
1.3 指定Reindex操作范围
通过在source中指定type或者查询条件可以指定Reindex的范围:
POST localhost:9200/_reindex
{
"source": {
"index": "twitter",
"type": "_doc",
"query": {
"term": {
"user": "kimchy"
}
}
},
"dest": {
"index": "new_twitter"
}
}
上述请求表示只有twitter中type为_doc
,且user等于kimchy的文档需要被复制到new_twitter中。
1.4 合并多个index
index可以接收一个List集合:
{
"conflicts": "proceed",
"source":{
"index":["twitter","blog"]
},
"dest":{
"index":"message"
}
}
上述请求将twitter和blog中的文档到复制到了message索引中。
从Elasticsearch 6 以后,一个index中只允许存在一个type,这就意味则source中的index列表下所有index的type必须相同,否则会报错。报错信息如下:
{
"took": 86,
"timed_out": false,
"total": 2,
"updated": 1,
"created": 0,
"deleted": 0,
"batches": 1,
"version_conflicts": 0,
"noops": 0,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": -1,
"throttled_until_millis": 0,
"failures": [
{
"index": "new_twitter_blog",
"type": "_doc",
"id": "H9TmBmQBgT0CU6BFaEVw",
"cause": {
"type": "illegal_argument_exception",
"reason": "Rejecting mapping update to [new_twitter_blog] as the final mapping would have more than 1 type: [post, _doc]"
},
"status": 400
}
]
}
1.5 限制操作的数量
通过指定size参数,可以限制对多少个文档执行Reindex 操作:
POST localhost:9200/_reindex
{
"size": 1,
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter"
}
}
再通过指定顺序,就可以做到对某种顺序下的前面一定数量的文档进行操作:
POST localhost:9200/_reindex
{
"size": 10000,
"source": {
"index": "twitter",
"sort": { "date": "desc" }
},
"dest": {
"index": "new_twitter"
}
}
上述请求表示中对最近的10000条数据进行Reindex操作。
1.6 字段过滤
通过_source
参数可以实现字段过滤,只有指定的字段会复制:
POST localhost:9200/_reindex
{
"source": {
"index": "twitter",
"_source": ["user", "_doc"]
},
"dest": {
"index": "new_twitter"
}
}
上述请求表示只有user和_doc
字段会被复制到新的索引中。
1.7 执行脚本
和Update,Update By Query一样,Reindex也支持使用脚本。但不同的是,除了对文档的内容以及操作类型(ctx.op)进行修改外,Reindex还允许对文档的元数据(_index
,_type
,_id
,_version
,_routing
)进行修改,例如:
POST localhost:9200/_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"
}
}
上述代码表示如果文档的foo字段等于bar,那么就将该字段移除,同时使得文档的版本号自增1.
对于ctx.op有以下可选参数:
- noop:忽略此操作,该文档不会被索引到目标索引中。
- delete:从目标索引中删除该文档。
通过执行脚本,可以对文档的以下元数据进行操作:
- _index
- _type
- _id
- _routing
- _version
如果将_version
设置为null,那么在索引该文档的时候将会忽视掉版本控制相关的设置,当目标索引中不存在该文档的时候就会创建该文档(version为1),否则直接覆写该文档(version自增1)。
1.8 路由
默认情况下,如果_reindex
带有routing的文档,则routing将被保留,除非脚本更改了该routing。通过在dest请求上设置routing参数可以改变使用routing的策略:
- keep:保留文档上的routing,这是默认值。
- discard:不保留文档的routing
-
=
:将所有文档的routing设置为指定的值。
例如:
POST localhost:9200/_reindex
{
"source": {
"index": "source",
"query": {
"match": {
"company": "cat"
}
}
},
"dest": {
"index": "dest",
"routing": "=cat"
}
}
1.9 批处理大小
Reindex也是基于Scroll实现分批操作的,我们可以指定每个批次的大小:
POST localhost:9200/_reindex
{
"source": {
"index": "source",
"size": 100
},
"dest": {
"index": "dest"
}
}
1.10 Ingest Node特性
和Update By Query 一样, Reindex也支持Ingest Node特性,或者说是通过管道对文件进行预处理。
例如:
POST localhost:9200/_reindex
{
"source": {
"index": "source"
},
"dest": {
"index": "dest",
"pipeline": "some_ingest_pipeline"
}
}
2. 从远程服务器上获取数据重建索引
Reindex支持从远程的Elasticserach集群上获取数据,并在本地重建索引,例如:
POST localhost:9200/_reindex
{
"source": {
"remote": {
"host": "http://otherhost:9200",
"username": "user",
"password": "pass"
},
"index": "source",
"query": {
"match": {
"test": "data"
}
}
},
"dest": {
"index": "dest"
}
}
host参数必须包含schema,host和port。username和password是可选的。
远程服务器上必须包含一组允许远程访问的主机白名单。具体来说是在config/elasticsearch.yml文件上以reindex.remote.whitelist
为key,以host:port
为value进行配置。例如:
reindex.remote.whitelist: "otherhost:9200, another:9200, 127.0.10.*:9200, localhost:*
在配置中不需要协议。
这个特性适用于你可能找到的任何Elasticsearch版本的远程集群。这应该允许您从任何版本的Elasticsearch升级到新的版本,方法是从旧版本的集群中使用Reindex重建索引。
从远程服务器Reindex会使用到默认大小为100MB的堆缓冲区。如果远程索引包含非常大的文档,则需要使用较小的批量。下面的例子将批量大小设置为10:
POST localhost:9200/_reindex
{
"source": {
"remote": {
"host": "http://otherhost:9200"
},
"index": "source",
"size": 10,
"query": {
"match": {
"test": "data"
}
}
},
"dest": {
"index": "dest"
}
}
在通过远程服务器的数据重建索引的过程中,可能还需要设置socket读取的超时时间,以及建立连接的超时时间,他们默认都是30S,例如:
POST localhost:/_reindex
{
"source": {
"remote": {
"host": "http://otherhost:9200",
"socket_timeout": "1m",
"connect_timeout": "10s"
},
"index": "source",
"query": {
"match": {
"test": "data"
}
}
},
"dest": {
"index": "dest"
}
}
3. URL参数
- refresh:发送refresh参数将导致所有reindex的目标索引发生refresh操作。
- wait_for_completiong
- wait_for_active_shards
- requests_per_second
- timeout
- scroll
4. 响应
{
"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": [ ]
}
4. Task API
如果将wait_for_completiong设置为false,那么Reindex操作将会异步执行,并返回一个task id,通过这个id就可以对Reindex进行控制。
4.1 查询所有执行中的Reindex 操作
请求如下:
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
},
"description" : ""
}
}
}
}
}
4.2 通过id查看任务
GET /_tasks/taskId
4.3 通过Task Id取消任务
POST _tasks/task_id/_cancel
4.4 调整限速
POST _reindex/task_id:1/_rethrottle?requests_per_second=-1
5. 改变字段名
通过脚本可以改变文档中的字段名。
例如,索引文档的请求如下:
POST test/_doc/1?refresh
{
"text": "words words",
"flag": "foo"
}
现在通过脚本将flag字段重命名为tag:
POST localhost:9200/_reindex
{
"source": {
"index": "test"
},
"dest": {
"index": "test2"
},
"script": {
"source": "ctx._source.tag = ctx._source.remove(\"flag\")"
}
}
remove操作的返回值就是字段的值,将字段值赋给tag,这样就实现了"重命名"。
4. Slice
5. 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}
metricbeat-*
索引的新模板已经加载到Elasticsearch中,但它仅适用于新创建的索引。通过重建索引,可以应用新的模板。
以下脚本从索引名称中提取日期,并创建一个名称中附加-1
的新索引。例如所有来自metricbeat-2016.05.31
的数据将重新编入metricbeat-2016.05.31-1
索引中。
例如:
POST localhost:9200/_reindex
{
"source": {
"index": "metricbeat-*"
},
"dest": {
"index": "metricbeat"
},
"script": {
"lang": "painless",
"source": "ctx._index = 'metricbeat-' + (ctx._index.substring('metricbeat-'.length(), ctx._index.length())) + '-1'"
}
6. 抽取一个随机的子集
_reindex
可从测试用的索引中提取随机子集:
POST localhost:9200/_reindex
{
"size": 10,
"source": {
"index": "twitter",
"query": {
"function_score" : {
"query" : { "match_all": {} },
"random_score" : {}
}
},
"sort": "_score"
},
"dest": {
"index": "random_twitter"
}
}
_reindex
默认使用_doc
进行排序,因此random_score不会产生任何效果,除非您将sort重写为_score
。
参考来源
- http://moranshouwang.com/articles/2018/07/14/1531561505058.html