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



我们有一个覆盖租赁,我需要根据索引属性范围和客户端id在一个巨大的appengine数据存储中进行搜索和提取。使用Ancestor Paths会提高效率吗?或者,也可以使用额外的过滤器进行相同操作

例如,通过对象化获得前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"是全局存储的,还是根据祖先进行分区,以便索引更新仅在同一祖先内发生?这将减少更新索引所花费的时间,并且当我们永远不会跨不同的客户端进行查询时,这将是一个很好的解决方案。

我需要指出的第一件事是数据存储不进行表扫描。除了几个例外(最明显的是Z字形合并),GAE查询只遵循索引——所以通常这类问题可以归结为"维护哪个索引更有效?"

让我们从第二种情况开始(请注意,我已经将Salary单独化了,我认为这是你的意图):

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索引的2次写入(asc和desc)
  • salary索引的2次写入(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的默认行为是从数据中心的仲裁中读取,以使其成为强一致性操作。这应该比其他方法慢一些(尽管并不更昂贵),但是,您可以显式指定最终一致性,以获得相同的"任何数据中心"行为:ofy().consistency(Consistency.EVENTUAL).load()...。这里的好处是您可以选择强一致性。

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

  • 1为实体操作写入
  • salary索引的2次写入(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可以找到与查询匹配的实体。

我希望这有助于澄清问题。

最新更新