インデックスの作成

Spring Data MongoDB は、@Document のアノテーションが付けられたエンティティ型のインデックスを自動的に作成できます。バージョン 3.0 以降では、コレクションのライフサイクルやパフォーマンスへの望ましくない影響を防ぐために、インデックスの作成を明示的に有効にする必要があります。インデックスは、アプリケーションの起動時、およびアプリケーションの実行中に初めてエンティティ型にアクセスしたときに、初期エンティティセットに対して自動的に作成されます。

Spring Data はアプリケーションの実行中に再作成されたコレクションのインデックスを自動的に作成できないため、アプリケーションベースのインデックスの制御には、通常、明示的なインデックスの作成をお勧めします。

IndexResolver は、@GeoSpatialIndexed@TextIndexed@CompoundIndex@WildcardIndexed などの @Indexed アノテーションを使用する場合に、プログラムによるインデックス定義作成の抽象化を提供します。IndexOperations でインデックス定義を使用してインデックスを作成できます。インデックス作成の適切な時点は、アプリケーションの起動時、特に ContextRefreshedEvent の監視によってトリガーされてアプリケーションコンテキストがリフレッシュされた後です。このイベントは、コンテキストが完全に初期化されていることを保証します。現時点では、他のコンポーネント、特に Bean ファクトリが MongoDB データベースにアクセスできる可能性があることに注意してください。

Map - マップキーはインデックス定義の一部である必要があるため、@WildcardIndexed のアノテーションが付けられていない限り、同様のプロパティは IndexResolver によってスキップされます。マップの目的は動的なキーと値を使用することであるため、静的なマッピングメタデータからキーを解決することはできません。

例 1: 単一のドメイン型に対するプログラムによるインデックスの作成
class MyListener {

  @EventListener(ContextRefreshedEvent.class)
  public void initIndicesAfterStartup() {

    MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext = mongoTemplate
                .getConverter().getMappingContext();

    IndexResolver resolver = new MongoPersistentEntityIndexResolver(mappingContext);

    IndexOperations indexOps = mongoTemplate.indexOps(DomainType.class);
    resolver.resolveIndexFor(DomainType.class).forEach(indexOps::ensureIndex);
  }
}
例 2: すべての初期エンティティに対するプログラムによるインデックス作成
class MyListener{

  @EventListener(ContextRefreshedEvent.class)
  public void initIndicesAfterStartup() {

    MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext = mongoTemplate
        .getConverter().getMappingContext();

    // consider only entities that are annotated with @Document
    mappingContext.getPersistentEntities()
                            .stream()
                            .filter(it -> it.isAnnotationPresent(Document.class))
                            .forEach(it -> {

    IndexOperations indexOps = mongoTemplate.indexOps(it.getType());
    resolver.resolveIndexFor(it.getType()).forEach(indexOps::ensureIndex);
    });
  }
}

あるいは、コンポーネントがアプリケーションからデータベースにアクセスできるようになる前にインデックスとコレクションの存在を確認したい場合は、MongoTemplate の @Bean メソッドを宣言し、MongoTemplate オブジェクトを返す前に上記のコードを含めます。

自動インデックス作成をオンにするには、構成で autoIndexCreation() をオーバーライドしてください。

@Configuration
public class Config extends AbstractMongoClientConfiguration {

  @Override
  public boolean autoIndexCreation() {
    return true;
  }

// ...
}
バージョン 3.0 では、自動インデックス作成はデフォルトでオフになっています。

複合インデックス

複合インデックスもサポートされています。これらは、個々のプロパティではなく、クラスレベルで定義されます。

複合インデックスは、複数のフィールドの条件を含むクエリのパフォーマンスを向上させるために非常に重要です。

以下は、昇順で lastName と降順で age の複合インデックスを作成する例です。

例 3: 複合インデックスの使用例
package com.mycompany.domain;

@Document
@CompoundIndex(name = "age_idx", def = "{'lastName': 1, 'age': -1}")
public class Person {

  @Id
  private ObjectId id;
  private Integer age;
  private String firstName;
  private String lastName;

}

@CompoundIndex は、@CompoundIndexes をコンテナーとして使用して反復可能です。

@Document
@CompoundIndex(name = "cmp-idx-one", def = "{'firstname': 1, 'lastname': -1}")
@CompoundIndex(name = "cmp-idx-two", def = "{'address.city': -1, 'address.street': 1}")
public class Person {

  String firstname;
  String lastname;

  Address address;

  // ...
}

ハッシュ化されたインデックス

ハッシュインデックスを使用すると、シャードクラスター内でハッシュベースのシャーディングが可能になります。ハッシュフィールド値を使用してコレクションをシャーディングすると、よりランダムな分布が得られます。詳細は MongoDB ドキュメント (英語) をご参照ください。

