Elasticsearchクエリが非常に高速なのはなぜですか?何を見ていますか?お願いだから!

この間、私は製品の検索機能を維持していましたが、管理コンソールでElasticsearchの効率的なクエリ効率を見るたびに、彼がどのようにそれを行っているのか興味がありました。

Elasticsearchクエリが非常に高速なのはなぜですか?

これは、MySQLをローカルで使用してプライマリキーを介してクエリを実行するよりもさらに高速です。

Elasticsearchクエリが非常に高速なのはなぜですか?

Elasticsearchクエリが非常に高速なのはなぜですか?

このために私は関連情報を検索しました:

Elasticsearchクエリが非常に高速なのはなぜですか?

この種の質問に対する答えはインターネット上にたくさんあります。おおよその意味は次のとおりです。ESはLuceneをベースにしたフルテキスト検索エンジンです。データをセグメント化してインデックスを保存します。大量のインデックスデータを管理するのに適しています。MySQLと比較して、データの更新や関連付けを頻繁に行うのは得意ではありません。お問い合わせください。

あまり徹底的ではなく、分析に関連する原則もありませんが、インデックスが繰り返し言及されているので、インデックスの観点から両者の違いを比較します。

MySQLインデックス

最初にMySQLと言えば、インデックスという用語は誰もが知っている必要があります。これは通常、一部のクエリシナリオに存在します。これは、時間のスペースの一般的なケースです。以下では、例としてInnoDBエンジンを使用しています。

共通のデータ構造

MySQLインデックスを自分で設計すると仮定すると、オプションは何ですか?

①ハッシュテーブル

最初に考えなければならないのは、クエリと書き込みのための非常に一般的で効率的なデータ構造であるハッシュテーブルです。Javaに対応するのはHashMapです。

Elasticsearchクエリが非常に高速なのはなぜですか?

このデータ構造をあまり導入する必要はありません。書き込み効率は非常にO(1)です。たとえば、id = 3のデータをクエリする場合は、3をハッシュして、この配列で対応するものを見つける必要があります。場所は大丈夫です。

ただし、1≤id≤6などの間隔データを照会する場合、ハッシュテーブルは十分に満たすことができません。無秩序であるため、すべてのデータをトラバースして、どのデータがこの間隔に属するかを知る必要があります。

②注文配列

Elasticsearchクエリが非常に高速なのはなぜですか?

順序付けされた配列のクエリ効率も非常に高く、id = 4のデータをクエリする場合は、バイナリ検索によってデータO(logn)を効率的に見つけるだけで済みます。

同時に、データも順序付けされているため、当然、間隔クエリをサポートできます。順序付けられた配列はインデックス作成に適しているようです。

当然のことながら、別の大きな問題があります。id= 2.5のデータを挿入すると、後続のすべてのデータを同時に1ビット移動する必要があり、この書き込み効率は非常に低くなります。

③バランスの取れたバイナリツリー

順序付けされた配列の書き込み効率は高くないので、書き込み効率を見てみましょう。バイナリツリーは簡単に考えられます。

ここでは、例としてバランスの取れたバイナリツリーを取り上げます。

Elasticsearchクエリが非常に高速なのはなぜですか?

バランスの取れたバイナリツリーの特性により、左側のノードは親ノードよりも小さく、右側のノードは親ノードよりも大きくなります。

したがって、id = 11のデータをクエリし、最終的にデータを見つけるために10→12→11をクエリするだけでよいと仮定します。時間の複雑さはO(logn)であり、データを書き込むときも同じです。

ただし、それでも間隔範囲検索は十分にサポートされていません。5≤id≤20のデータをクエリする場合、最初に10ノードの左側のサブツリーをクエリし、次に10ノードの右側のサブツリーをクエリして最後にすべてのデータをクエリする必要があります。このようなクエリの効率は高くありません。

④ジャンプテーブル

ジャンプテーブルは、上記のハッシュテーブル、順序付き配列、バイナリツリーほど一般的ではない場合がありますが、実際には、Redisで設定された並べ替えはジャンプテーブルによって実装されます。ここでは、次のジャンプテーブルで実装されるデータ構造の利点を簡単に紹介します。

順序付きリンクリストのクエリでさえ効率的ではないことは誰もが知っています。バイナリ検索に配列の添え字を使用できないため、時間の複雑さはo(n)です。

ただし、次の図に示すように、リンクリストを巧妙に最適化して、偽装したバイナリ検索を実現することもできます。

Elasticsearchクエリが非常に高速なのはなぜですか?

