如何获取超过1000?

时间:2008-11-05 01:56:21

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

如何从数据存储中获取超过1000条记录并将所有内容放在一个列表中传递给django?

16 个答案:

答案 0 :(得分:37)

从版本1。3。6(2010年8月17日发布)开始, CAN

From the changelog:

  

数据存储计数()查询的结果和所有数据存储区查询的偏移量不再限制在1000

答案 1 :(得分:23)

仅为记录 - 现在取消了1000个条目的限制:

http://googleappengine.blogspot.com/2010/02/app-engine-sdk-131-including-major.html

报价:

  

不再有1000个结果限制 - 那就是   右:加上游标和   许多小人物的高潮   数据存储的稳定性和性能   过去几个月的改进,   我们现在有足够的信心去除   最大限度的结果限制。   无论你是在取,   迭代,或使用Cursor,有   对结果数量没有限制。

答案 2 :(得分:19)

App Engine通过对Keys进行排序并使用最后一个键作为下一个偏移量,为您提供了一种很好的方式,通过1000“分页”结果。他们甚至在这里提供了一些示例代码:

http://code.google.com/appengine/docs/python/datastore/queriesandindexes.html#Queries_on_Keys

虽然他们的示例将查询分散到多个请求中,但您可以将页面大小从20更改为1000并在循环中查询,并组合查询集。此外,您可以使用itertools链接查询,而无需在需要之前对其进行评估。

例如,要计算超过1000的行数:

class MyModel(db.Expando):
    @classmethod
    def count_all(cls):
        """
        Count *all* of the rows (without maxing out at 1000)
        """
        count = 0
        query = cls.all().order('__key__')

        while count % 1000 == 0:
            current_count = query.count()
            if current_count == 0:
                break

            count += current_count

            if current_count == 1000:
                last_key = query.fetch(1, 999)[0].key()
                query = query.filter('__key__ > ', last_key)

        return count

答案 3 :(得分:18)

每当这出现限制时,我总是想知道“为什么你需要超过1,000个结果吗?”您是否知道Google自己没有提供超过1,000个结果?试试这个搜索:http://www.google.ca/search?hl=en&client=firefox-a&rls=org.mozilla:en-US:official&hs=qhu&q=1000+results&start=1000&sa=N直到最近我还不知道,因为我从来没有花时间点击查询的第100页搜索结果。

如果您实际上将超过1,000个结果返回给用户,那么我认为手头上存在的问题比数据存储不允许您这样做的事情更重要。

如果您对数据执行大型操作并显示摘要(例如,所有这些数据的平均值),那么需要许多结果的一个可能(合法)理由是。这个问题的解决方案(在Google I / O谈话中讨论过)是在动态计算摘要数据,并将其保存。

答案 4 :(得分:14)

你不能。

部分常见问题解答表明,除了查询的第1000行之外,您无法访问,增加“OFFSET”只会导致更短的结果集,

即:OFFSET 999 - > 1结果回来了。

来自维基百科:

  

App Engine限制最大行数   从实体返回到1000   每个数据存储区调用的行数。大多数网络   数据库应用使用分页和   缓存,因此不需要这个   一次有很多数据,所以这是一个   在大多数情况下没有问题。[引证   需要]如果应用程序需要更多   它每个操作超过1,000条记录   可以使用自己的客户端软件   或者执行Ajax页面   无限数量的操作   行。

来自http://code.google.com/appengine/docs/whatisgoogleappengine.html

  

服务限制的另一个例子是   a返回的结果数   查询。查询最多可以返回   1,000个结果。查询会   返回更多结果只返回   最大值。在这种情况下,请求   执行这样的查询不太可能   在超时之前返回请求,   但限制到位是为了保存   数据存储区中的资源。

来自http://code.google.com/appengine/docs/datastore/gqlreference.html

  

注意:LIMIT子句的最大值为   1000.如果指定了大于最大值的限制,则最大值为   用过的。同样的最大值适用于   GqlQuery类的fetch()方法。

     

注意:与offset的参数类似   fetch()方法,GQL中的OFFSET   查询字符串不会减少   从中获取的实体数量   数据存储。它只影响哪个   结果由fetch()返回   方法。具有偏移量的查询具有   性能特征   与偏移线性对应   大小

来自http://code.google.com/appengine/docs/datastore/queryclass.html

  

限制和偏移参数控制   从中获取了多少结果   数据存储区,以及返回的数量   通过fetch()方法:

     
      
  • 数据存储区将偏移量+限制结果提取给应用程序。数据存储区本身跳过了第一个偏移结果

  •   
  • fetch()方法会跳过第一个偏移结果,然后返回其余的结果(限制结果)。

  •   
  • 查询具有对应的性能特征   线性地与偏移量加上限制。

  •   

这意味着什么

如果您有单一查询,则无法请求0-1000范围之外的任何内容。

增加偏移量只会提高0,所以

LIMIT 1000  OFFSET 0    

将返回1000行,

LIMIT 1000 OFFSET 1000 

将返回 0行,因此,使用单个查询语法无法手动或使用API​​获取2000结果。

