Hibernate Searchの紹介

1概要

この記事では、Hibernate Searchの基本、設定方法、そしていくつかの簡単なクエリを実装します。

2 Hibernate Searchの基本

全文検索機能を実装する必要があるときはいつでも、既に熟知しているツールを使用することが常にプラスになります。

ORMにHibernateとJPAを既に使用している場合は、Hibernate Searchから一歩先に進みます。

  • Hibernate Searchは、Java ** で書かれた高性能で拡張可能な全文検索エンジンライブラリであるApache Luceneを統合しています。これは、LuceneのパワーとHibernateおよびJPAの単純さを兼ね備えています。

簡単に言うと、ドメインクラスに追加のアノテーションを追加するだけです。** このツールは、データベースとインデックスの同期などの処理を行います。

Hibernate SearchはElasticsearchとの統合も提供します。しかし、まだ実験段階にあるので、ここではLuceneに焦点を当てます。

3構成

3.1. Mavenの依存関係

始める前に、まず必要なhttps://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.hibernate%22%20AND%20a%3A%22hibernate-search-を追加する必要があります。 orm%22[依存関係]を pom.xml に追加します。

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-search-orm</artifactId>
    <version>5.8.2.Final</version>
</dependency>

わかりやすくするために、https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22com.h2database%22%20AND%20a%3A%22h2%22[H2を使用します。]私たちのデータベースとして:

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.196</version>
</dependency>

3.2. 構成

Luceneがインデックスを格納する場所も指定する必要があります。

これはプロパティ hibernate.search.default.directory provider__を介して実行できます。

私たちは filesystem を選びます。これは私たちのユースケースのための最も直接的なオプションです。より多くのオプションはhttps://docs.jboss.org/hibernate/stable/search/reference/en-US/html single/#search-configuration-directory[非公開の文書]に記載されています。 Filesystem-master / filesystem-slave および infinispan__は、インデックスをノード間で同期する必要があるクラスタ化されたアプリケーションには注目に値します。

また、インデックスが格納されるデフォルトのベースディレクトリを定義する必要があります。

hibernate.search.default.directory__provider = filesystem
hibernate.search.default.indexBase =/data/index/default

4モデルクラス

設定が終わったら、モデルを指定する準備が整いました。

  • JPAアノテーション @ Entity @ Table の上に、 @ Indexed アノテーションを追加する必要があります。** これはHibernate Searchにエンティティ Product がインデックスされることを伝えます。

  • その後、 @ Field アノテーションを追加して必須の属性を検索可能として定義する必要があります。

@Entity
@Indexed
@Table(name = "product")
public class Product {

    @Id
    private int id;

    @Field(termVector = TermVector.YES)
    private String productName;

    @Field(termVector = TermVector.YES)
    private String description;

    @Field
    private int memory;

   //getters, setters, and constructors
}

termVector = TermVector.YES 属性は、後で「もっと似ている」クエリに必要になります。

5 Luceneインデックスの構築

実際のクエリを開始する前に、まずLuceneを起動してインデックスを作成する必要があります。

FullTextEntityManager fullTextEntityManager
  = Search.getFullTextEntityManager(entityManager);
fullTextEntityManager.createIndexer().startAndWait();
  • この最初のビルドの後、Hibernate Searchはインデックスを最新に保つようにします** 。 I.通常どおり EntityManager を介してエンティティを作成、操作、削除できます。