ボトムデータのプライマリインデックスとセカンダリインデックスを抽出できます。データ量に応じて、Nレベルのインデックスを抽出できます。クエリを実行するときは、ここでインデックスを使用して、偽装したバイナリ検索を実現できます。

id = 13のデータを照会する場合、データを見つけるために4つのノード1→7→10→13をトラバースするだけで済みます。数値が大きいほど、効率の向上が明らかになります。

同時に、インターバルクエリもサポートされています。現在の単一ノードのクエリと同様に、開始ノードにクエリを実行してから、ターゲットノードまで順番にトラバース(リンクリストの順序)して、データの全範囲をクエリする必要があります。

同時に、実際のデータをインデックスに保存せず、ポインタのみを保存するため、最下層のリンクリストが占めるスペースはごくわずかです。

バランスの取れたバイナリツリーの最適化

しかし実際には、MySQLのInnoDBはスキップテーブルを使用せず、B +ツリーと呼ばれるデータ構造を使用します。

このデータ構造はバイナリツリーのようなものではなく、実際のプロジェクトの需要シナリオに応じて基本データ構造から発展したものであるため、大学の先生は基本データ構造とよく言います。

たとえば、ここでのB +ツリーは、バランスの取れたバイナリツリーから進化したと見なすことができます。先ほど、バイナリツリーの間隔クエリの効率は高くなく、この点に合わせて最適化できることを説明しました。

Elasticsearchクエリが非常に高速なのはなぜですか?

元のバイナリツリーに基づいて最適化した後:すべての非リーフはデータを格納しませんが、リーフノードのインデックスとして機能し、すべてのデータはリーフノードに格納されます。

このようにして、すべてのリーフノードのデータが整然と保存され、間隔クエリを適切にサポートできます。最初に開始ノードの位置を照会してから、リーフノードを逆方向にトラバースするだけで済みます。

データ量が多い場合は、インデックスファイルをメモリに保存できないことは明らかです。速度は非常に速いですが、リソースの消費量は少なくないため、MySQLはインデックスファイルを直接ディスクに保存します。

この点は、後述のElasticsearchインデックスとは少し異なります。インデックスはディスクに保存されるため、ディスクIOを可能な限り削減する必要があります(ディスクIOとメモリの効率は1桁ではありません)。

上の図からわかるように、データをクエリするには少なくとも4つのIOを実行する必要があります。明らかに、IOの数はツリーの高さと密接に関連しています。ツリーの高さが低いほど、IOの数が少なくなり、パフォーマンスが向上します。いいです。

どうすれば木の高さを下げることができますか?

Elasticsearchクエリが非常に高速なのはなぜですか?

バイナリツリーをトライノミアルツリーに変更して、ツリーの高さを大幅に下げることができます。これにより、データをクエリするときのIOの数が自然に減少し、クエリの効率が大幅に向上します。これが実際にはB +ツリーの起源です。

インデックスを使用するためのいくつかの提案

実際、上の図のB +ツリーを理解することで、日常業務の細部も最適化できます。たとえば、順番に増やす方がよいのはなぜですか。

書き込むプライマリキーデータが故障しているとすると、後で書き込むデータのIDが前に書き込んだIDよりも小さい可能性があるため、B +ツリーインデックスを維持するときに書き込まれたデータを移動する必要があります。

データが増分で書き込まれる場合、そのような考慮事項はなく、毎回順番に書き込むだけで済みます。そのため、データベースのプライマリキーは可能な限り増加傾向にある必要があります。最も合理的なのは、サブテーブルの状況を考慮せずにプライマリキーを増やすことです。

全体として、考え方はジャンプテーブルに似ていますが、使用シナリオに関連する調整が行われます(たとえば、すべてのデータがリーフノードに格納されます)。

ESインデックス

MySQLは終了しました。次に、Elasticsearchがインデックスをどのように使用するかを見てみましょう。

フロントインデックス

ESで使用されているのは、逆インデックスと呼ばれるデータ構造です。正式に説明する前に、逆インデックスの反対について説明しましょう。

Elasticsearchクエリが非常に高速なのはなぜですか?

上の図は例です。doc_idを介して特定のオブジェクトをクエリする方法は、正のインデックスを使用して呼び出されます。これは、ハッシュテーブルとしても理解できます。

本質は、キーによって値を見つけることです。たとえば、doc_id = 4を使用すると、データ名= jettywangおよびage = 20をすばやく見つけることができます。

反転インデックス

それで、名前にliを含むデータをクエリしたい場合、どうすれば効率的にクエリできますか?

明らかに、上記のフォワードインデックスだけでは効果がありません。名前にliが含まれているかどうかを判断するためにすべてのデータをトラバースすることしかできません。これは、非常に非効率的です。

