検索

14.2. インデックス構造へのエンティティーのマッピング

download PDF

14.2.1. エンティティーのマッピング

エンティティーのインデックス化に必要なすべてのメタデータ情報はアノテーションで記述されるため、XML マッピングファイルは必要ありません。基本的な Hibernate 設定には Hibernate マッピングファイルも使用できますが、Hibernate Search 固有の設定はアノテーションで表現する必要があります。

14.2.1.1. 基本的なマッピング

エンティティーのマッピングに最も一般的に使用されるアノテーションから始めましょう。
Lucene ベースの Query API は、以下の共通アノテーションを使用してエンティティーをマッピングします。
  • @Indexed
  • @Field
  • @NumericField
  • @Id
14.2.1.1.1. @Indexed
ほとんどの場合、永続クラスをインデックス化可能として宣言する必要があります。これは、クラスに @Indexed アノテーションを付けることで行われます (@Indexed アノテーションが付いていないすべてのエンティティーはインデックスプロセスによって無視されます)。

例14.8 @Indexed を使用してクラスをインデックス可能にする

@Entity
@Indexed
public class Essay {
    ...
}
オプションで @Indexed アノテーションの index 属性を指定して、インデックスのデフォルト名を変更できます。
14.2.1.1.2. @Field
エンティティーのプロパティー(または属性) ごとに、インデックス化方法を記述する機能があります。デフォルト (アノテーションなし) は、インデックスプロセスによってプロパティーが無視されることを意味します。@Field はプロパティーをインデックスとして宣言し、以下の属性のいずれかを設定してインデックスプロセスの複数の側面を設定できます。
  • name: プロパティーがどの名前下で、Lucene Document に保存されるべきかを説明します。デフォルト値はプロパティー名です (続く JavaBeans 規則)。
  • store: プロパティーが Lucene インデックスに保存されているかどうかを示します。Store.YES の値 (インデックスに多くの領域が必要ですが projection を許可 「プロジェクション」 を参照) を保存するか、これを圧縮方式 Store.COMPRESS で保存、あるいは、Store.NO を回避することができます (デフォルト値)。プロパティーが保存されると、Lucene ドキュメントから元の値を取得できます。これは、要素がインデックス化されるかどうかに関連しません。
  • index: プロパティーがインデックス化されるかどうかを示します。異なる値は、Index.NO (インデックス付けなし、つまりクエリーで見つけることができない)、Index.YES (要素にインデックスが付けられて検索可能) です。デフォルト値は Index.YES です。Index.NO は、プロパティーの検索が不可能であるものの、利用できる必要がある場合に便利です。
    注記
    Index.NOAnalyze.YES または Norms.YES と組み合わせると有用なわけではありません。これは、analyzenorms と解析のプロパティーのインデックス作成が必要ないためです。
  • analyze: プロパティーが分析されたかどうか (Analyze.YES) または (Analyze.NO) を判断します。デフォルト値は Analyze.YES です。
    注記
    プロパティーを分析するかどうかは、要素をそのまま0検索する場合と、含まれる単語で検索するかによって異なります。テキストフィールドを分析することは理にかなっていますが、日付フィールドは分析しません。
    注記
    ソートに使用されるフィールドは、分析できません
  • norms: インデックス時間の改善情報を保存する必要があるかどうか (Norms.YES) または (Norms.NO) を示します。これを保存しないと、大量のメモリーを節約できますが、インデックスの時間が改善する情報は提供されません。デフォルト値は Norms.YES です。
  • termVector: 用語と周波数のペア (term-frequency) のコレクションについて説明しています。この属性により、インデックス作成中にドキュメント内にベクターを保存することができます。デフォルト値は TermVector.NO です。
    この属性の異なる値は次のとおりです。
    定義
    TermVector.YES 各ドキュメントのTerm Vectors を保存します。これにより、同期されたアレイが作成され、これらはドキュメント用語が含まれ、他は用語の周波数が含まれます。
    TermVector.NO Term Vector は保存しないでください。
    TermVector.WITH_OFFSETS Term Verctor およびトークンオフセット情報を保存します。これは TermVector.YES と同様で、用語の開始および終了オフセット位置情報が含まれます。
    TermVector.WITH_POSITIONS Term Verctor およびトークン位置情報を保存します。これは TermVector.YES と同じですが、ドキュメント内の各用語の特徴も含まれます。
    TermVector.WITH_POSITION_OFFSETS Term Vector 、トークンの位置、およびオフセット情報を格納します。これは、YES、WITH_OFFSETS、および WITH_POSITIONS の組み合わせです。
  • indexNullAs: デフォルトの null 値ごとに無視され、インデックスは作成されません。ただし、indexNullAs を使用すると、null 値のトークンとして挿入される文字列を指定できます。デフォルトでは、この値はに設定されていますField.DO_NOT_INDEX_NULLそのことを示すnull値にインデックスを付けないでください。この値を次のように設定できますField.DEFAULT_NULL_TOKENデフォルトであることを示すnullトークンを使用する必要があります。このデフォルトの null トークンは、hibernate.search.default_null_token を使用して設定に指定できます。このプロパティーが設定されておらず、指定した場合Field.DEFAULT_NULL_TOKEN文字列 _null_ がデフォルトとして使用されます。
    注記
    indexNullAs パラメーターを使用する場合は、検索クエリーで同じトークンを使用して null 値を検索することが重要です。また、この機能は、非分析フィールド (analyze=Analyze.NO) でのみ使用することが推奨されます。
    警告
    カスタム FieldBridge または TwoWayFieldBridge を実装する場合、null 値のインデックス作成を処理するのは開発者の責任です (の JavaDocs を参照してください。LuceneOptions.indexNullAs())。
