【问题标题】:App engine - Datastore, NOT EQUAL (!=), 30 Subquery limit应用引擎 - 数据存储,不等于 (!=),30 个子查询限制
【发布时间】:2013-12-02 10:56:33
【问题描述】:

使用 Java、Google App Engine 及其 Datastore。 我知道以前有人问过很多这样的问题,但我不能完全理解我正在做的事情是否可行,或者我做错了。

我想做什么: 假设我有 100 个问题,每个问题都是一个问题实体。我希望用户下载例如 20 个问题并回答它们。然后稍后用户应该下载另外 20 个问题,但我想确保它与以前的问题不同。最好的方法是什么?

我目前正在向用户发送 20 个问题,每个问题都有一个唯一的 ID。然后,当他们再请求 20 个问题时,用户还会发回他回答的问题(即 20 个问题的 ID)。然后,当我进行“查询”以检索 20 个新问题时,我通过调用 query.setFilter("id != 1 && id != 2 && ... && id != 20") 来设置过滤器。这是“问题”,在这种查询中我可以有多少个'!='(不等于)有限制吗?因为用户第三次请求新问题时,过滤器不仅有 20 个条件,而是 60 个条件。这可能吗?它是一种有效的做事方式吗? '!=' 每次使用时都会创建一个新的子查询吗?

谢谢!

【问题讨论】:

    标签: java google-app-engine google-cloud-datastore


    【解决方案1】:

    听起来你需要一个“光标”。

    查询游标允许应用程序检索查询的结果 方便的批处理,而不会产生查询偏移量的开销。 执行检索操作后,应用程序可以获得 cursor,它是一个不透明的 base64 编码字符串,用于标记索引 检索到的最后一个结果的位置。该应用程序可以保存这个 字符串(例如在数据存储区、内存缓存中、任务队列中 任务负载,或作为 HTTP GET 或 POST 嵌入网页中 参数),然后可以使用光标作为起点 后续检索操作得到下一批结果 从上一次检索结束的点开始。一个检索可以 还指定一个结束游标,以限制结果集的范围 返回。

    https://developers.google.com/appengine/docs/java/datastore/queries#Java_Query_cursors

    您必须小心使用它,有关详细信息,请参阅链接。

    【讨论】:

    • 感谢您提供非常好的答案!如果我找不到更好的解决方案,我可能会使用它,但是如果“随机”选择 20 个问题会采取什么方法呢? (我知道我没有在问题中包含这个,因为我不想限制潜在的可能性)。另外,我的其他问题是,我可以拥有多少个 '!=' 有限制吗?
    • np。如果您不想问已经问过的问题,则必须存储用户已经回答的问题。您在哪里/如何做到这一点实际上取决于我们正在谈论多少问题。如果您运行查询,它将返回 20 个“随机”结果(除非您指定排序顺序)并且您可以从该点开始使用光标。我不知道有多少!= 因为我在任何情况下都使用 python/ndb。
    • 谢谢!即使我存储了某个用户已经回答过的问题,我仍然会陷入同一条船上,我仍然必须过滤掉他们已经回答过的问题。 :((我似乎每次都以相同的顺序得到结果,没有指定任何顺序,尽管这与案例并不真正相关)
    • 是的,您通常会以相同的顺序获得问题(记录),但不能保证。与其将它们过滤掉,不如反其道而行之。假设您总共有 100 个问题,每个问题都存储有一个密钥,该密钥也是问题的编号。 1,2,3 等等。因此,要选择一些随机问题,您可以简单地生成一个 1 到 100 的随机数,然后按键获取该问题。在您执行此操作之前,请检查用户是否已经回答了所选择的问题,如果是,请生成另一个选择并重试。这既不高效也不优雅,只是需要考虑一下。
    • 我最终使用了您的解决方案!我使用了两个光标;一个总是指向最后一个 known 元素和一个从头到尾连续移动的元素。如果在从头到尾移动时添加了新问题,它还会检索最新问题并首先将它们发送给用户!
    【解决方案2】:

    我会看看这两个关于获取随机记录的问题。

    Get a random entity in Google App Engine datastore which does not belong to a list

    和

    Query random row in ndb

    在您的情况下,选择一个随机集合,然后过滤掉已经回答的问题,这将比您目前尝试执行的查询更有效。

    如果您在已知整数范围内为问题预先分配 ID,则可以使用为用户存储的位图来检查问题的键,并根据已完成的问题 ID 设置位。这可能比对键执行 get 更快。

    【讨论】:

    • 谢谢! (也感谢您考虑这个问题的随机元素,而我没有将它包含在原始问题中。)所以,如果我理解正确的话;我应该随机抽取 20 个问题,如果其中 10 个问题已经被用户回答,我应该: 1. 对我得到的 10 个问题感到满意,将它们发送给用户或者... 2. 再随机抽取 10 个问题(按照你的逻辑以上),然后将它们发送给用户。另外,过滤器中的每个 '!=' 是否会导致子查询,或者我可以在过滤器中使用无限数量的 '!=' 吗?
    • 每个!= 创建一个子查询,因此通过选择范围,即,您只需要一个查询。如果您使用位图,您甚至可以从位位置创建键,并获取一堆尚未完成的问题(假设它们存在)。如果您的问题分布稀疏,则随机查询更有可能为您提供结果。然后,我会获取 40 或 50 个问题,并在您有 20 个未回答的问题时丢弃任何问题,而不是进行多个查询。或者至少分析一下这两种策略,看看哪种策略在大多数情况下表现更好。
    • 好的!明天我会试试这个,看看我能不能让它以“干净”的方式工作。由于简单(随机不是必需的,但更优选),我更倾向于 Pauls 解决方案。还有一个问题:当我尝试时,我似乎能够拥有超过 30 个 '!=',这个规则是否仅适用于它们用于不同的“字段”时?
    • 不等式过滤器最多只能使用一个属性 - 我会阅读不等式过滤器 developers.google.com/appengine/docs/python/datastore/… 相同的限制将适用于 java。
    • 呃,对最后一部分感到抱歉。不要以为我的问题是我想要的。我知道不等式过滤器最多只能使用一个属性(/字段)。我真正想知道的是:即使我尝试使用 60 个不等式,为什么我的查询仍然有效,例如: setFilter("id != 1 && id != 2 && .. && id != 60)?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多