しかし、インデックス構造を再構築すると、次のようになります。

Elasticsearchクエリが非常に高速なのはなぜですか?

名前にliが含まれているデータを照会する場合は、このインデックス構造を介して投稿リストに含まれているデータを照会し、次にマッピングを介して最終データを照会するだけで済みます。

このインデックス構造は、実際には逆インデックスです。

用語辞書

しかし、以前の経験と組み合わせて、このインデックス構造でliを効率的にクエリする方法は、用語を整然と配置する限り、バイナリツリー検索ツリーデータ構造を使用してo(logn)の下のデータをクエリできます。

テキストを独立した用語に分割するプロセスは、実際には、単語のセグメンテーションと呼ばれることがよくあります。

すべての用語を組み合わせたものが用語辞書であり、単語辞書とも呼ばれます。

英語の単語のセグメンテーションは比較的単純です。単語を分割するには、テキストをスペースと句読点で区切るだけです。中国語は比較的複雑ですが、それをサポートする多くのオープンソースツールがあります(この記事の焦点では​​ないため、単語のセグメンテーションに関心のある人は自分で検索できます)。

テキストの量が多いと、単語のセグメンテーション後に多くの用語が発生します。このような反転インデックスデータ構造をメモリに保存する場合は間違いなく十分ではありませんが、MySQLのようにディスクに保存する場合は効率がそれほど高くありません。

用語インデックス

したがって、妥協方法を選択できます。用語辞書全体をメモリに配置することはできないため、用語辞書のインデックスを作成してメモリに配置できます。

このようにして、用語辞書を効率的に照会し、最後に用語辞書を介して投稿リストを照会できます。

MySQLのB +ツリーと比較すると、ディスクIOも数倍削減されます。

Elasticsearchクエリが非常に高速なのはなぜですか?

この用語インデックスには、このようなTrieツリーを使用できます。これは、保存する辞書ツリーと呼ばれることがよくあります。

Elasticsearchクエリが非常に高速なのはなぜですか?

jで始まる用語で検索する場合、最初のステップは、メモリ内の用語インデックスを介して、用語辞書ファイルのどこにjで始まる用語があるかを見つけることです(この位置はファイルポインタである可能性があります。間隔範囲)。

この位置間隔のすべての用語を取り出した直後に、順序がソートされているため、バイナリ検索によって特定の位置をすばやく見つけることができます。このようにして、投稿リストを照会できます。

最後に、ターゲットデータは、投稿リストの場所情報を介して元のファイルから取得できます。

より多くの最適化

もちろん、Elasticsearchは多くのターゲットを絞った最適化も行っています。2つのフィールドを検索する場合、ビットマップを使用して最適化できます。

たとえば、name = liとage = 18のデータをクエリする必要があります。このとき、これら2つのフィールドを使用して、投稿リストからそれぞれの結果を取得する必要があります。

Elasticsearchクエリが非常に高速なのはなぜですか?

最も簡単な方法は、2つのセットを別々にトラバースして重複データを取り出すことですが、これは明らかに非効率的です。

現時点では、ビットマップをストレージに使用(およびストレージスペースを節約)すると同時に、固有のビットと計算を使用して結果を取得できます。

[1, 3, 5] ⇒ 10101 

[1, 2, 4, 5] ⇒ 11011 

結果は、2つのバイナリ配列を追加することで取得できます。

10001 ⇒ [1, 5] 

結局、投稿リストは[1、5]として解かれますが、これは当然効率がはるかに高くなります。同じクエリ要件はMySQLで特別に最適化されていませんが、2番目のフィールドは、少量のデータを含むデータが除外された後にフィルタリングされ、効率は当然ESほど高くありません。

もちろん、投稿リストは最新バージョンのESでも圧縮されます。特定の圧縮ルールは公式ドキュメントに記載されていますが、ここでは紹介しません。

総括する

最後に、要約しましょう。

Elasticsearchクエリが非常に高速なのはなぜですか?

上記の内容から、最終的には基本的なデータ構造で構成された複雑な製品であっても、さまざまなアプリケーションシナリオに合わせて最適化されることがわかります。したがって、データ構造とアルゴリズムの基礎を築いた後、新しいテクノロジーやミドルウェアを検討してください。すぐに始めて、最適化の方向性さえ知っているだけです。

最後に、パイを描きます。ES反転インデックスのアイデアに基づいてスタンドアロンの検索エンジンを構築しようとします。自分で書くだけで、理解を深めることができます。

おすすめ

転載: blog.csdn.net/qwe123147369/article/details/109095927