Cassandra 固有のクエリメソッド

この章では、Cassandra 固有のクエリメソッドについて説明します。このドキュメントでは命令型を使用します。リアクティブな戻り値の型を使用すると、同じセマンティクスがリアクティブリポジトリにも適用されます。

通常、リポジトリでトリガーするデータアクセス操作のほとんどは、Apache Cassandra データベースに対して実行されるクエリになります。このようなクエリを定義するには、リポジトリインターフェースでメソッドを宣言します。次の例は、このようなメソッド宣言をいくつか示しています。

PersonRepository とクエリメソッド
  • 命令的

  • リアクティブ

interface PersonRepository extends CrudRepository<Person, String> {

    List<Person> findByLastname(String lastname);                           (1)

    Slice<Person> findByFirstname(String firstname, Pageable pageRequest);  (2)

    Window<Person> findByFirstname(String firstname, CassandraScrollPosition pos, Limit limit);  (3)

    List<Person> findByFirstname(String firstname, QueryOptions opts);      (4)

    List<Person> findByFirstname(String firstname, Sort sort);              (5)

    List<Person> findByFirstname(String firstname, Limit limit);            (6)

    Person findByShippingAddress(Address address);                          (7)

    Person findFirstByShippingAddress(Address address);                     (8)

    Stream<Person> findAllBy();                                             (9)

    @AllowFiltering
    List<Person> findAllByAge(int age);                                     (10)
}
1 このメソッドは、指定された lastname を持つすべての人々に対するクエリを示します。クエリは、制約のメソッド名を解析して派生し、And と連結できます。メソッド名は SELECT * FROM person WHERE lastname = 'lastname' というクエリ式になります。
2 クエリにページネーションを適用します。メソッドシグネチャーに Pageable パラメーターを指定して、メソッドが Slice インスタンスを返すようにすると、それに応じてクエリが自動的にページングされます。
3 クエリにスクロールを適用します。スクロールすると、Cassandra の PagingState が CassandraScrollPosition にラップされ、動的制限が可能になります。findTop …  を静的制限に使用することもできます。
4QueryOptions オブジェクトを渡すと、実行前に結果のクエリにクエリオプションが適用されます。
5 クエリに動的並べ替えを適用します。Sort パラメーターをメソッドシグネチャーに追加すると、Spring Data によってクエリに順序付けが自動的に適用されます。
6 動的結果制限をクエリに適用します。SELECT … LIMIT を使用してクエリ結果を制限できます。
7CustomConversions に登録された Converter インスタンスを使用して、プリミティブ型ではないプロパティに基づいてクエリを実行できることを示します。複数の一致が見つかった場合は、IncorrectResultSizeDataAccessException をスローします。
8First キーワードを使用して、クエリを最初の結果のみに制限します。前述のメソッドとは異なり、このメソッドは、複数の一致が見つかった場合でも例外をスローしません。
9Java 8 Stream を使用して、ストリームを反復しながら個々の要素を読み取り、変換します。
10 サーバー側のフィルタリングを可能にするために、@AllowFiltering アノテーションが付けられたクエリメソッドを示します。
interface ReactivePersonRepository extends ReactiveSortingRepository<Person, Long> {

  Flux<Person> findByFirstname(String firstname);                                (1)

  Flux<Person> findByFirstname(Publisher<String> firstname);                     (2)

  Mono<Person> findByFirstnameAndLastname(String firstname, String lastname);    (3)

  Mono<Person> findFirstByFirstname(String firstname);                           (4)

  @AllowFiltering
  Flux<Person> findByAge(int age);                                               (5)
}
1 指定された firstname を持つすべての人々に対するクエリ。クエリは、制約のメソッド名を解析することによって導出されます。制約は And および Or と連結できます。メソッド名は SELECT * FROM person WHERE firstname = :firstname というクエリ式になります。
2 指定された Publisher から firstname が発行された後の、指定された firstname を持つすべての人々に対するクエリ。
3 指定された条件を満たす単一のエンティティを検索します。固有でない結果の場合は IncorrectResultSizeDataAccessException で完了します。
4 前述のクエリとは異なり、クエリによってさらに多くの結果行が生成された場合でも、最初のエンティティが常に出力されます。
5@AllowFiltering アノテーションが付けられたクエリメソッド。これにより、サーバー側のフィルタリングが可能になります。
主キー以外のプロパティをクエリするには、セカンダリインデックスが必要です。