唯一合理的例外

是在表上创建数字索引,即:

 SELECT * FROM Foo  WHERE ID > 0 AND ID < 1000 

 SELECT * FROM Foo WHERE ID >= 1000 AND ID < 2000

如果您的数据或查询不能包含此“ID”硬编码标识符,那么您运气不佳

答案 5 :(得分:10)

此1K限制问题已解决。

query = MyModel.all()
for doc in query:
    print doc.title

通过将Query对象视为可迭代:迭代器以小批量从数据存储中检索结果,允许应用程序停止迭代结果以避免获取超出需要的数量。当检索到与查询匹配的所有结果时,迭代停止。与fetch()一样,迭代器接口不会缓存结果,因此从Query对象创建新的迭代器将重新执行查询。

最大批量大小为1K。而且您仍然拥有自动数据存储区配额。

但是通过计划1.3.1 SDK,他们引入了可以序列化和保存的游标,以便将来的调用可以从最后一次停止的查询开始。

答案 6 :(得分:7)

1000记录限制是Google AppEngine的硬限制。

此演示文稿http://sites.google.com/site/io/building-scalable-web-applications-with-google-app-engine说明了如何使用AppEngine有效地翻阅数据。

(基本上通过使用数字id作为键并在id上指定WHERE子句。)

答案 7 :(得分:6)

获取超过1000条记录时,远程api仍然存在问题。我们编写了这个微小的函数来迭代遍历表格:

def _iterate_table(table, chunk_size = 200):
    offset = 0
    while True:
        results = table.all().order('__key__').fetch(chunk_size+1, offset = offset)
        if not results:
            break
        for result in results[:chunk_size]:
            yield result
        if len(results) < chunk_size+1:
            break
        offset += chunk_size

答案 8 :(得分:3)

我们在ModelBase类中使用了以下内容:

@classmethod
def get_all(cls):
  q = cls.all()
  holder = q.fetch(1000)
  result = holder
  while len(holder) == 1000:
    holder = q.with_cursor(q.cursor()).fetch(1000)
    result += holder
  return result

这可以在每个模型上获得1000个查询限制,而无需考虑它。我认为密钥版本也很容易实现。

答案 9 :(得分:2)

class Count(object):
def getCount(self,cls):
    class Count(object):
def getCount(self,cls):
    """
    Count *all* of the rows (without maxing out at 1000)
    """
    count = 0
    query = cls.all().order('__key__')


    while 1:
        current_count = query.count()
        count += current_count
        if current_count == 0:
            break

        last_key = query.fetch(1, current_count-1)[0].key()
        query = query.filter('__key__ > ', last_key)

    return count

答案 10 :(得分:2)

entities = []
for entity in Entity.all():
    entities.append(entity)

这很简单。请注意,每个实体都有一个RPC,它比以块的形式提取要慢得多。因此,如果您担心性能,请执行以下操作:

如果您的项目少于1M:

entities = Entity.all().fetch(999999)

否则,请使用光标。

还应该注意:

Entity.all().fetch(Entity.all().count())

返回1000最大值,不应使用。

答案 11 :(得分:1)

JJG:你的解决方案很棒,但如果你有0条记录会导致无限循环。 (我在本地测试我的一些报告时发现了这一点。)

我修改了while循环的开头,如下所示:

while count % 1000 == 0:
    current_count = query.count()
    if current_count == 0:
        break

答案 12 :(得分:0)

将两个查询的内容一起添加:

list1 = first query
list2 = second query
list1 += list2

列表1现在包含所有2000个结果。

答案 13 :(得分:0)

建议的解决方案仅在条目按键排序时才有效...如果您先按其他列排序,则仍需使用limit(offset,count)子句,则仍然适用1000条目限制。如果您使用两个请求,它们是相同的:一个用于检索索引(带条件和排序),另一个用于使用第一个结果中的索引子集中的索引(),因为第一个请求不能返回超过1000个键? (如果我们必须按排序以删除1000个结果限制,那么Google 按键上的查询部分并未明确说明)

答案 14 :(得分:0)

这与Gabriel提供的解决方案很接近,但是没有获取它只计算它们的结果:

count = 0
q = YourEntityClass.all().filter('myval = ', 2)
countBatch = q.count()
while countBatch > 0:
    count += countBatch
    countBatch = q.with_cursor(q.cursor()).count()

logging.info('Count=%d' % count)

完美适用于我的查询,也快速(1.1秒计算67,000个实体)

请注意,查询不能是不等式过滤器或集合,否则游标将无效,您将获得此异常:

  

AssertionError:没有可用于MultiQuery的游标(使用“IN”或“!=”运算符进行查询)

答案 15 :(得分:0)

如果你正在使用NDB:

@staticmethod
def _iterate_table(table, chunk_size=200):
    offset = 0
    while True:
        results = table.query().order(table.key).fetch(chunk_size + 1, offset=offset)
        if not results:
            break
        for result in results[:chunk_size]:
            yield result
        if len(results) < chunk_size + 1:
            break
        offset += chunk_size