Is there a smarter way to reindex elasticsearch?

downtime, elasticsearch

Solution

I think @karmi makes it right. However let me explain it a bit simpler. I needed to occasionally upgrade production schema with some new properties or analysis settings. I recently started to use the scenario described below to do live, constant load, zero-downtime index migrations. You can do that remotely.

Here are steps:

Assumptions:

- You have index `real1` and aliases `real_write`, `real_read` pointing to it,

- the client writes only to `real_write` and reads only from `real_read` ,

- `_source` property of document is available.

1. New index

Create `real2` index with new mapping and settings of your choice.

2. Writer alias switch

Using following bulk query switch write alias.

curl -XPOST 'http://esserver:9200/_aliases' -d '
{
    "actions" : [
        { "remove" : { "index" : "real1", "alias" : "real_write" } },
        { "add" : { "index" : "real2", "alias" : "real_write" } }
    ]
}'

This is atomic operation. From this time `real2` is populated with new client's data on all nodes. Readers still use old `real1` via `real_read`. This is eventual consistency.

3. Old data migration

Data must be migrated from `real1` to `real2`, however new documents in `real2` can't be overwritten with old entries. Migrating script should use `bulk` API with `create` operation (not `index` or `update`). I use simple Ruby script es-reindex which has nice E.T.A. status:

$ ruby es-reindex.rb http://esserver:9200/real1 http://esserver:9200/real2

UPDATE 2017 You may consider new Reindex API instead of using the script. It has lot of interesting features like conflicts reporting etc.

4. Reader alias switch

Now `real2` is up to date and clients are writing to it, however they are still reading from `real1`. Let's update reader alias:

curl -XPOST 'http://esserver:9200/_aliases' -d '
{
    "actions" : [
        { "remove" : { "index" : "real1", "alias" : "real_read" } },
        { "add" : { "index" : "real2", "alias" : "real_read" } }
    ]
}'

5. Backup and delete old index

Writes and reads go to `real2`. You can backup and delete `real1` index from ES cluster.

Done!

Problem

I ask because our search is in a state of flux as we work things out, but each time we make a change to the index (change tokenizer or filter, or number of shards/replicas), we have to blow away the entire index and re-index all our Rails models back into Elasticsearch ... this means we have to factor in downtime to re-index all our records. Is there a smarter way to do this that I'm not aware of?

Original source