第5章 クエリ
Hibernate Search の 2 番目に重要な機能は、Lucene クエリを実行し、Hibernate セッションにより管理されたエンティティを取得する機能です (これにより、Hibernate のパラダイム内で Lucene の能力が提供され、Hibernate の従来の検索メカニズム (HQL、基準クエリ、ネイティブ SQL クエリ) に別の次元が提供されます。クエリの準備と実行は 4 つの単純な手順から構成されます。
FullTextSession
の作成- Lucene クエリの作成
org.hibernate.Query
を使用した Lucene クエリのラップlist()
やscroll()
などを呼び出して検索を実行
クエリ機能にアクセスするには、
FullTextSession
を使用する必要があります。この検索固有のセッションは、通常の org.hibernate.Session
をラップしてクエリ機能とインデックス機能を提供します。
例5.1 FullTextSession の作成
Session session = sessionFactory.openSession(); ... FullTextSession fullTextSession = Search.getFullTextSession(session);
Session session = sessionFactory.openSession();
...
FullTextSession fullTextSession = Search.getFullTextSession(session);
実際の検索機能は、以下の例で示されたネイティブの Lucene クエリに基づいて構築されます。
例5.2 Lucene クエリの作成
Lucene クエリ上に構築された Hibernate クエリは通常の
org.hibernate.Query
です。つまり、他の Hibernate クエリ機能 (HQL、Native、または Criteria) と同じパラダイムに属しています。通常の list()
、uniqueResult()
、iterate()
、および scroll()
メソッドを使用できます。
Hibernate の Java Persistence API (EJB 3.0 Persistence とも呼ばれます) を使用している場合は、同じ拡張機能が存在します。
例5.3 JPA API を使用した検索クエリの作成
以下の例では、Hibernate API を使用します。ただし、同じ例は、Java Persistence API を使用して
FullTextQuery
が取得される方法を調整することによって簡単に書き換えることができます。
5.1. クエリの構築 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
Hibernate Search クエリは Lucene クエリの上部に構築され、実行する Lucene クエリのタイプはまったく関係ありません。ただし、構築された Hibernate Search は
org.hibernate.Query
を主なクエリ操作 API として使用してクエリ処理をラップします。
5.1.1. Lucene クエリの構築 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
Lucene クエリの実際の構築方法については、このドキュメンテーションの範囲外です。オンラインの Lucene ドキュメンテーションまたは『Lucene In Action』あるいは『Hibernate Search in Action』を参照してください。
5.1.2. Hibernate Search クエリの構築 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
5.1.2.1. 概要 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
Lucene クエリが構築されたら、Lucene クエリを Hibernate Query にラップする必要があります。
例5.4 Hibernate Query への Lucene クエリのラップ
FullTextSession fullTextSession = Search.getFullTextSession( session ); org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery );
FullTextSession fullTextSession = Search.getFullTextSession( session );
org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery );
特に指定がない限りクエリはインデックス化されたすべてのエンティティに対して実行されます (場合によっては、インデックス化されたクラスのすべてのタイプが返されます)。パフォーマンスの観点から、返されるタイプを制限することが推奨されます。
例5.5 エンティティタイプによる検索結果のフィルタリング
org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, Customer.class ); // or fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, Item.class, Actor.class );
org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, Customer.class );
// or
fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, Item.class, Actor.class );
最初の例は一致する
Customer
だけを返し、2 つ目の例は一致する Actor
と Item
を返します。タイプの制限は完全にポリモーフィックです。つまり、基本クラス Person
の、2 つのインデックス化されたサブクラスSalesman
と Customer
が存在する場合、結果タイプに基づいてフィルタするには Person.class
を指定します。
5.1.2.2. ページ処理 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
パフォーマンス上の理由から、1 つのクエリに対して返されるオブジェクトの数を制限することが推奨されます。ユーザーがあるページから別のページに移動することは実際にはよくあることです。ページ処理を定義する方法は、プレーンな HQL または基準クエリでページ処理を定義する方法とまったく同じです。
例5.6 検索クエリのページ処理の定義
org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, Customer.class ); fullTextQuery.setFirstResult(15); //start from the 15th element fullTextQuery.setMaxResults(10); //return 10 elements
org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, Customer.class );
fullTextQuery.setFirstResult(15); //start from the 15th element
fullTextQuery.setMaxResults(10); //return 10 elements
注記
fulltextQuery.
getResultSize()
を使用すると、ページ処理に関係なく一致するエレメントの合計数を取得できます。
5.1.2.3. ソート リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
Apache Lucene を使用すると、結果を非常に柔軟かつ強力にソートできます。ほとんどの場合はデフォルトのソート (重要度別) が適切ですが、1 つまたは複数の他のプロパティによってソートすることもできます。これを行うには、Lucene Sort オブジェクトが Lucene ソート方針を適用するよう設定します。
例5.7 結果をソートするための Lucene Sort
の指定
org.hibernate.search.FullTextQuery query = s.createFullTextQuery( query, Book.class ); org.apache.lucene.search.Sort sort = new Sort(new SortField("title")); query.setSort(sort); List results = query.list();
org.hibernate.search.FullTextQuery query = s.createFullTextQuery( query, Book.class );
org.apache.lucene.search.Sort sort = new Sort(new SortField("title"));
query.setSort(sort);
List results = query.list();
FullTextQuery
インタフェースが org.hibernate.Query
のサブインタフェースであることに気づかれるかもしれません。ソートに使用されるフィールドはトークン化しないよう注意してください。
5.1.2.4. フェッチ方針 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
戻り値のタイプを 1 つのクラスに制限する場合、Hibernate Search は単一のクエリを使用してオブジェクトをロードします。また、ドメインモデルで定義された静的なフェッチ方針が優先されます。
ただし、多くの場合、特定の使用例のためにフェッチ方針を調整することが役に立ちます。
例5.8 クエリでの FetchMode
の指定
Criteria criteria = s.createCriteria( Book.class ).setFetchMode( "authors", FetchMode.JOIN ); s.createFullTextQuery( luceneQuery ).setCriteriaQuery( criteria );
Criteria criteria = s.createCriteria( Book.class ).setFetchMode( "authors", FetchMode.JOIN );
s.createFullTextQuery( luceneQuery ).setCriteriaQuery( criteria );
この例では、クエリは luceneQuery に一致するすべての本を返します。作者コレクションは SQL 外部結合を使用して同じクエリからロードされます。
基準クエリを定義する場合は、完全テキストセッションから Hibernate Search クエリを作成するときに返されるエンティティタイプを制限する必要はありません。タイプは基準クエリ自体から推測されます。フェッチモードのみを調整し、他の制限の適用を回避できます。
複数のエンティティが返されることが期待される場合は、
setCriteriaQuery
を使用できません。
5.1.2.5. プロジェクション リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
場合によっては、ドメインオブジェクト (グラフ) を返すことがやりすぎになることがあります。Hibernate Search では、プロパティのサブセットを返すことができます。
例5.9 完全なドメインオブジェクトを返す代わりにプロジェクションを使用
Hibernate Search は Lucene インデックスからプロパティを抽出し、オブジェクト形式に再び変換します (
Object[]
のリストが返されます)。プロジェクションにより、潜在的なデータベースラウンドトリップ (クエリの応答時間が重要な場合に有用) が回避されますが、いくつかの制限が存在します。
- 予測されたプロパティはインデックス (
@Field(store=Store.YES)
) に格納する必要があります (これによりインデックスサイズが増加します)。 - 予測されたプロパティは、
org.hibernate.search.bridge.TwoWayFieldBridge
またはorg.hibernate.search.bridge.TwoWayStringBridge
(単純なバージョン) を実装するFieldBridge
を使用する必要があります。すべての Hibernate Search 組込みタイプは両方向です。 - インデックス化されたエンティティまたは組み込まれた関係の単純なプロパティのみを予測できます。つまり、組み込まれたエンティティ全体を予測できません。
- プロジェクションは、
@IndeedEmbedded
を使用してインデックス化されたコレクションまたはマップに対して機能しません。
プロジェクションは、別の場合にも役に立ちます。Lucene は結果に関するいくつかのメタデータ情報をユーザーに提供します。いくつかの特殊なプレースホルダーを使用することにより、プロジェクションメカニズムはこれらのメタデータを取得できます。
例5.10 メタデータを取得するためにプロジェクションを使用
通常のフィールドと特殊なプレースホルダーは混在させることができます。利用可能なプレースホルダーのリストは以下のとおりです。
- FullTextQuery.THIS: 初期化および管理されたエンティティを返します (予測されないクエリの場合と同様)。
- FullTextQuery.DOCUMENT: 予測されたオブジェクトに関連する Lucene Document を返します。
- FullTextQuery.OBJECT_CLASS: インデックス化されたエンティティのクラスを返します。
- FullTextQuery.SCORE: クエリのドキュメンテーションスコアを返します。スコアはある結果とクエリの他の結果を比較するのに役に立ちしますが、異なるクエリの結果を比較する場合は役に立ちません。
- FullTextQuery.ID: 予測されたオブジェクトの id プロパティ値。
- FullTextQuery.DOCUMENT_ID: Lucene ドキュメント id。Lucene ドキュメント id は 2 つの異なる IndexReader のオープン間で変わることがあることに注意してください (この機能は実験段階にあります)。
- FullTextQuery.EXPLANATION: 該当するクエリの一致するオブジェクト/ドキュメントに対する Lucene Explanation オブジェクトを返します。たくさんのデータを取得する場合は使用しないでください。通常、Explanation を返すコストは、一致するエレメントごとに Lucene クエリ全体を実行するコストと同じです。