14.2.1.1.3. @NumericField
@Field には @NumericField というコンパニオンアノテーションがあり、@Field または @DocumentId と同じスコープで指定できます。このプロパティーは、Integer、Long、Float、および LastName プロパティーに指定できます。インデックスの作成時に、値は Trie 構造を使用してインデックス化されます。プロパティーを数字フィールドとしてインデックス化すると、標準的な @Field プロパティーに対して同じクエリーを実行するよりも、効率的な範囲クエリーとソートが可能になります。@NumericField アノテーションは以下のパラメーターを受け入れます。
定義
forField (オプション) 数値としてインデックス化される関連 @Field の名前を指定します。@Field 宣言を超えるプロパティーが含まれる場合にのみ必須となります。
precisionStep (オプション) インデックスに Trie 構造を格納する方法を変更します。precisionStes を小さくすると、ディスク領域の使用率が高くなり、範囲やソートのクエリーが速くなります。値が大きいほど使用領域が少なくなり、クエリーのパフォーマンスは通常の @Fields の範囲のクエリーに近づくことになります。デフォルト値は 4 です。
NumericField は、DoubleLongIntegerFloat のみをサポートしています。他の数値タイプには Lucene で同様の機能を活用できないため、残りのタイプはデフォルトまたはカスタムの TwoWayFieldBridge で文字列エンコーディングを使用する必要があります。
タイプ変換中に概算を処理できると仮定した場合は、カスタムの NumericFieldBridge を使用することができます。

例14.9 カスタム NumericFieldBridge の定義

public class BigDecimalNumericFieldBridge extends NumericFieldBridge {
   private static final BigDecimal storeFactor = BigDecimal.valueOf(100);

   @Override
   public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
      if ( value != null ) {
         BigDecimal decimalValue = (BigDecimal) value;
         Long indexedValue = Long.valueOf( decimalValue.multiply( storeFactor ).longValue() );
         luceneOptions.addNumericFieldToDocument( name, indexedValue, document );
      }
   }

    @Override
    public Object get(String name, Document document) {
        String fromLucene = document.get( name );
        BigDecimal storedBigDecimal = new BigDecimal( fromLucene );
        return storedBigDecimal.divide( storeFactor );
    }

}
14.2.1.1.4. @Id
最後に、エンティティーの id (identifier) プロパティーは、特定のエンティティーのインデックスを一意に保つために Hibernate Search で使用される特別なプロパティーです。設計上、id は保存する必要があり、トークン化しないでください。プロパティーをインデックス識別子としてマークするには、@DocumentId アノテーションを使用します。JPA を使用し、@Id を指定した場合は、@DocumentId を省略できます。選択したエンティティー ID は、ドキュメント識別子として使用されます。

