射影クエリ

ほとんどの Cloud Datastore クエリでは結果としてエンティティ全体が返されますが、多くの場合、アプリケーションが必要とするのはエンティティのプロパティの一部分だけです。射影クエリを使用すると、エンティティのプロパティの中で本当に必要なものだけをクエリできるため、エンティティ全体を取得する場合よりもレイテンシとコストを低く抑えられます。

射影クエリは、次のような形式の SQL クエリと似ています。

SELECT name, email, phone FROM CUSTOMER

標準的なエンティティ クエリで使用できるフィルタリングや並べ替えの機能はすべて使用できます。制限事項については、以降で説明するとおりです。このクエリでは要約された結果が返されます。指定したプロパティ(この例では nameemailphone)だけに値が格納され、その他すべてのプロパティにはデータは格納されません。

Java での射影クエリの使用

射影クエリを作成するには、Query オブジェクトを作成し、addProjection() メソッドを使用してそのオブジェクトにプロパティを追加します。

Java 8

private void addGuestbookProjections(Query query) {
  query.addProjection(new PropertyProjection("content", String.class));
  query.addProjection(new PropertyProjection("date", Date.class));
}

Java 7

private void addGuestbookProjections(Query query) {
  query.addProjection(new PropertyProjection("content", String.class));
  query.addProjection(new PropertyProjection("date", Date.class));
}

各プロパティに指定する型は、最初に Entity.setProperty() でプロパティを定義したときに使用した型と一致する必要があります。次の例は、返されるエンティティのリストを反復処理し、各プロパティの値を期待される型にキャストすることによって、クエリの結果を処理する方法を示しています。

Java 8

private void printGuestbookEntries(DatastoreService datastore, Query query, PrintWriter out) {
  List<Entity> guests = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(5));
  for (Entity guest : guests) {
    String content = (String) guest.getProperty("content");
    Date stamp = (Date) guest.getProperty("date");
    out.printf("Message %s posted on %s.\n", content, stamp.toString());
  }
}

Java 7

private void printGuestbookEntries(DatastoreService datastore, Query query, PrintWriter out) {
  List<Entity> guests = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(5));
  for (Entity guest : guests) {
    String content = (String) guest.getProperty("content");
    Date stamp = (Date) guest.getProperty("date");
    out.printf("Message %s posted on %s.\n", content, stamp.toString());
  }
}

グループ化(試験運用)

射影クエリでは setDistinct() メソッドを使用すると、完全に一意の結果のみが結果セットで返されます。つまり、プロジェクションされているプロパティについて同じ値を持つエンティティが複数存在する場合は、最初の結果だけが返されます。

Java 8

Query q = new Query("TestKind");
q.addProjection(new PropertyProjection("A", String.class));
q.addProjection(new PropertyProjection("B", Long.class));
q.setDistinct(true);
q.setFilter(Query.FilterOperator.LESS_THAN.of("B", 1L));
q.addSort("B", Query.SortDirection.DESCENDING);
q.addSort("A");

Java 7

Query q = new Query("TestKind");
q.addProjection(new PropertyProjection("A", String.class));
q.addProjection(new PropertyProjection("B", Long.class));
q.setDistinct(true);
q.setFilter(Query.FilterOperator.LESS_THAN.of("B", 1L));
q.addSort("B", Query.SortDirection.DESCENDING);
q.addSort("A");

射影の制限

射影クエリには次のような制限があります。

  • インデックス付けされたプロパティだけを射影できる。

    インデックスに登録されていないプロパティでは、明示的にも暗黙的にも射影はサポートされません。長いテキスト文字列(Text)と長いバイト文字列(Blob)はインデックスに登録されません。

  • 同じプロパティは複数回射影できない

  • 等式(EQUAL)またはメンバー(IN)フィルタは射影できない

    例:

    SELECT A FROM kind WHERE B = 1
    

    は有効です(射影されたプロパティが等式フィルタで使用されていないため)。同様に、

    SELECT A FROM kind WHERE A > 1
    

    も有効です(等式フィルタではないため)。ただし、

    SELECT A FROM kind WHERE A = 1
    

    は無効です(射影されたプロパティが等式フィルタで使用されているため)。

  • 射影クエリから返された結果を Cloud Datastore に再保存するべきではない

    このようなクエリでは部分的に格納された結果しか返されないため、Cloud Datastore に書き戻すべきではありません。

射影と複数の値を持つプロパティ

複数の値を持つプロパティを射影しても、そのプロパティのすべての値が格納されるわけではありません。その代わり、クエリに一致する射影された値の一意の組み合わせごとに個別のエンティティが返されます。たとえば、複数の値を持つ 2 つのプロパティ AB が設定された Foo という種類のエンティティがあるとします。

entity = Foo(A=[1, 1, 2, 3], B=['x', 'y', 'x'])

この状況で、次の射影クエリを実行します。

SELECT A, B FROM Foo WHERE A < 3

この場合、次の値の組み合わせを持つ 4 つのエンティティが返されます。

A = 1B = 'x'
A = 1B = 'y'
A = 2B = 'x'
A = 2B = 'y'

射影のインデックス

射影クエリでは、射影で指定されているすべてのプロパティが Cloud Datastore のインデックスに含まれるようにする必要があります。App Engine 開発用サーバーを使用すると、インデックス設定ファイル datastore-indexes-auto.xml で必要なインデックスが自動的に作成されます。このファイルはアプリケーションと一緒にアップロードされます。

必要なインデックスの数を最小限に抑える方法の 1 つとして、必ずしもすべてが必要でない場合であっても、同じ複数のプロパティを一貫して射影するという方法が挙げられます。たとえば、次のクエリはそれぞれ個別のインデックスを必要とします。

SELECT A, B FROM Kind
SELECT A, B, C FROM Kind

ただし、C が必要でないときでもプロパティ ABC を常に射影する場合は、1 つのインデックスのみ必要になります。

射影のプロパティがクエリの別の部分に含まれていない場合、既存のクエリを射影クエリに変換する際に新しいインデックスを構築しなければならない場合があります。たとえば、次のような既存のクエリがあるとします。

SELECT * FROM Kind WHERE A > 1 ORDER BY A, B

必要なインデックスは次のとおりです。

Index(Kind, A, B)

このクエリを次のいずれかの射影クエリに変換します。

SELECT C FROM Kind WHERE A > 1 ORDER BY A, B
SELECT A, B, C FROM Kind WHERE A > 1 ORDER BY A, B

新しいプロパティ(C)が取り入れられるため、新しいインデックス Index(Kind, A, B, C) を作成する必要があります。次の射影クエリ

SELECT A, B FROM Kind WHERE A > 1 ORDER BY A, B

では必要なインデックスは変わりません。これは、射影されるプロパティ AB が既存のクエリにすでに含まれているためです。

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

Java の App Engine スタンダード環境