_id のハッシュインデックスを作成する例を次に示します。

例 4: ハッシュ化インデックスの使用例
@Document
public class DomainType {

  @HashIndexed @Id String id;

  // ...
}

ハッシュインデックスは、以下に示すように他のインデックス定義の隣に作成できます。その場合、両方のインデックスが作成されます。

例 5: 単純なインデックスと組み合わせたハッシュインデックスの使用例
@Document
public class DomainType {

  @Indexed
  @HashIndexed
  String value;

  // ...
}

上記の例が冗長すぎる場合は、複合アノテーションを使用して、プロパティで宣言する必要があるアノテーションの数を減らすことができます。

例 6: 合成ハッシュインデックスの使用例
@Document
public class DomainType {

  @IndexAndHash(name = "idx...")                            (1)
  String value;

  // ...
}

@Indexed
@HashIndexed
@Retention(RetentionPolicy.RUNTIME)
public @interface IndexAndHash {

  @AliasFor(annotation = Indexed.class, attribute = "name") (1)
  String name() default "";
}
1 メタアノテーションの特定の属性のエイリアスを登録する可能性があります。

アノテーションによるインデックスの作成は多くのシナリオで便利ですが、IndexOperations を介してインデックスを手動で設定することで、より詳細な制御を引き継ぐことも考えられます。

mongoOperations.indexOpsFor(Jedi.class)
  .ensureIndex(HashedIndex.hashed("useTheForce"));

ワイルドカードインデックス

WildcardIndex は、指定された (ワイルドカード) パターンに基づいてすべてのフィールドまたは特定のフィールドを含めるために使用できるインデックスです。詳細は MongoDB ドキュメント (英語) をご参照ください。

インデックスは、WildcardIndex 経由 IndexOperations を使用してプログラムで設定できます。

例 7: プログラムによる WildcardIndex セットアップ
mongoOperations
    .indexOps(User.class)
    .ensureIndex(new WildcardIndex("userMetadata"));
db.user.createIndex({ "userMetadata.$**" : 1 }, {})

@WildcardIndex アノテーションを使用すると、ドキュメント型またはプロパティのいずれかで使用できる宣言的なインデックスのセットアップが可能になります。

ルートレベルのドメインエンティティ ( @Document アノテーションが付けられたもの) である型に配置された場合、インデックスリゾルバーはそのワイルドカードインデックスを作成します。

例 8: ドメイン型のワイルドカードインデックス
@Document
@WildcardIndexed
public class Product {
	// …
}
db.product.createIndex({ "$**" : 1 },{})

wildcardProjection を使用して、インデックスに含める / 除外するキーを指定できます。

例 9: wildcardProjection を使用したワイルドカードインデックス
@Document
@WildcardIndexed(wildcardProjection = "{ 'userMetadata.age' : 0 }")
public class User {
    private @Id String id;
    private UserMetadata userMetadata;
}
db.user.createIndex(
  { "$**" : 1 },
  { "wildcardProjection" :
    { "userMetadata.age" : 0 }
  }
)

ワイルドカードインデックスは、フィールドにアノテーションを直接追加することによっても表現できます。wildcardProjection はプロパティなどのネストされたパスでは許可されないことに注意してください。@WildcardIndexed アノテーションが付けられた型の射影は、インデックスの作成時に省略されます。

例 10: プロパティのワイルドカードインデックス
@Document
public class User {
    private @Id String id;

    @WildcardIndexed
    private UserMetadata userMetadata;
}
db.user.createIndex({ "userMetadata.$**" : 1 }, {})

テキストインデックス

MongoDB v.2.4 では、テキストインデックス機能はデフォルトで無効になっています。

テキストインデックスを作成すると、複数のフィールドを検索可能なフルテキストインデックスに蓄積できます。コレクションごとに 1 つのテキストインデックスのみを持つことができるため、@TextIndexed でマークされたすべてのフィールドがこのインデックスに結合されます。プロパティに重みを付けて、ランキング結果のドキュメントスコアに影響を与えることができます。テキストインデックスのデフォルト言語は English.To です。デフォルト言語を変更するには、language 属性を任意の言語 (たとえば、@Document(language="spanish")) に設定します。language または @Language というプロパティを使用すると、ドキュメントごとに言語オーバーライドを定義できます。次の例は、テキストインデックスを作成し、言語をスペイン語に設定する方法を示しています。

例 11: テキストインデックスの使用例
@Document(language = "spanish")
class SomeEntity {

    @TextIndexed String foo;

    @Language String lang;

    Nested nested;
}

class Nested {

    @TextIndexed(weight=5) String bar;
    String roo;
}