例14.10 インデックス付きプロパティーの指定

@Entity
@Indexed
public class Essay {
    ...

    @Id
    @DocumentId
    public Long getId() { return id; }

    @Field(name="Abstract", store=Store.YES)
    public String getSummary() { return summary; }

    @Lob
    @Field
    public String getText() { return text; }

    @Field @NumericField( precisionStep = 6)
    public float getGrade() { return grade; }
}
例14.10「インデックス付きプロパティーの指定」 idAbstracttextgrade の 4 つのフィールドでインデックスを定義します。デフォルトでは、JavaBean 仕様にしたがってフィールド名は大文字では表示されないことに注意してください。Grade フィールドは、デフォルトよりも若干精度の高いステップで数字としてアノテーションが付けられます。

14.2.1.2. 複数回のプロパティーのマッピング

若干異なるインデックスストラテジーで、インデックスごとにプロパティーを複数回マップする必要がある場合があります。たとえば、フィールド別にクエリーを並び替えるには、フィールドを分析解除する必要があります。このプロパティーの単語で検索し、これをソートするには、分析後と未分析のときにインデックス付けする必要があります。これは、@Fields を使用することで可能です。

例14.11 @Fields を使用してプロパティーを複数回マップする

@Entity
@Indexed(index = "Book" )
public class Book {
    @Fields( {
            @Field,
            @Field(name = "summary_forSort", analyze = Analyze.NO, store = Store.YES)
            } )
    public String getSummary() {
        return summary;
    }

    ...
}
この例では、フィールの summary は 2 回インデックス化されます。これはトークン化方式の summary、非トークン化方式の summary_forSort で行われます。

14.2.1.3. 埋め込みおよび関連オブジェクト

関連オブジェクトおよび組み込みオブジェクトは、ルートエンティティーインデックスの一部としてインデックス化できます。これは、関連するオブジェクトのプロパティーに基づいて特定のエンティティーを検索する場合に役に立ちます。例14.12「インデックスアソシエーション」 関連する都市が Atlanta である場所を返すことを目的としています (Lucene クエリーパーサー言語で、address.city:Atlanta に変換されます)。場所フィールドは、Place インデックスでインデックス化されます。Placement インデックスドキュメントには、クエリー可能な address.idaddress.streetaddress.city フィールドも含まれます。

例14.12 インデックスアソシエーション

@Entity
@Indexed
public class Place {
    @Id
    @GeneratedValue
    @DocumentId
    private Long id;

    @Field
    private String name;

    @OneToOne( cascade = { CascadeType.PERSIST, CascadeType.REMOVE } )
    @IndexedEmbedded
    private Address address;
    ....
}

@Entity
public class Address {
    @Id
    @GeneratedValue
    private Long id;

    @Field
    private String street;

    @Field
    private String city;

    @ContainedIn
    @OneToMany(mappedBy="address")
    private Set<Place> places;
    ...
}
@IndexedEmbedded 技術を使用すると、データは Lucene インデックスで非正規化されるため、Hibernate Search は Place オブジェクトのすべての変更と、インデックスを最新の状態に保つため Address オブジェクトの変更を認識する必要があります。Place Lucene ドキュメントが Address の変更時に更新されるようにするには、双方向関係の反対側に @ContainedIn のマークを付けます。
注記
@ContainedIn はエンティティーを参照する関連付けや、組み込み (コレクション) オブジェクトを参照する関連付けで役立ちます。
この例を展開するために、以下の例では @IndexedEmbedded のネスト化を示しています。

例14.13 @IndexedEmbedded および @ContainedIn のネスト化された使用方法

