2018年10月23日 エンジニアリング

ディスク容量の節約:Elasticsearchのインデックスソートに関するあまり知られていないメリット

著者 Shane Connelly

Elasticsearch 6.0では、インデックスソートという新機能をリリースしました。詳細についてはリンク先のブログをお読みいただければと思いますが、要約すると、ドキュメントをインデックスする際に、キーまたはキーのセットを使用して、指定した順序に並び変えることができます。この機能によって、今までに述べてきたような新しいメリットが実現します。

  • インデックスソートに使用したのと同じキーで並べ替えて結果を返すようにElasticsearchに指示すると、クエリ時の結果の並べ替えが不要になります。すでにソートされているからです。
  • 総ヒット件数が不要でソートキーで並べ替える場合、Elasticsearchでは、リクエストを満たすヒット件数に達した場合にそのクエリは終了します。これにより、クエリパフォーマンスが驚くほど向上します。
  • 異なるフィールドに関してANDを使用してクエリを実行する場合、それらのフィールドはインデックスソートによってグループ化されるため、Elasticsearchは一致しない多数のドキュメントブロックをスキップすることが可能になり、検索も速くなります。

つまり、特に複数のユーザーがドキュメントの検索や並べ替えにいくつかの共通の方法を使用している場合には、インデックスソートによってより迅速に検索できるようになります。 そして、実はこのインデックスソートに関してあまり語られていないメリットがあります。それは、インデックスに使用されているディスク容量の削減も可能になることです。その理由と仕組みについて説明しましょう。

注意:インデックスソートは誰にでも役立つものではない

この機能の仕組みについて話す前に再度確認しておきたいのは、インデックスソートは誰にでも役立つものではないということです。ソートはインデックスを作る際に実行されます。ソートは負荷の高いオペレーションであるため、インデックスする速度が主な懸念事項の場合は、実行前に注意が必要です。書き込みのパフォーマンスが40~50%も低下します。そのためインデックス作成のスループットが主な懸念事項の場合、たとえば大量のロギング、メトリック、セキュリティ分析などのユースケースでは往々にしてそれが問題となりますが、インデックスソートは適していません。 インデックス数が少ない場合やクエリ速度が最も重要なユースケースの場合、またはインデックス付けのオフピーク時に定期的に再インデックスプロセスが実行される場合には便利です。

ソートオーダーの検討:一例

Elasticsearchインスタンス使用して製品検索を行うとしましょう。インデックスを作成する際に、以下のようなドキュメントのセットを持っていると仮定します(見やすくするために表の形式にしています)。

製品ID 製品カテゴリー 製品カラー 価格
206f467b-8cfe シューズ レッド $97.00
4f89fbec-acc3 ジャケット ブラック $120.50
47771396-dfe3 ジャケット グレー $170.10
c6c8fbdf-651b 帽子 イエロー $15.00
dc18c426-0eb3 シューズ レッド $107.20
ee304259-df57 ジャケット ブラック $88.00
9332c0ac-e55e シューズ ブラック $49.00
30e96765-52a1 帽子 ブルー $11.00
811cc8ca-d6bb ジャケット ブルー $92.99

ここで、インデックスソートを有効にしたいとします。何でソートしますか?製品カテゴリー、製品カラー、および/または価格といったいくつかのオプションがあります。ユーザー検索がほぼ常に価格のみでソートされており、カテゴリーやカラーのフィルターがない場合には、ソートキーとして価格で並び変えることが最も有用です。しかし、おそらくユーザーは最安値の商品を見つける前に、少なくともカテゴリーは選択しているでしょう。また、カラーの好みもあるはずです。 カテゴリーの昇順、カラーの昇順、そして価格の昇順でソートしてみましょう。

"sort.field" : ["product_category", "product_color", "price"], "sort.order" : ["asc", "asc", "asc"]

ソートされたインデックスは次のようになります。

製品ID 製品カテゴリー 製品カラー 価格
30e96765-52a1 帽子 ブルー $11.00
c6c8fbdf-651b 帽子 イエロー $15.00
ee304259-df57 ジャケット ブラック $88.00
4f89fbec-acc3 ジャケット ブラック $120.50
811cc8ca-d6bb ジャケット ブルー $92.99
47771396-dfe3 ジャケット グレー $170.10
9332c0ac-e55e シューズ ブラック $49.00
206f467b-8cfe シューズ レッド $97.00
dc18c426-0eb3 シューズ レッド $107.20

