如何正确迭代所有 BigQuery 结果行?
Posted
技术标签:
【中文标题】如何正确迭代所有 BigQuery 结果行?【英文标题】:How to correctly iterate over all BigQuery result rows? 【发布时间】:2017-08-25 11:27:37 【问题描述】:我正在从 BigQuery 表中选择一列,例如
select url from `project.dataset.urllist` where status = 2
count(*) 给了我 245217 个结果,我可以在 浏览器控制台。
根据示例在 Java 中实现相同 https://cloud.google.com/bigquery/create-simple-app-api 看起来像
QueryResponse response = bigquery.query(queryRequest);
QueryResult result = response.getResult();
while (result != null)
for (List<FieldValue> row : result.iterateAll())
... do something
result = result.getNextPage();
但是,我最终从 3 个 QueryResult 页面返回了 435651 个结果行。
我发现在 while 循环的第一次迭代中我已经得到了 所需的 245217 行;第二次和第三次迭代返回一个部分 同样的结果。 如果没有 while 循环,我会收到我所期望的,但这是正确的吗?
QueryResult result = response.getResult();
for (List<FieldValue> row : result.iterateAll())
... do something
显然,第一个结果页面包含从 #1 到 #245217 的所有行, 第二页包含从 #100000 到 #245217 的行, 第三页包含从 #200000 到 #245217 的行。 这是 API 中的错误吗?
【问题讨论】:
Javadoc forQueryResult
中的奇怪语言:Returns an iterator for all values, possibly also in the next pages
【参考方案1】:
从实际的角度来看,关于如何正确迭代所有 BigQuery 行的简短答案似乎是:
只需在当前版本的 Google Cloud Java Client Core (1.4.0) 和 BigQuery (0.22.0-beta) 中依赖QueryResult#iterateAll()
;并通过结果页面删除该外循环。
考虑
让我们看一下QueryResult
从com.google.cloud.PageImpl
继承的iterateAll
方法的实现。目前,此方法返回一个从当前页面开始的迭代器,一旦当前页面的所有元素都被迭代(github link),它似乎会获取下一页。这发生在相应的computeNext()
调用上,其中currentPage = currentPage.getNextPage();
显式出现
也就是说,result.getNextPage().iterateAll()
返回迭代器,它从getNextPage
返回的页面的第一个元素开始迭代元素,并将迭代所有下一页,直到到达最后一页的最后一个元素。与result.iterateAll()
的唯一区别是最后一个返回从第一页开始的迭代器。
鉴于上述情况,将 result.iterateAll()
调用包装到页面中的附加循环是多余的,因此看起来 current version of example 不是 100% 一致的,需要删除周围的循环
while (result != null)
...
result = result.getNextPage();
就 API 本身的一致性而言 - 缺乏基于每页处理结果的明确方法,因为对于特定页面上的特定行,我们既没有 iterateAll
的替代品,也没有能力清楚地确定已到达当前页面的末尾(除了在迭代时手动计算行数的能力)。但是,当通过所有行处理整个结果时 - 这似乎不是一个障碍
编辑
请注意Java Client for BigQuery 在撰写本文时处于测试阶段,并且有明确说明:
注意:此客户端正在进行中,可能偶尔会进行向后不兼容的更改。
这意味着我们应该期待进一步的变化,并相应地调整处理所有行的方法。
【讨论】:
以上是关于如何正确迭代所有 BigQuery 结果行?的主要内容,如果未能解决你的问题,请参考以下文章
如何从“grep”中排除所有“permission denied”结果行?