注:** Luceneによってエンティティが検出されインデックスが作成される前に、エンティティがデータベースに完全にコミットされていることを確認する必要があります(ところで、これも最初のテストデータがhttps://github.comにインポートされる理由です。/eugenp/tutorials/tree/master/persistence-modules/spring-hibernate-5[サンプルコードテストケース]には、専用のJUnitテストケースが用意されています。

6. クエリの構築と実行

これで、最初のクエリを作成する準備が整いました。

次のセクションでは、クエリを準備および実行するための一般的なワークフローについて説明します。

その後、最も重要な種類のクエリに対してクエリの例をいくつか作成します。

6.1. クエリを作成および実行するための一般的なワークフロー

  • クエリの準備と実行は一般的に4つのステップで構成されています** :

ステップ1では、JPA FullTextEntityManager を取得し、そこから QueryBuilder を取得します。

FullTextEntityManager fullTextEntityManager
  = Search.getFullTextEntityManager(entityManager);

QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory()
  .buildQueryBuilder()
  .forEntity(Product.class)
  .get();

ステップ2では、HibernateクエリDSLを介してLuceneクエリを作成します。

org.apache.lucene.search.Query query = queryBuilder
  .keyword()
  .onField("productName")
  .matching("iphone")
  .createQuery();

ステップ3では、LuceneクエリをHibernateクエリにラップします。

org.hibernate.search.jpa.FullTextQuery jpaQuery
  = fullTextEntityManager.createFullTextQuery(query, Product.class);

最後に、ステップ4でクエリを実行します。

List<Product> results = jpaQuery.getResultList();

:デフォルトでは、Luceneは結果を関連性の高い順にソートします。

手順1、3、4はすべてのクエリタイプで同じです。

以下では、ステップ2に焦点を当てます。 e。さまざまな種類のクエリを作成する方法。

6.2. キーワードクエリ

最も基本的なユースケースは 特定の単語の検索 です。

これは、前のセクションで実際に行ったことです。

Query keywordQuery = queryBuilder
  .keyword()
  .onField("productName")
  .matching("iphone")
  .createQuery();

ここで、 keyword() は1つの特定の単語を探していることを指定します。

6.3. ファジークエリ

ファジークエリはキーワードクエリと同じように機能しますが、「ファジー」の制限を定義できます。それを超えるとLuceneは2つの用語を一致として受け入れます。

withEditDistanceUpTo() によって、ある用語が他の用語からどれだけ逸脱する可能性があるかを定義できます。 0、1、2に設定できます。デフォルト値は2です( note :この制限はLuceneの実装によるものです)。

withPrefixLength() によって、あいまいさによって無視されるプレフィックスの長さを定義することができます。

Query fuzzyQuery = queryBuilder
  .keyword()
  .fuzzy()
  .withEditDistanceUpTo(2)
  .withPrefixLength(0)
  .onField("productName")
  .matching("iPhaen")
  .createQuery();

6.4. ワイルドカードクエリ

Hibernate Searchでは、ワイルドカードクエリを実行することもできます。 e。

単語の一部が不明なクエリ。

これには、単一の文字に「 ?」 を、任意の文字シーケンスに「 ** 」 を使用できます。

Query wildcardQuery = queryBuilder
  .keyword()
  .wildcard()
  .onField("productName")
  .matching("Z** ")
  .createQuery();

6.5. フレーズクエリ

複数の単語を検索したい場合は、フレーズクエリを使用できます。

必要ならば、 phrase() および withSlop() を使用して、 正確な文章または近似の文章 を探すことができます。スロップ係数は、文中で許可されている他の単語の数を定義します。

Query phraseQuery = queryBuilder
  .phrase()
  .withSlop(1)
  .onField("description")
  .sentence("with wireless charging")
  .createQuery();

6.6. 単純なクエリ文字列クエリ

以前のクエリタイプでは、クエリタイプを明示的に指定する必要がありました。

ユーザーにもっと力を与えたい場合は、単純なクエリ文字列クエリを使用できます。 これにより、実行時に独自のクエリを定義できます

以下のクエリタイプがサポートされています。

  • ブール値(ANDを使用したAND、ORを使用した|、使用していない - )

  • プレフィックス(プレフィックス** )

  • フレーズ(「いくつかのフレーズ」)

  • 優先順位(括弧を使用)

  • あいまい(fuzy〜2)

  • フレーズクエリ用のnear演算子(“ some phrase”〜3​​)

次の例では、あいまいクエリ、フレーズクエリ、およびブールクエリを組み合わせます。

Query simpleQueryStringQuery = queryBuilder
  .simpleQueryString()
  .onFields("productName", "description")
  .matching("Aple~2 + \"iPhone X\" + (256 | 128)")
  .createQuery();

6.7. 範囲クエリ

  • 範囲クエリは与えられた境界 の間で ** 値を検索します。これは数値、日付、タイムスタンプ、文字列に適用できます。

Query rangeQuery = queryBuilder
  .range()
  .onField("memory")
  .from(64).to(256)
  .createQuery();

6.8. もっとこのような質問

最後のクエリタイプは「 More Like This 」 - クエリです。このためにエンティティを提供し、 Hibernate Searchは類似のエンティティ を持つリストを返します。それぞれのリストは類似性スコアを持ちます。

前述のように、この場合はモデルクラスの termVector = TermVector.YES 属性が必要です。これは、インデックス作成中に各項の頻度を格納するようにLuceneに指示します。

これに基づいて、類似度はクエリ実行時に計算されます。

Query moreLikeThisQuery = queryBuilder
  .moreLikeThis()
  .comparingField("productName").boostedTo(10f)
  .andField("description").boostedTo(1f)
  .toEntity(entity)
  .createQuery();
List<Object[]> results = (List<Object[]>) fullTextEntityManager
  .createFullTextQuery(moreLikeThisQuery, Product.class)
  .setProjection(ProjectionConstants.THIS, ProjectionConstants.SCORE)
  .getResultList();

6.9. 複数のフィールドを検索する

これまでは、 onField() を使用して、1つの属性を検索するためのクエリのみを作成していました。

ユースケースによっては、** 複数の属性を検索することもできます。

Query luceneQuery = queryBuilder
  .keyword()
  .onFields("productName", "description")
  .matching(text)
  .createQuery();

さらに、 各属性を別々に検索するように指定することもできます 、e。

g。 1つの属性に対してブーストを定義したい場合は、

Query moreLikeThisQuery = queryBuilder
  .moreLikeThis()
  .comparingField("productName").boostedTo(10f)
  .andField("description").boostedTo(1f)
  .toEntity(entity)
  .createQuery();

6.10. クエリを組み合わせる

最後に、Hibernate Searchはさまざまな戦略を使ったクエリの組み合わせもサポートしています。

  • SHOULD: クエリには一致する要素を含める

副照会 ** MUST: クエリはサブクエリの一致する要素を含まなければなりません

  • MUST NOT :クエリは、の一致する要素を含んではいけません。

副照会

集約は、ブール型の AND、OR 、および NOT __. __に類似しています。ただし、関連性にも影響を与えることを強調するために、名前は異なります。

たとえば、2つのクエリ間の SHOULD は、ブール値の OR: に似ています。2つのクエリのいずれかに一致がある場合、この一致が返されます。

ただし、両方のクエリが一致した場合、一方のクエリのみが一致した場合に比べて、一致の関連性が高くなります。

Query combinedQuery = queryBuilder
  .bool()
  .must(queryBuilder.keyword()
    .onField("productName").matching("apple")
    .createQuery())
  .must(queryBuilder.range()
    .onField("memory").from(64).to(256)
    .createQuery())
  .should(queryBuilder.phrase()
    .onField("description").sentence("face id")
    .createQuery())
  .must(queryBuilder.keyword()
    .onField("productName").matching("samsung")
    .createQuery())
  .not()
  .createQuery();

7. 結論

この記事では、Hibernate Searchの基本について説明し、最も重要なクエリタイプを実装する方法を説明しました。より高度なトピックはhttps://docs.jboss.org/hibernate/stable/search/reference/en-us/html__single/[公式文書]にあります。

いつものように、例の完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-hibernate-5[over GitHub]から入手可能です。