Single Property Indexを作らないとComposite Indexも作成されない?

昨日行われたappengine ja night #9で話題になった次の二つについて試してみました。

  • プロパティa、bに対してSingle Property Indexは作らずにComposite Indexだけを作った場合、a=1、b=2、c=3のようなフィルタを使えばComposite Index + ZigZag Scanを試せるんじゃないか。
  • プロパティa、bに対してSingle Property Indexは作らずにComposite Indexだけを作った場合、a=1のようなaだけを使ったフィルタは機能するか。

結果

Single Property Indexを作らなかったEntityは、Composite Indexテーブルに登録されないように見えます。下記コードの三つのQueryの結果はすべて空でした。Entity#setUnindexedPropertyメソッドを利用した場合は、Composite Indexも含めてIndexテーブルに書き込む処理が省略されているのかもしれません。

実行結果はこちら。何も出てこないのでまったく面白くないですがw

ソース

package org.koherent.appengine.ajn9;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.*;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;

@SuppressWarnings("serial")
public class CompositeIndexTestServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		response.setContentType("text/plain");
		response.setCharacterEncoding("UTF-8");

		DatastoreService datastore = DatastoreServiceFactory
				.getDatastoreService();
		List<Entity> entities = new ArrayList<Entity>();
		Entity entity;
		Query query;
		Iterable<Entity> results;
		PrintWriter out = response.getWriter();

		//////////////////////////////////////////////////////////////
		// (0) Preparation: Puts entities
		//     (The composite index for "a" and "b" exists)
		entity = new Entity("kind", "keyName1");
		entity.setUnindexedProperty("a", 1); // propertyName = "a", value = 1
		entity.setUnindexedProperty("b", 1);
		entity.setProperty("c", 3);
		entities.add(entity);

		entity = new Entity("kind", "keyName2");
		entity.setUnindexedProperty("a", 1);
		entity.setUnindexedProperty("b", 2);
		entity.setProperty("c", 3);
		entities.add(entity);

		entity = new Entity("kind", "keyName3");
		entity.setUnindexedProperty("a", 2);
		entity.setUnindexedProperty("b", 2);
		entity.setProperty("c", 3);
		entities.add(entity);

		datastore.put(entities);

		//////////////////////////////////////////////////////////////
		// (1) Combinations of the composite index and zigzag scan

		query = new Query("kind");
		query.addFilter("a", FilterOperator.EQUAL, 1); // composite index
		query.addFilter("b", FilterOperator.EQUAL, 2); // composite index
		query.addFilter("c", FilterOperator.EQUAL, 3); // zigzag scan

		results = datastore.prepare(query).asIterable();
		for (Entity result : results) {
			out.print("(1) ");
			out.println(result.getKey().getName()); // keyName2
		}

		//////////////////////////////////////////////////////////////
		// (2) Filtering by the first property of the composite index

		query = new Query("kind").addFilter("a", FilterOperator.EQUAL, 2);

		results = datastore.prepare(query).asIterable();
		for (Entity result : results) {
			out.print("(2) ");
			out.println(result.getKey().getName()); // keyName3
		}

		//////////////////////////////////////////////////////////////
		// (3) Must use the composite index
		query = new Query("kind");
		query.addFilter("a", FilterOperator.EQUAL, 2);
		query.addFilter("b", FilterOperator.GREATER_THAN_OR_EQUAL,
				Long.MIN_VALUE);
		query.addFilter("b", FilterOperator.LESS_THAN_OR_EQUAL,
				Long.MAX_VALUE);

		results = datastore.prepare(query).asIterable();
		for (Entity result : results) {
			out.print("(3) ");
			out.println(result.getKey().getName()); // keyName3
		}
	}
}
<?xml version="1.0" encoding="utf-8"?>
<datastore-indexes>
	<datastore-index kind="kind" ancestor="false">
		<property name="a" direction="asc" />
		<property name="b" direction="asc" />
	</datastore-index>
</datastore-indexes>

補足

最初からEntity#setUnindexedPropertyメソッドを使うとそもそもComposite Indexが作成すらされなかったので、一度Entity#setPropertyメソッドを使ってComposite Indexを作成させてから上記のコードに差し替えました。

当然ですが、Entity#setPropertyを使った場合は次のような結果になりました。

(1) keyName2
(2) keyName3
(3) keyName3