次の表は、クエリメソッドで使用できるキーワードの短い例を示しています。

表 1: クエリメソッドでサポートされるキーワード
キーワード サンプル 論理的な結果

After

findByBirthdateAfter(Date date)

birthdate > date

GreaterThan

findByAgeGreaterThan(int age)

age > age

GreaterThanEqual

findByAgeGreaterThanEqual(int age)

age >= age

Before

findByBirthdateBefore(Date date)

birthdate < date

LessThan

findByAgeLessThan(int age)

age < age

LessThanEqual

findByAgeLessThanEqual(int age)

age ⇐ age

Between

findByAgeBetween(int from, int to) and findByAgeBetween(Range<Integer> range)

age > from AND age < to and lower / upper bounds (> / >= & < / ) according to Range

In

findByAgeIn(Collection ages)

age IN (ages…​)

Like, StartingWith, EndingWith

findByFirstnameLike(String name)

firstname LIKE (name as like expression)

Containing on String

findByFirstnameContaining(String name)

firstname LIKE (name as like expression)

Containing on Collection

findByAddressesContaining(Address address)

addresses CONTAINING address

(No keyword)

findByFirstname(String name)

firstname = name

IsTrue, True

findByActiveIsTrue()

active = true

IsFalse, False

findByActiveIsFalse()

active = false

リポジトリ削除クエリ

前の表のキーワードを delete … By と組み合わせて使用すると、一致するドキュメントを削除するクエリを作成できます。

  • 命令的

  • リアクティブ

interface PersonRepository extends Repository<Person, String> {

  void deleteWithoutResultByLastname(String lastname);

  boolean deleteByLastname(String lastname);
}
interface PersonRepository extends Repository<Person, String> {

  Mono<Void> deleteWithoutResultByLastname(String lastname);

  Mono<Boolean> deleteByLastname(String lastname);
}

削除クエリは、クエリが適用されたかどうかを返すか、void を使用して値を返さずに終了します。

クエリオプション

QueryOptions オブジェクトを渡すことで、クエリメソッドのクエリオプションを指定できます。オプションは、実際のクエリの実行前にクエリに適用されます。QueryOptions は非クエリパラメーターとして扱われ、クエリパラメーター値とは見なされません。クエリオプションは、派生および文字列 @Query リポジトリメソッドに適用されます。

整合性レベルを静的に設定するには、クエリメソッドで @Consistency アノテーションを使用します。宣言された整合性レベルは、クエリが実行されるたびにクエリに適用されます。次の例では、整合性レベルを ConsistencyLevel.LOCAL_ONE に設定します。

  • 命令的

  • リアクティブ

interface PersonRepository extends CrudRepository<Person, String> {

    @Consistency(ConsistencyLevel.LOCAL_ONE)
    List<Person> findByLastname(String lastname);

    List<Person> findByFirstname(String firstname, QueryOptions options);
}
interface PersonRepository extends ReactiveCrudRepository<Person, String> {

    @Consistency(ConsistencyLevel.LOCAL_ONE)
    Flux<Person> findByLastname(String lastname);

    Flux<Person> findByFirstname(String firstname, QueryOptions options);
}

DataStax Cassandra のドキュメントには利用可能な整合性レベルについての十分な議論 (英語) が含まれています。

CQL API インスタンスでパラメーター CqlTemplateAsyncCqlTemplateReactiveCqlTemplate を構成することで、フェッチサイズ、整合性レベル、再試行ポリシーのデフォルトを制御できます。特定のクエリオプションが設定されていない場合は、デフォルトが適用されます。