@Entity
@Indexed
public class Place {
    @Id
    @GeneratedValue
    @DocumentId
    private Long id;

    @Field
    private String name;

    @OneToOne( cascade = { CascadeType.PERSIST, CascadeType.REMOVE } )
    @IndexedEmbedded
    private Address address;
    ....
}

@Entity
public class Address {
    @Id
    @GeneratedValue
    private Long id;

    @Field
    private String street;

    @Field
    private String city;

    @IndexedEmbedded(depth = 1, prefix = "ownedBy_")
    private Owner ownedBy;

    @ContainedIn
    @OneToMany(mappedBy="address")
    private Set<Place> places;
    ...
}

@Embeddable
public class Owner {
    @Field
    private String name;
   ...
}
@*ToMany, @*ToOne および @Embedded 属性は、@IndexedEmbedded アノテーションを付けることができます。その後、関連クラスの属性が主なエンティティーインデックスに追加されます。例14.13「@IndexedEmbedded および @ContainedIn のネスト化された使用方法」 インデックスには以下のフィールドが含まれます。
  • id
  • name
  • address.street
  • address.city
  • address.ownedBy_name
デフォルトの接頭辞は propertyName.で、従来のオブジェクトナビゲーション規則に従います。ownedBy プロパティーに示されるように、prefix 属性を使用して上書きできます。
注記
接頭辞を空の文字列に設定することはできません。
depth プロパティーは、オブジェクトグラフにクラス (インスタンスではない) の cyclic 依存関係が含まれるときに必要になります。たとえば、OwnerPlace をポイントする場合です。Hibernate Search は、予想される深さに達すると (またはオブジェクトグラフの境界に到達する)、インデックス化された組み込み属性を含まなくなります。自己参照を持つクラスは、cyclic 依存関係の例です。この例では、depth が 1 に設定されているため、Owner の @IndexedEmbedded 属性は無視されます。
オブジェクト関連付けに @IndexedEmbedded を使用すると、以下のようなクエリーを表現できます (Lucene のクエリー構文を使用)。
  • 名前に JBoss が含まれ、住所の都市がアトランタである場所を返します。Lucene クエリーでは、以下のようになります。
    +name:jboss +address.city:atlanta
  • 名前に JBoss が含まれ、所有者の名前に Joe が含まれる場所を返します。Lucene クエリーでは、以下のようになります。
    +name:jboss +address.ownedBy_name:joe
この動作は、より効率的な方法 (データの重複が犠牲となる) でのリレーショナルジョイン操作の操作に似ています。初期状態の Lucene インデックスには関連付けの概念がないため、join 操作が存在しないことに注意してください。これは、完全なテキストインデックスの速度と機能が充実した状態で、リレーショナルデータベースを維持するのに役立ちます。
注記
関連付けられたオブジェクトは、@Indexed にすることができます (ただし、必須ではありません)。
@IndexedEmbedded がエンティティーを参照する場合、関連付けには指向性が必要で、反対側にはアノテーション @ContainedIn を付ける必要があります (前述の例を参照)。これがない場合、Hibernate Search は関連エンティティーの更新時にルートインデックスを更新することはできません (この例では、関連付けられた Address インスタンスの更新時に Place インデックスドキュメントを更新する必要があります)。
@IndexedEmbedded アノテーションが付けられたオブジェクトタイプは、Hibernate および Hibernate Search によってターゲットに設定されたオブジェクトタイプではない場合があります。これは、インターフェースが実装の代わりに使用される場合にとくに当てはまります。このため、Hibernate Search の対象となるオブジェクトタイプを、targetElementパラメーター。

例14.14 @IndexedEmbeddedtargetElementプロパティーの使用

@Entity
@Indexed
public class Address {
    @Id
    @GeneratedValue
    @DocumentId
    private Long id;

    @Field
    private String street;

    @IndexedEmbedded(depth = 1, prefix = "ownedBy_", targetElement = Owner.class)
    @Target(Owner.class)
    private Person ownedBy;


