2.6 ReIndex and Update

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有以下可选参数:

  1. noop:忽略此操作,该文档不会被索引到目标索引中。
  2. delete:从目标索引中删除该文档。

通过执行脚本,可以对文档的以下元数据进行操作:

  1. _index
  2. _type
  3. _id
  4. _routing
  5. _version

如果将_version设置为null,那么在索引该文档的时候将会忽视掉版本控制相关的设置,当目标索引中不存在该文档的时候就会创建该文档(version为1),否则直接覆写该文档(version自增1)。

1.8 路由

默认情况下,如果_reindex带有routing的文档,则routing将被保留,除非脚本更改了该routing。通过在dest请求上设置routing参数可以改变使用routing的策略:

  1. keep:保留文档上的routing,这是默认值。
  2. discard:不保留文档的routing
  3. =:将所有文档的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参数

  1. refresh:发送refresh参数将导致所有reindex的目标索引发生refresh操作。
  2. wait_for_completiong
  3. wait_for_active_shards
  4. requests_per_second
  5. timeout
  6. 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

你可能感兴趣的:(2.6 ReIndex and Update)