興味深いことが見えてきました。例を示しながら説明します。

  • 価格でソートして最安値上位2つのシューズを示すように指示し、すべてのシューズの総ヒット数が不要な場合、ElasticsearchはShoesのブロックを見つける必要があり、その他のすべてのカテゴリーをスキップするので効率的です。そして、結果となる2つが見つかると、残りのインデックスに対する処理を停止し、結果を返します。このように機能させるためには、一致するフィルターがあったとしても、ソートオーダーのすべての要素をインデックスに含める必要があります。
  • Elasticsearchでproduct_category:Jackets AND product_color:Blackと指定すると、HatsのすべてとShoesのすべてがスキップされ、Jacketsの中で「Black」のものが検索され、それが見つかると、他のカラーのすべてがスキップされるので効率的です。
  • Elasticsearchは、見えないところでかなりの圧縮を行っているわけです。この圧縮は繰り返し値がある場合に機能します。最も効率的に機能するのは、繰り返し値がインデックス内でお互いに近い位置にある場合です。「Jackets」のすべてまたは「Color」のすべてがお互いに側にある場合、ディスクに効率的に圧縮されます。これによってディスクスペースが少なくて済むとともに、オペレーティングシステムのファイルシステムキャッシュがより効率化され、動作がさらに迅速になります。

一般的に、ソートオーダーはカーディナリティの高い順番にすることがベストプラクティスです。1行内のできるだけ多くの繰り返し値を利用できるという利点があるからです。

節約できるディスク容量

インデックスソートを有効化することで、どれくらいのディスク容量を節約できるでしょうか。 それは他のさまざまなことと同様、「場合による」ことになります。 その主な要素の1つは、ソートするフィールドのカーディナリティです。これによるディスク容量の節約はかなりの量になります。 先週末、私は個人的なプロジェクトに使用しているIoT/ホームオートメーションのデータの一部を、古いマシンから新しいマシンに移動させることにしました。そのデータの移行にはスナップショット/復元のような迅速な方法がありますが、再インデックスする時間の余裕があったため、インデックスソートによってどれくらいディスク容量が節約できるかを見てみたいと思いました。そこでまず、ソートされていないインデックスとしてリモートに再インデックスを実行しました。

status    index           pri    docs.count    docs.deleted    pri.store.size 
open      devices-2017    1      33310674      0               4.2gb

デバイスは30台より少し多いぐらいで、各デバイスは30秒ごとにステータスを送信、全体のインデックス登録の速度は1秒あたり1ドキュメントです。私はインデックス登録に関して制約を受けることはありません。インデックス登録の速度またはデバイス数を大きく増加させる必要があれば、影響を受けるでしょう。つまり、インデックスソートの利点が得られるケースに該当するようです。 データはハードウェア ID、ハードウェア名、時間、さまざまなセンサー値(温度、特定の時間におけるデバイスのオン/オフ、その他のセンサーレベルなど)で構成されています。インデックスをデバイスIDでソートし、そして時間でソートしたところ、あるデバイスではかなり高い確率で、ほぼ同じ時間に同様または同じ値が見られるらしいことが分かりました。つまり、さらに効率的に圧縮できる可能性があることになります。例えば、スイッチが7:00:00に「オン」の状態になる場合、そのオンになる時間が7:00:30、7:01:00、および少なくとも数分後になる可能性は非常に高く、この場合だと効率的に圧縮できることになります。 ソートされたインデックスの統計によると…

status    index           pri    docs.count     docs.deleted    pri.store.size
open      devices-2017    1      3310674        0               2.5gb

ディスク容量を約40%節約できました!

再び注意

同じデータを40%も少ないディスク容量で格納できることは、誰にとってもありがたいことでしょう。ここで、皆さんにもう一度注意を喚起しなければなりません。要約すると次の2つの内容になります。

  • 節約量は異なります。私は別のデータセットにインデックスソートを使用しましたが、そちらは20%の節約でした。どのフィールドでソートするか、慎重に考えてください。
  • インデックスする速度が遅くなります。インデックスする速度が非常に重要な場合、例えば大量のロギングを実行している、またはメトリックのユースケースなどの場合、短時間でインデックスするにはドキュメント数に影響を受けるため、インデックスソートを実行するのに適していない可能性があります。

インデックスする速度よりもディスク容量のほうがはるかに重要な場合、またはインデックスの容量が少なく、インデックスする速度に制限を受けない場合は、インデックスソートから利点を得られるかどうか確認してみる価値はあるでしょう。