Elasticsearch は、Apache Lucene を使用して構築されたオープンソースの分散型 ベースの検索および分析エンジンであり、高速なリアルタイム検索機能を提供します。これは、デフォルトでドキュメント指向、スケーラブル、スキーマレスの NoSQL データ ストアです。 Elasticsearch は、大規模なデータセットを大規模に処理できるように設計されています。検索エンジンとして、複数のノードにわたって水平方向に拡張できる高速なインデックス作成と検索機能を提供します。 JSON 恥知らずなプラグ: 、クラウド上のリアルタイム インデックス データベースです。検索だけでなく集計や結合にも最適化されたインデックスが自動的に構築されるため、データの取得元や形式に関係なく、アプリケーションでデータを迅速かつ簡単にクエリできるようになります。ただし、この投稿では、いくつかの回避策を紹介します。 , Elasticsearch で SQL スタイルの結合を本当に実行したい場合に備えて。 Rockset は データ関係が重要なのはなぜですか? 私たちは高度に接続された世界に住んでおり、データ関係の処理が重要です。リレーショナル データベースは関係の処理には優れていますが、ビジネス要件が常に変化するため、これらのデータベースのスキーマが固定されているため、スケーラビリティとパフォーマンスの問題が発生します。 NoSQL データ ストアの使用は、従来のデータ処理アプローチに伴ういくつかの課題に対処できるため、ますます一般的になってきています。 企業は、データを分析するために集計、結合、フィルタリング機能が必要となる複雑なデータ構造を継続的に扱っています。非構造化データの急増に伴い、データ分析の目的でさまざまなソースからのデータを結合する必要があるユースケースが増えています。 結合は主に SQL の概念ですが、NoSQL の世界でも同様に重要です。 SQL スタイルの結合は、Elasticsearch では第一級住民としてサポートされていません。この記事では、非正規化、アプリケーション側の結合、ネストされたドキュメント、親子関係などのさまざまな手法を使用して、Elasticsearch でリレーションシップを定義する方法について説明します。また、各アプローチに関連するユースケースと課題についても説明します。 Elasticsearch でリレーションシップに対処する方法 Elasticsearch はリレーショナル データベースではないため、SQL データベースのようなネイティブ機能として結合は存在しません。ストレージ効率ではなく、検索効率に重点を置いています。保存されたデータは実質的に平坦化または非正規化され、高速検索のユースケースを促進します。 Elasticsearch で関係を定義するには複数の方法があります。ユースケースに基づいて、Elasticsearch で以下の手法のいずれかを選択してデータをモデル化できます。 1 対 1 の関係: オブジェクトのマッピング 1 対多の関係: ネストされたドキュメントと親子モデル 多対多の関係: 非正規化とアプリケーション側の結合 1 対 1 のオブジェクト マッピングは単純なので、ここではあまり説明しません。このブログの残りの部分では、他の 2 つのシナリオについて詳しく説明します。 Elasticsearch でのデータ モデルの管理 Elasticsearch でデータを管理するには、次の 4 つの一般的なアプローチがあります。 非正規化 アプリケーション側の結合 ネストされたオブジェクト 親子関係 非正規化 非正規化により、クエリ時にデータセットを結合する必要がないため、Elasticsearch で最高のクエリ検索パフォーマンスが得られます。各ドキュメントは独立しており、必要なデータがすべて含まれているため、コストのかかる結合操作が不要になります。 非正規化を使用すると、データはインデックス作成時にフラット化された構造で保存されます。ただし、これによりドキュメントのサイズが増加し、各ドキュメントに重複したデータが保存されることになります。ディスク容量は高価なものではないため、ほとんど心配する必要はありません。 非正規化の使用例 分散システムを使用している場合、ネットワーク経由でデータ セットを結合する必要があるため、大幅な遅延が発生する可能性があります。データを非正規化することで、これらの負荷の高い結合操作を回避できます。多対多の関係は、データのフラット化によって処理できます。 データの非正規化に関する課題 データをフラット化されたドキュメントに複製するには、追加の記憶域が必要です。 フラット化された構造でデータを管理すると、本質的にリレーショナルであるデータ セットに追加のオーバーヘッドが発生します。 プログラミングの観点から見ると、非正規化には追加のエンジニアリング オーバーヘッドが必要になります。複数のリレーショナル テーブルに格納されているデータをフラット化し、それを Elasticsearch の単一のオブジェクトにマップするには、追加のコードを記述する必要があります。 データが頻繁に変更される場合、データを非正規化することは得策ではありません。このような場合、非正規化ではデータのサブセットが変更されたときにすべてのドキュメントを更新する必要があるため、非正規化は避けるべきです。 フラット化されたデータ セットでは、より多くのデータがインデックス付けされるため、インデックス付け操作に時間がかかります。データが頻繁に変更される場合は、インデックス作成率が高いことを示しており、クラスターのパフォーマンスの問題が発生する可能性があります。 アプリケーション側の結合 アプリケーション側の結合は、ドキュメント間の関係を維持する必要がある場合に使用できます。データは別のインデックスに保存され、クエリ時にアプリケーション側から結合操作を実行できます。ただし、これには、ドキュメントを結合するためにアプリケーションから検索時に追加のクエリを実行する必要があります。 アプリケーション側結合の使用例 アプリケーション側の結合により、データが正規化された状態が維持されます。変更は 1 か所で行われるため、ドキュメントを常に更新する必要はありません。このアプローチにより、データの冗長性が最小限に抑えられます。この方法は、ドキュメントの数が少なく、データの変更の頻度が低い場合に適しています。 アプリケーション側の結合に関する課題 アプリケーションは、検索時にドキュメントを結合するために複数のクエリを実行する必要があります。データ セットに多数のコンシューマが含まれる場合、同じクエリ セットを複数回実行する必要があり、パフォーマンスの問題が発生する可能性があります。したがって、このアプローチは Elasticsearch の真の力を活用しません。 このアプローチでは、実装レベルが複雑になります。結合操作を実装してドキュメント間の関係を確立するには、アプリケーション レベルで追加のコードを記述する必要があります。 ネストされたオブジェクト 配列内の各オブジェクトの関係を維持する必要がある場合は、ネストされたアプローチを使用できます。ネストされたドキュメントは個別の Lucene ドキュメントとして内部的に保存され、クエリ時に結合できます。これらはインデックス時結合であり、複数の Lucene ドキュメントが 1 つのブロックに保存されます。アプリケーションの観点から見ると、ブロックは単一の Elasticsearch ドキュメントのように見えます。すべてのデータが同じオブジェクト内に存在するため、クエリは比較的高速になります。ネストされたドキュメントは 1 対多の関係を扱います。 ネストされたドキュメントの使用例 ドキュメントにオブジェクトの配列が含まれている場合は、ネストされたドキュメントを作成することをお勧めします。以下の図 1 は、Elasticsearch のネストされた型により、オブジェクトの配列が個別の Lucene ドキュメントとして内部的にインデックス付けされる仕組みを示しています。 Lucene には内部オブジェクトの概念がないため、Elasticsearch が元のドキュメントを内部でどのようにフラット化された複数値フィールドに変換するかを見るのは興味深いことです。 ネストされたクエリを使用する利点の 1 つは、オブジェクト間の一致が行われないため、予期しない一致結果が回避されることです。オブジェクトの境界を認識するため、検索がより正確になります。 図 1: ネストされたアプローチを使用した Elasticsearch の個別の Lucene ドキュメントとして内部的にインデックス付けされたオブジェクトの配列 ネストされたオブジェクトに関する課題 ネストされたオブジェクトを追加/更新/削除するには、ルート オブジェクトとそのネストされたオブジェクトのインデックスを完全に再作成する必要があります。つまり、子レコードを更新すると、ドキュメント全体のインデックスが再作成されます。 ネストされたドキュメントには直接アクセスできません。これらには、関連するルート ドキュメントからのみアクセスできます。 検索リクエストは、検索クエリに一致するネストされたドキュメントのみを返すのではなく、ドキュメント全体を返します。 データセットが頻繁に変更される場合、ネストされたドキュメントを使用すると、大量の更新が行われることになります。 親子関係 親子関係では、 利用して、関係を持つオブジェクトを個別のドキュメント (親と子) に完全に分離します。これにより、ドキュメントをリレーショナル構造で別個の Elasticsearch ドキュメントに保存し、個別に更新できるようになります。 結合データ型を ドキュメントを頻繁に更新する必要がある場合、親子関係は有益です。したがって、このアプローチは、データが頻繁に変更されるシナリオに最適です。基本的には、ベースドキュメントを親と子を含む複数のドキュメントに分離します。これにより、親ドキュメントと子ドキュメントの両方を互いに独立してインデックス付け、更新、削除できます。 親ドキュメントと子ドキュメントの検索 インデックス作成および検索中の Elasticsearch のパフォーマンスを最適化するには、ドキュメントのサイズが大きくならないようにすることが一般的に推奨されます。親子モデルを利用して、ドキュメントを別々のドキュメントに分割できます。 ただし、これを実装するにはいくつかの課題があります。親ドキュメントと子ドキュメントは、クエリ時にそれらを結合することがメモリ内で効率的に行われるように、同じシャードにルーティングする必要があります。親 ID は、子ドキュメントのルーティング値として使用する必要があります。 フィールドは、Elasticsearch に親ドキュメントの ID とタイプを提供します。これにより、内部的に子ドキュメントを親ドキュメントと同じシャードにルーティングできるようになります。 _parent Elasticsearch を使用すると、複雑な JSON オブジェクトから検索できます。ただし、効率的にクエリを実行するには、データ構造を完全に理解する必要があります。親子モデルは複数のフィルターを利用して検索機能を簡素化します。 クエリ has_child クエリに一致する子ドキュメントを持つ親ドキュメントを返します。 クエリ has_parent 親を受け入れ、関連付けられた親が一致した子ドキュメントを返します。 クエリ inner_hits クエリから関連する子の情報を取得します。 has_child 図 2 は、親子モデルを使用して 1 対多の関係を示す方法を示しています。子ドキュメントは、親に影響を与えることなく追加、削除、更新できます。親ドキュメントにも同じことが当てはまり、子のインデックスを再作成せずに更新できます。 図 2: 1 対多の関係の親子モデル 親子関係の課題 結合操作のため、クエリはよりコストがかかり、メモリを大量に消費します。 親子構造はクエリ時に結合する必要がある別個のドキュメントであるため、オーバーヘッドが発生します。 親とそのすべての子が同じシャード上に存在することを確認する必要があります。 親子関係を持つドキュメントを保存するには、実装が複雑になります。 結論 適切な Elasticsearch 設計を選択することは、アプリケーションのパフォーマンスと保守性にとって重要です。 Elasticsearch でデータ モデルを設計するときは、ここで説明する 4 つのモデリング方法それぞれのさまざまな長所と短所に注意することが重要です。 データ モデリング この記事では、ネストされたオブジェクトと親子関係により、Elasticsearch で SQL のような結合操作がどのように可能になるかについて説明しました。アプリケーションにカスタム ロジックを実装して、アプリケーション側の結合との関係を処理することもできます。 Elasticsearch で複数のデータ セットを結合する必要があるユースケースでは、これらの両方のデータ セットを Elasticsearch インデックスに取り込んでロードすることで、パフォーマンスの高いクエリを有効にすることができます。 初期状態では、Elasticsearch には SQL データベースのような結合がありません。文書内で関係を確立するための潜在的な回避策はありますが、これらのアプローチごとに生じる課題を認識しておくことが重要です。 Rockset でのネイティブ SQL 結合の使用 リアルタイム分析のために複数のデータ セットを結合する必要がある場合、ネイティブ SQL 結合を提供するデータベースは、この使用例をより適切に処理できます。 Elasticsearch と同様に、Rockset はデータベース、イベント ストリーム、データ レイクからのデータのインデックス レイヤーとして使用され、これらのソースからのスキーマレスの取り込みを可能にします。 Elasticsearch とは異なり、Rockset は結合を含む 機能を備えているため、データの使用方法がより柔軟になります。 フル機能の SQL を使用してクエリを実行する でも公開されています。 ここ