使用appengine数据存储区祖先路径进行高效搜索

时间:2014-10-13 10:53:26

标签: google-app-engine indexing google-cloud-datastore hierarchy objectify

我们有一个覆盖租赁,我需要根据索引属性范围和客户端ID搜索和获取一个巨大的appengine数据存储区。 Ancestor Paths的使用是否有效?或者可以使用额外的过滤器

来完成

e.g。通过客观化获得前100名工资

Key<Clients> clientIdKey = Key.create(Clients.class, 500)
ofy().load().type(Salaries.class).ancestor(clientIdKey).order("-salary").limit(100).list()

或者只是

ofy().load().type(Salaries.class).filter("clientId = ", 500 ).order("-salary").limit(100).list()

我的假设是,在第一种情况下,属于任何其他客户端的所有实体都将被忽略,但在以后的情况下,它将是全扫描,这将更加昂贵。这个假设是对的吗?

索引“salary”也是全局存储的,还是根据祖先进行分区,以便索引更新只发生在同一个祖先中?这将减少更新索引所需的时间,并且当我们永远不会在不同的客户端进行查询时,这将是一个很好的解决方案。

1 个答案:

答案 0 :(得分:4)

我需要指出的第一件事是数据存储区不进行表扫描。除了几个例外(最明显的是Z字形合并)之外,GAE查询只跟踪索引 - 所以通常这些问题归结为&#34;哪个索引更有效维护?&#34;

让我们先谈谈第二个案例(注意我已经单独化了薪水,我认为这是你的意图):

ofy().load().type(Salary.class).filter("clientId = ", 500 ).order("-salary").limit(100).list()

这需要Salary { clientId, salary } DESC上的多属性索引。 GAE将索引导航到Salary/clientId/500的开头,然后一次读取一个索引记录。它将在任意数据中心的索引表上执行此操作 - 并且由于这些索引表是异步复制的,因此最终会得到一致的结果。

为了让实体参与多属性索引,必须为每个单独的属性编制索引。如果Salary没有其他索引属性,则编写单个Salary将花费:

  • 1为实体操作写
  • 写入clientId索引(asc和desc)
  • 写入salary索引(asc和desc)
  • 1写入多属性索引{ clientId, salary } DESC

现在让我们来看看第一个案例:

ofy().load().type(Salary.class).ancestor(clientIdKey).order("-salary").limit(100).list()

这需要在datastore-indexes.xml中使用不同的多属性索引。这次您需要Salary { ancestor, salary } DESC上的索引。此外,GAE的默认行为是从法定数量的中心读取数据,以使其成为一致的操作。这应该比其他方法稍微慢一些(虽然不会更贵),但是,您可以明确指定最终的一致性以获得相同的&#34;任何数据中心&#34;行为:ofy().consistency(Consistency.EVENTUAL).load()...这里的好处是你可以选择强一致性。

祖先方法的另一个好处是,您不需要在clientId上维护单一属性索引。这里写了这个薪水时会发生什么(假设没有其他索引字段):

  • 1为实体操作写
  • 写入salary索引(asc和desc)
  • 1写入多属性索引{ ancestor, salary } DESC

这可以使您的系统更便宜。多属性索引的最大成本通常是所有(否则无关的)双向单属性索引的成本,您必须将其作为GAE的标志维护。


关于您的上一个问题,可能有助于解释GAE索引表的外观。索引有三个BigTable表,在所有应用程序中共享。前两个是单属性索引表(一个用于升序,一个用于降序)。他们的内容看起来非常像这样:

{appId}/{entityKind}/{propertyName}/{propertyValue}/{entityKey}

通过范围扫描(BigTable的基本操作之一),您可以确定哪些实体与您的查询匹配。这也是仅限密钥查询快速/便宜的原因;您可以立即返回密钥,而无需进行后续查找。

多属性索引表看起来(再次,这不完全),如下所示:

{appId}/{entityKind}/{prop1name}/{prop1value}/{prop2name}/{prop2value}/.../{entityKey}\

使用Salary { clientId, salary } DESC上的多属性索引的某些值进行可视化可能更容易:

yourapp/Salary/clientId/500/salary/99000/aghzfnZvb3N0MHILCxIFRXZlbnQYAQw
yourapp/Salary/clientId/500/salary/98000/aghttydiisgAJJ3JGS0ij44JFAjasdw

同样,您可以看到通过执行范围扫描,GAE可以找到与您的查询匹配的实体。

我希望这有助于澄清事情。