動画
テスト
テストの設定方法については docs / testing / elasticsearch を参照してください。
統合する理由
Ebean ORM を使用するアプリケーションにとって、ElasticSearch の統合が便利な理由はいくつかあります。
ElasticSearch の価値
- 「全文検索」を提供します
- DB マテリアライズドビューのようなものを提供します
- 読み取りアクセスのスケーリング
- 読み取りアクセスパフォーマンス(ドキュメントストレージ)
- L2キャッシュの問題を修正します
- L3キャッシュを提供します
「全文検索」を提供します
多くの現代的なアプリケーションは、「Google検索」のような形式で動作する単一の検索入力フィールドを提供します。たとえば、顧客の名前と住所(通り、市区町村、国など)を含む顧客の検索などです。
ElasticSearch はアナライザーと転置インデックスを使用して「テキスト検索」を高速かつ効率的にします。OLTPデータベースは一般的に、BTreeやBitMapインデックスによる非常に異なるインデックスを提供しており、これらはOLTP(短いトランザクション、自己バランスなど)のニーズに合わせて調整されています。
DB マテリアライズドビューのようなものを提供します
多くのデータベースは、一般的にデータのより高速な表示を提供するために使用される派生/計算されたビューであるマテリアライズドビューを提供します。マテリアライズドビューは定期的に更新され、派生/計算されたデータが定期的にのみ更新され、古くなる可能性があることを認識しているアプリケーションによって使用されます。たとえば、製品の価格設定は毎晩深夜に更新される場合があります。
ElasticSearchインデックスは、DBマテリアライズドビューと同様に表示できます。それらは、各コミットでほぼリアルタイムで更新したり、より定期的なバッチ方式で更新したりできる、データのマテリアライズされた(ドキュメント指向の)ビューを表します。
読み取りアクセスのスケーリング
ElasticSearchはアーキテクチャ的に水平スケーリングが組み込まれており、これにより、より従来型のOLTPデータベースをスケーリングするよりも、読み取りアクセスをスケーリングするためのより簡単で安価な方法を提供できます。アクセスは、ほとんどのOLTPデータベースによって提供されるものと同等ではなく、同じトランザクション読み取り整合性の保証を提供せず、「ほぼ」リアルタイム(通常は1秒程度遅れる)であることに注意してください。ただし、これらの制限は、読み取りスケーラビリティの向上を考慮すると許容できることがよくあります。
読み取りアクセスパフォーマンス(非正規化されたドキュメントストレージ)
ElasticSearch はドキュメントストアとしても表示でき、保存される「ドキュメント」は非正規化されており、派生および結合された情報が含まれていることがよくあります。これは、Elastic Search で単一のドキュメントを検索することが、多くの結合を必要とする SQL クエリと競合する可能性があることを意味します。たとえば、Order ドキュメントは非正規化される可能性があり、そうでない場合は、SQL クエリで Order、OrderDetails、Customer、Product テーブルを結合します。
非正規化されたデータの従来からの欠点は存在しますが、OLTPデータベースが依然としてプライマリデータストアであり、ElasticSearch がセカンダリストアである場合は、「非正規化されたドキュメント」の保存が適切に管理されます。
L2キャッシュの問題を修正します
ElasticSearch は、合理的な量の挿入、更新、または削除の変更が発生するタイプに対する L2 クエリキャッシュ の効果的な代替として使用できます。
基本的に、アプリケーションが頻繁に変更される (挿入、更新、または削除) Bean タイプで L2 クエリキャッシュ
に依存している場合、これは L2 クエリキャッシュの非効率的な利用 (頻繁に無効化されるため) が原因でデータベースに負荷がかかります。
ElasticSearch は、「リレーショナル」述語によくマッピングされる多くの「正確な値/ターム」述語を提供し、多くのリレーショナル/orm クエリを ElasticSearch に対して適切に実行できます。頻繁に更新されるテーブルに対して「多数検索」クエリをスケーリングする必要がある場合、ElasticSearch は、ElasticSearch インデックスがわずかに古い可能性があるという注意点がありますが、優れたソリューションを提供できます。
L3キャッシュを提供します
Ebean の場合、L3 キャッシュ
という用語は、L2 キャッシュ
のリモート部分を意味します。つまり、L2 キャッシュには「ニアキャッシュ」と「リモートキャッシュ」があり、「L3 キャッシュ」とはここでは L2 キャッシュのリモート部分を意味します。
Ebean は、(より従来的な Hazelcast/Infinispan/などの分散キャッシュの代わりに) L3 キャッシュとして ElasticSearch を使用できます。ローカル L2 キャッシュでミスがあった場合、Ebean は、ElasticSearch がすべてのデータを持ち、非正規化された形式で持つことがわかっているという利点とともに、データベースではなく ElasticSearch をヒットする可能性があります (そのため、ElasticSearch に対する 1 回のヒットで、従来の DB ヒットよりも多くのグラフを埋める可能性があります)。
JSONドキュメントとしてのORMグラフ
ORM グラフは自然に JSON ドキュメントにマッピングされます。Ebean には、JSON との間でマーシャリング/アンマーシャリングを行うための組み込みサポートと、大規模なクエリを効率的に実行するための組み込みサポートもあります。これにより、たとえば、特定のタイプのすべてのオブジェクトに対して大規模なクエリを実行し、それらのオブジェクトグラフを JSON に変換して ElasticSearch に送信することは、完全に自然で合理的です。
注意点として、ORM グラフは通常、適切に構造化されています (Postgres および Oracle で十分にサポートされている DB に JSON を格納する場合、半構造化されています)。ORM グラフを ElasticSearch ドキュメントにマッピングする際には、通常、「コード」であるプロパティ(分析すべきでない)を識別したり、分析された形式と未加工形式で必要なプロパティを識別したりするなど、マッピングを考慮に入れる必要があります(クエリの order by 句をサポートするため)。
自動同期
コア統合機能は、ElasticSearchへの変更を同期するための優れたメカニズムを提供することです。つまり、Ebeanがデータベースへの変更を処理するとき、インデックスに対してどのような更新が必要かを自動的に認識し、それらの更新をいつどのように行うかを制御できるようにする機能を提供します。
Ebean はマッピングから必要なインデックス更新イベントを判断し、これらの更新をバックグラウンドでElasticSearchに即座に送信するか、後で処理するためにキューに入れるか、無視するか(インデックス作成を完全に制御する場合)を制御できます。
クエリ
Ebeanを使用せずに常にElasticSearchに直接クエリを実行でき、それはいくつかのユースケースによく適合します。さらに、Ebeanは、多くの利点を持ってクエリを実行するための優れたサポートを提供します。
「raw」フィールドの自動使用
Ebeanは、式を自動的に変換して、ソート(order by)句およびターム式の場合に関連付けられた「raw」フィールドを使用します。つまり、Ebeanはマッピングを通じて、どのプロパティに関連付けられた非分析(raw)フィールドを持っているかを知っており、必要な場合(order byおよびターム式)にこれらを使用します。
永続コンテキスト
ElasticSearchからフェッチし、OLTP DBに永続化する場合に使用します。永続コンテキストは、JSONドキュメントからオブジェクトグラフが構築される際にBeanの重複排除に使用され、一貫したグラフが得られます(これが通常、永続化で必要となるものです)。永続コンテキストは、クエリ結合(同じBeanの複数のJSONソースのマージ)でも役割を果たします。
ロードコンテキスト - 遅延ロードとクエリ結合
ORM クエリと同様に、ロードコンテキストを使用して、効率的なバッチ遅延ロードとクエリ結合を提供できます。ElasticSearch から構築されたオブジェクトグラフは、遅延ロードを呼び出すことができます (L2、他のインデックス、および Bean タイプが Elastic インデックスにマッピングされる場合は OLTP DB にフォールバックします)。ロードコンテキストは、「クエリ結合」も提供するため、他のインデックスに結合して結果を構築できます。たとえば、顧客インデックスからフェッチし、連絡先インデックスを結合します (ElasticSearch 用語では、これは「アプリケーション側の結合」として記述されます)。従来の ORM クエリ結合 (N + 1 を回避するため) と同様に、バッチロードによってこれを効率的に行うことができます。
クエリビーン - タイプセーフなクエリ構築
クエリビーンを使用して、タイプセーフな方法でクエリを構築できます。これは、スキーマとタイプの変更に対するコンパイル時保護を備えた長期的なメンテナンスに適しています。
DBまたはElasticをヒットしますか?
ORM クエリを記述し、それを ElasticSearch をヒットするように簡単に変更できる機能により、アプリケーション開発者は決定を遅らせ、DB または Elastic をヒットする間で比較的簡単に変更できます。これは、述語の大文字と小文字の区別および読み取りの一貫性(およびサブクエリのサポートなし)を考慮した「完全な」スワップではありませんが、非常に多くのケースで、この2つを簡単にスワップできる機能により、開発者は、後で再検討できるという知識(永続コンテキスト、遅延ロード、DBへの保存などに関してセマンティクスを変更せずに実装をElasticにヒットするように変更できます)を構築することができます。
つまり、これにより、読み取りを水平方向にスケーリングするための障壁の低いパスが提供されます。
useDocStore(true)
Ebean クエリで useDocStore(true)
を設定するだけで、クエリは ElasticSearch に対して実行されます。ElasticSearch に変換できないクエリ式はサブクエリ式のみであり、それ以外の場合はすべての式を ElasticSearch 式に変換できます。
例:ページングリストの検索
PagedList<Product> products = server.find(Product.class)
.setUseDocStore(true) // hit Elastic index
.where().startsWith("sku", "C00")
.setMaxRows(20)
.findPagedList();
例:IDによる検索
Product product = server.find(Product.class)
.setUseDocStore(true) // hit Elastic index
.setId(1)
.findOne();
リレーショナル式のマッピング
ほとんどの「リレーショナル/正確な値」式は、いくつかの例外を除いて、ElasticSearch 式に直接マッピングされます。
- Like、StartsWith、EndsWith、および Contains は、ElasticSearch ではすべて実質的に大文字と小文字を区別しないことに注意してください。
- サブクエリ IN - これは現在サポート/変換されていません
- サブクエリ EXISTS - これは現在サポート/変換されていません
部分オブジェクト - select() と fetch()
ORM クエリと同様に、ElasticSearch クエリを最適化して、必要なドキュメントの一部のみをフェッチできます。通常の Ebean クエリ select() および fetch() を使用して、フェッチバックするドキュメントの部分を定義できます。Ebean はそれを ElasticSearch クエリに適用します。
List<Customer> customers =
server.find(Customer.class)
.useDocStore(true)
// only fetch id, status and name from index
// ... as a performance optimisation
.select("status, name")
.where().istartWith("name", "Rob")
.findList();
クエリ結合
ORM クエリと同様に、複数のインデックスを「クエリ結合」できます。
// fetch from the customer index
// ... "join" the contacts index
List<Customer> customers = server.find(Customer.class)
.setUseDocStore(true)
// fetch related contacts from the contacts index
.fetch("contacts", new FetchConfig().query())
.findList();
// fetch from the order index
// ... "join" the customer index
//
// internally this merges the customer details
// ... from the order index with the customer details
// ... from the customer index
List<Order> orders = server.find(Order.class)
.setUseDocStore(true)
// say the order index only embeds customer(id,name)
// so we additionally fetch (and merge) all customer
// details including the billingAddress and shippingAddress
// from the customer index
.fetch("customer", new FetchConfig().query())
.findList();
これに対するサポートは、特定のインデックスに使用する非正規化/埋め込みドキュメントの量に関する決定を変更する可能性があります。たとえば、「Order」インデックスでは、顧客のどの程度を注文に含めるか/埋め込むかを決定する必要があります。顧客(id,name)または顧客(id,name,billingAddress(*))などを埋め込むことができます。「顧客インデックス」を簡単に結合する機能 (必要な顧客の詳細をフェッチするため) は、注文ドキュメントに顧客をあまり埋め込まないように選択できることを意味します。
クエリ - フルテキスト
フルテキストクエリ式もEbeanによって公開されています。これらは「ドキュメントストア」クエリでのみ使用され、OLTPデータベースに送られる通常のORMクエリには使用されません。
where()
を使用する代わりに、text()
を使用して、match
、multi-match
、common terms
、text simple query
、および text query
のような「全文」検索式をクエリに追加できます。これらは、対応するElasticSearchの全文式に直接マッピングされます。
「テキスト式」を追加すると、クエリは自動的に useDocStore(true)
に設定されることに注意してください。
PagedList<Customer> customers = server.find(Customer.class)
.text()
.match("name", "Rob")
.findPagedList();
PagedList<Customer> customers = server.find(Customer.class)
.text()
.match("name", "Rob")
.match("notes", "kung fu")
.findPagedList();
PagedList<Customer> customers = server.find(Customer.class)
.text()
.must()
.match("customer.name", "Rob")
.eq("status", Order.Status.COMPLETE)
.findPagedList();
MultiMatch match = MultiMatch.fields("name", "notes").boost(2).opAnd();
PagedList<Customer> customers = server.find(Customer.class)
.text()
.multiMatch("Rob", match)
.findPagedList();
現在対象外
以下の機能は、現在対象外とみなされています。
ElasticSearchの親/子マッピング
ElasticSearchは、ネスト/埋め込み/非正規化アプローチの代替として、親/子マッピングを提供します。この段階では、これに対するサポートは対象外であり、代わりにネスト/非正規化アプローチが推奨されます。
Ebeanは、「クエリ結合」を使用して、複数のインデックスを単一の結果に結合してフェッチできることに注意してください。