    ...
}

@Embeddable
public class Owner implements Person { ... }

14.2.1.4. 特定のパスへのオブジェクト埋め込みの制限

@IndexedEmbedded アノテーションは属性も提供しますincludePathsの代わりに使用できますdepth、またはそれと組み合わせる。
depth のみを使用すると、埋め込み型のインデックス設定されたフィールドはすべて、同じデプスで再帰的に追加されます。これにより、他のフィールドもすべて追加せずに特定のパスのみを選択することが困難になります。これは必須ではありません。
不要な読み込みおよびインデックスエンティティーを回避するには、必要なパスを正確に指定することができます。通常のアプリケーションでは、パスごとに異なるデプスが必要な場合や、例14.15「@IndexedEmbeddedincludePaths プロパティーの使用」 のようにパスを明示的に指定する必要がある場合があります。

例14.15 @IndexedEmbeddedincludePaths プロパティーの使用

@Entity
@Indexed
public class Person {

   @Id
   public int getId() {
      return id;
   }

   @Field
   public String getName() {
      return name;
   }

   @Field
   public String getSurname() {
      return surname;
   }

   @OneToMany
   @IndexedEmbedded(includePaths = { "name" })
   public Set<Person> getParents() {
      return parents;
   }

   @ContainedIn
   @ManyToOne
   public Human getChild() {
      return child;
   }

    ...//other fields omitted
のようにマッピングを使用する例14.15「@IndexedEmbeddedincludePaths プロパティーの使用」名前 や名前、および/または 名前人物 を検索できます。親の surname をインデックス化しないため、親の surname を検索することはできません。ただし、インデックス作成を迅速化し、スペースを節約して、全体的なパフォーマンスを向上させることができます。
@IndexedEmbeddedincludePaths制限された値を指定して通常インデックスを作成 するものに加えて、指定されたパスが含まれますdepth。使用する場合includePaths、そして去るdepth未定義、動作は設定と同等ですdepth= 0: 含まれているパスのみにインデックスが付けられます。

例14.16 @IndexedEmbeddedincludePaths プロパティーの使用

@Entity
@Indexed
public class Human {

   @Id
   public int getId() {
      return id;
   }

   @Field
   public String getName() {
      return name;
   }

   @Field
   public String getSurname() {
      return surname;
   }

   @OneToMany
   @IndexedEmbedded(depth = 2, includePaths = { "parents.parents.name" })
   public Set<Human> getParents() {
      return parents;
   }

   @ContainedIn
   @ManyToOne
   public Human getChild() {
      return child;
   }

    ...//other fields omitted
例14.16「@IndexedEmbeddedincludePaths プロパティーの使用」、すべての人間の名前と名前の属性にインデックスが付けられます。また、depth 属性が原因で、親の名前と surname (姓) も再帰的に 2 行目にインデックス化されます。人が直接、自身の親、または親の名前で検索することができます。第 2 レベル以外では、姓 (surname) ではなく、もう 1 レベル (名前のみ) をインデックス化します。
これにより、インデックスに以下のフィールドが生成されます。
  • id - プライマリーキーとして
  • _hibernate_class - エンティティータイプを保存
  • name - 直接フィールドとして
  • surname - 直接フィールドとして
  • parents.name - デプス 1 の埋め込みフィールドとして
  • parents.surname - デプス 1 の埋め込みフィールドとして
  • parents.parents.name: デプス 2 の埋め込みフィールドとして
  • parents.parents.surname - デプス 2 の埋め込みフィールドとして
  • 親.parents.parents.name- によって指定された追加のパスとしてincludePaths。最初の parents. はフィールド名から推測され、残りのパスは includePaths の属性です。
インデックス化されたパスを明示的に制御することは、必要なクエリーを最初に定義してアプリケーションを設計する場合に容易になる可能性があります。この時点では、どのフィールドが必要かを正確に把握している可能性もあります。その他のどのフィールドがユースケースを実装する必要はありません。
Red Hat logoGithubRedditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

© 2024 Red Hat, Inc.