查询 Cloud Datastore 中的嵌入式实体

Querying embedded entities in Cloud Datastore

我有几个关于在 Datastore 中使用嵌入式实体的问题。

考虑以下简单测试用例:

Entity entity = new Entity("Person");

entity.setProperty("name", "Alice");
EmbeddedEntity address = new EmbeddedEntity();
address.setProperty("streetAddress", "100 Main Street");
address.setProperty("addressLocality", "Springfield");
address.setProperty("addressRegion", "VA");

entity.setProperty("address", address);

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
datastore.put(entity);

Query query = new Query("Person");
FilterPredicate regionFilter = 
    new FilterPredicate("address.addressRegion", FilterOperator.EQUAL, "VA");
query.setFilter(regionFilter);

List<Entity> results = datastore.prepare(query)
    .asList(FetchOptions.Builder.withDefaults());

assertEquals(1, results.size());

这个测试失败了;结果集为空。

这是我的问题:

  1. 我是否正确使用了 FilterPredicate?该文档没有解释如何引用 EmbeddedEntity 的属性。我猜约定是使用点分隔的路径。但也许这是不正确的。
  2. 我的测试用例是否需要为嵌入地址实体中的子属性声明索引?如果是,怎么做?

Datastore documentation 包含以下语句:

"When an embedded entity is included in indexes, you can query on subproperties."

我按照 Local Unit Testing 文章中关于 Java 的说明进行操作,但文章中没有任何内容解释如何在 JUnit 测试中定义索引。

由于最终一致性,此测试不稳定。

由于您没有执行祖先查询,因此查询使用最终一致的索引 (SELECT * FROM Person WHERE address.addressRegion = "VA")。不保证插入和查询命中同一个副本,也不保证 address.addressRegion 已更新。

默认情况下,嵌入式实体应该被索引,所以这不是问题。

最终一致性通常在几毫秒内解决,但由于您正在立即编写和查询,因此您命中它的机会会增加。

您可以采用 2 种策略来减少测试的不稳定性。

1。睡觉

在 put 和查询之间添加 1 或 2 秒的休眠将减少测试的脆弱性,但不会消除它 - 可能是合理的第一步。我没有 运行 你的代码乍一看似乎是正确的。

2。强制应用索引写入

Cloud Datastore 将实体同步写入多数副本,但在此步骤之后异步应用索引 - 这会导致某些查询的最终一致性。

您可以通过执行相关实体的读取来强制应用索引。读取实体时,将检查实体组的写入日志以查看是否有任何待应用的未完成写入 - 如果有,则强制在读取之前应用它们。您可以在单元测试中使用此机制来减少最终一致性问题。

杂项

此外,要验证实体是否按预期编写,您可以跳转到云控制台并从上方执行 GQL 语句。