10

我正在运行一个查询,它当前返回 1400 个结果,因此我在日志文件中收到以下警告:

com.google.appengine.api.datastore.QueryResultsSourceImpl logChunkSizeWarning:此查询在 FetchOptions 中没有设置块大小,并且返回了 1000 多个结果。如果此大小的结果集对于此查询很常见,请考虑设置块大小以提高性能。

我在任何地方都找不到关于如何实际实现这一点的任何示例,这里有一个关于 python 的问题,但是由于我使用 java 并且不懂 python,我正在努力翻译它。

此外,这个查询(如下)需要 17226cpu_ms 来执行,这感觉太长了,我什至无法想象如果我说 5000 个联系人并且需要在客户端搜索它们会发生什么(就像你对 googlemail 联系人所做的那样! )

我的代码是:

    int index=0;
    int numcontacts=0;
    String[][] DetailList;

    PersistenceManager pm = PMF.get().getPersistenceManager();


    try {
        Query query = pm.newQuery(Contact.class, "AdminID == AID");
        query.declareParameters("Long AID");
        query.setOrdering("Name asc");
        List<Contact> Contacts = (List<Contact>) query.execute(AdminID);
        numcontacts=Contacts.size();
        DetailList=new String[numcontacts][5];

        for (Contact contact : Contacts) 
        {
            DetailList[index][0]=contact.getID().toString();
            DetailList[index][1]=Encode.EncodeString(contact.getName());
            index++;
        }
    } finally {
        pm.close();
    }
    return (DetailList);

我在这里找到了以下两个条目:

但实际上都没有详细说明如何实施或使用这些选项。我猜它是一个服务器端进程,我猜你打算设置某种循环来一次抓取一个块,但我该怎么做呢?

  • 我是否在循环内调用查询?
  • 我怎么知道循环多少次?
  • 我是否只检查返回的第一个块小于块大小的条目数?

如果没有实际的例子可循,我怎么能找到这样的东西?在我看来,这里的其他人似乎“只知道”怎么做..!

对不起,如果我没有以正确的方式提出问题,或者我只是一个对此感到迟钝的新手,但我不知道还有什么地方可以解决这个问题!

4

3 回答 3

4

遇到同样的问题,最后一条评论是一个月前的,所以这是我发现的关于重型数据集查询的内容。

我想我会在阅读了谷歌文档文章中的那些行之后使用“查询光标”技术(顺便提到的python中的那个):

本文是针对 SDK 版本 1.1.7 编写的。从 1.3.1 版开始,查询游标 ( Java | Python ) 已经取代了下面描述的技术,现在是推荐的对大型数据集进行分页的方法。

在关于“查询光标”的谷歌文档中。文档的第一行准确地说明了为什么需要cursor

查询游标允许应用程序执行查询并检索一批结果,然后在后续 Web请求中为同一查询获取其他结果,而无需查询偏移量的开销

该文档还提供了一个使用游标技术的 servlet 的java 示例。有一个提示如何为客户端生成安全光标。最后,游标的局限性暴露出来。

希望这可以为您解决问题提供线索。

关于 range 和offset的小提醒,如果忘记(我确实这样做了^^),则会对性能产生很大影响:

起始偏移量对性能有影响:Datastore 必须检索然后丢弃起始偏移量之前的所有结果。例如,范围为 5, 10 的查询从 Datastore 中获取 10 个结果,然后丢弃前 5 个并将剩余的 5 个返回给应用程序。


编辑:在使用 JDO 时,我一直在寻找一种方法来允许我以前的代码在单个查询中加载超过 1000 个结果。所以,如果你也在使用 JDO,我发现了这个老问题

Query query = pm.newQuery(...);
// I would use of value below 1000 (gae limit) 
query.getFetchPlan().setFetchSize(numberOfRecordByFetch); 
于 2012-08-18T00:04:25.660 回答
3

这就是我应用的方式FetchOptions,与您的示例代码相比,您可能需要稍微调整一下:

// ..... build the Query object
FetchOptions fetch_options =
    FetchOptions.Builder.withPrefetchSize(100).chunkSize(100);
QueryResultList<Entity> returned_entities =
    datastore_service_instance.prepare(query).asQueryResultList(fetch_options);

当然,数字可能会改变(100)。

如果我的答案不是您想要的,那么欢迎您重新提出您的问题(编辑)。

顺便说一句,我是写第一个链接问题的人。

于 2011-08-28T13:26:24.900 回答
1

如果您直接使用 dataStore,而不使用JDO,那么在迭代数据时,您可以执行以下操作来设置块大小:

Query query = new Query("entityname");
PreparedQuery preparedQuery = dataStore.prepare(query);
// the 200 should be less than 1000
FetchOptions options = FetchOptions.Builder.withChunkSize(200);
for (Entity result : preparedQuery.asIterable(options)) {
    ...
}
于 2012-09-06T21:43:00.740 回答