web-dev-qa-db-ja.com

elasticsearchのインデックスを再作成するよりスマートな方法はありますか?

私たちの検索は物事を進めるときに流動的な状態にあるので、私は尋ねますが、インデックスに変更を加えるたびに(トークナイザーやフィルター、シャード/レプリカの数を変更する)、インデックス全体を吹き飛ばさなければなりませんすべてのRailsモデルをElasticsearchに再インデックスします...これは、すべてのレコードのインデックスを再作成するためにダウンタイムを考慮する必要があることを意味します。

これを行うための賢い方法はありますか?

43
concept47

@karmiが正しいと思います。ただし、もう少し簡単に説明しましょう。運用スキーマをいくつかの新しいプロパティまたは分析設定で時々アップグレードする必要がありました。最近、以下に説明するシナリオを使用して、ライブで一定の負荷のゼロダウンタイムインデックス移行を開始しました。リモートで実行できます。

手順は次のとおりです。

仮定:

  • インデックスreal1とエイリアスreal_writereal_readを指し、
  • クライアントはreal_writeにのみ書き込み、real_readからのみ読み取ります
  • 文書の_sourceプロパティが利用可能です。

1.新しいインデックス

選択した新しいマッピングと設定でreal2インデックスを作成します。

2.ライターエイリアススイッチ

次の一括クエリスイッチ書き込みエイリアスを使用します。

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

これはアトミック操作です。この時点から、real2にはすべてのノードで新しいクライアントのデータが入力されます。読者はまだ_real1経由で古い_real_readを使用しています。これは最終的な一貫性です。

3.古いデータの移行

データはreal1からreal2に移行する必要がありますが、real2の新しいドキュメントを古いエントリで上書きすることはできません。移行スクリプトは、bulk操作でcreate AP​​Iを使用する必要があります(indexまたはupdateではありません)。シンプルなRuby script es-reindex を使用します。これはNice E.T.A.ステータスを持ちます:

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

UPDATE 2017スクリプトを使用する代わりに、新しい Reindex API を検討することもできます。競合レポートなどの興味深い機能がたくさんあります。

4.リーダーエイリアススイッチ

現在、real2は最新であり、クライアントはそれに書き込みを行っていますが、real1からは読み取り中です。リーダーエイリアスを更新しましょう。

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

5.古いインデックスのバックアップと削除

書き込みと読み取りはreal2に進みます。 ESクラスタからreal1インデックスをバックアップおよび削除できます。

できた!

70
gertas

はい、ダウンタイムなしでデータのインデックスを再作成するよりスマートな方法があります。

まず、決して「最終」インデックス名を実際のインデックス名として使用しないでください。したがって、インデックスに「articles」という名前を付けたい場合は、その名前を物理インデックスとして使用せずに、「articles-2012-12-12」や「articles-A」、「articles」などのインデックスを作成します-1 "など.

次に、そのインデックスを指すエイリアス「alias」を作成します。アプリケーションはこのエイリアスを使用するため、インデックス名を手動で変更したり、アプリケーションを再起動したりする必要はありません。

第三に、データのインデックスを再作成する必要がある場合、またはインデックスを再作成する必要がある場合は、異なるインデックスに再インデックスします。たとえば、「articles-B」と指定します。

完了したら、エイリアスを新しいインデックスにポイントします。この方法では、ダウンタイムを最小限に抑えるだけでなく(安全なスナップショットもあります)、安全なスナップショットも得られます。インデックスを新しいインデックスに何らかの形で混乱させた場合、解決するまで古いインデックスに切り替えることができます。問題。

30
karmi

最近ダウンタイムなしで再インデックスを処理した方法に関するブログ投稿を書きました。そうするために必要なすべてのささいなことを理解するのに時間がかかります。お役に立てれば!

https://summera.github.io/infrastructure/2016/07/04/reindexing-elasticsearch.html

要約する:

ステップ1:新しいインデックスを準備する

新しいマッピングで新しいインデックスを作成します。これは、Elasticsearchの同じインスタンスでも、新しいインスタンスでも可能です。

ステップ2:インデックスを最新の状態に保つ

インデックスの再作成中は、新しいインデックスと古いインデックスの両方を最新の状態に保ちたいと思います。書き込み操作の場合、これは、新しいインデックスと古いインデックスの両方でバックグラウンドワーカーに書き込み操作を送信することで実行できます。

レコードの削除と新しいインデックスへのインデックスの再作成の間には競合状態があるため、削除は少し複雑です。そのため、インデックスの再作成中に削除する必要があるレコードを追跡し、完了したらこれらを処理する必要があります。多数の削除を実行していない場合、別の方法は、インデックスの再作成中に削除の可能性を排除することです。

ステップ3:インデックスの再作成を実行する

データの読み取りには スクロール検索 を使用し、挿入には bulk API を使用します。ステップ2の後、バックグラウンドで新しいインデックスおよび更新されたドキュメントを新しいインデックスに書き込むため、バルクAPIリクエストで新しいインデックス内の既存のドキュメントを更新しないようにする必要があります。

これは、バルクAPIリクエストに必要な操作がインデックスではなく作成であることを意味します。 documentation :「同じインデックスとタイプのドキュメントが既に存在する場合、作成は失敗しますが、インデックスは必要に応じてドキュメントを追加または置換します」ここでの主なポイントは、スクロールされた検索スナップショットの古いデータが新しいインデックスの新しいデータを上書きしないようにすることです。

このプロセスを支援する素晴らしいスクリプトがgithubにあります: es-reindex

ステップ4:スイッチオーバー

インデックスの再作成が完了したら、検索を新しいインデックスに切り替えます。削除をオンに戻すか、新しいインデックスのキューに登録された削除ジョブを処理します。新しいインデックスの検索が最初は少し遅いことに気付くかもしれません。これは、ElasticsearchとJVMのウォームアップに時間が必要だからです。

必要なコード変更を実行して、アプリケーションが新しいインデックスの検索を開始するようにします。問題が発生してロールバックする必要がある場合に備えて、古いインデックスへの書き込みを続けることができます。これが不要だと思う場合は、書き込みを停止できます。

ステップ5:クリーンアップ

この時点で、新しいインデックスに完全に移行する必要があります。すべてが順調に進んでいる場合は、次のような必要なクリーンアップを実行します。

  • 古いインデックスホストが新しいインデックスホストと異なる場合は削除します
  • 古いインデックスに関連するシリアル化コードを削除します
3
Ari

別のインデックスを作成し、そのインデックスにすべてのデータのインデックスを再作成し、インデックスの再作成が完了したら切り替えを行うこともできますか?

2
Emil Hajric