Google Big Query + PHP -> 如何在不耗尽内存的情况下获取大型数据集

Posted

技术标签:

【中文标题】Google Big Query + PHP -> 如何在不耗尽内存的情况下获取大型数据集【英文标题】:Google Big Query + PHP -> How to fetch a large data set without running out of memory 【发布时间】:2014-04-25 15:57:54 【问题描述】:

我正在尝试在 BigQuery/php(使用 google php SDK)中运行一个查询,该查询返回一个大型数据集(可以是 100,000 - 10,000,000 行)。

$bigqueryService = new Google_BigqueryService($client);

$query = new Google_QueryRequest();
$query->setQuery(...);

$jobs = $bigqueryService->jobs;
$response = $jobs->query($project_id, $query); 
//query is a syncronous function that returns a full dataset

下一步是允许用户将结果下载为 CSV 文件。

当数据集变得太大(内存限制)时,上面的代码将失败。 我有哪些选择可以在内存使用量较低的情况下执行此操作?

(我认为一个选项是使用 BigQuery 将结果保存到另一个表中,然后开始使用 LIMIT 和 OFFSET 进行部分提取,但我认为可能会有更好的解决方案......)

感谢您的帮助

【问题讨论】:

如果可能的话,我会尽量避免使用 php 来完成这样的任务。否则,您可以将查询拆分为一些限制较小的子查询,并逐步将其附加到 csv 文件中。 @Johnny000 哪种语言更适合这个?谢谢 我使用了大量的 Java 来处理如此多的数据集,并且有一些非常相似的数据量。但是,如果您按照答案中提到的那样逐行从 google 读取 CSV 文件,它在 php 中也应该很好用,因为我只在 php 和 csv 方面取得了良好的经验。 【参考方案1】:

您可以直接从 Bigquery 导出数据

https://developers.google.com/bigquery/exporting-data-from-bigquery

您可以使用 PHP 运行执行导出的 API 调用(您不需要 BQ 工具)

您需要设置工作configuration.extract.destinationFormat 参见reference

【讨论】:

所以基本上这样做:运行查询并将结果写入表中。在 PHP 之外运行提取(使用 BQ 工具?)处理所述结果文件 我不确定你的意思。通过 PHP 运行这个 export-csv-command 不会使用 PHP 内部的内存吗? 不,这是一个异步作业,你只需提交元数据,作业就会在他们的服务器上执行。【参考方案2】:

只是为了详细说明 Pentium10 的答案

您最多可以以 json 格式导出 1GB 的文件。 然后您可以逐行读取文件,这将最大限度地减少您的应用程序使用的内存,然后您可以使用json_decode 的信息。

【讨论】:

有一个通配符支持导出到多个文件。无论如何,您需要逐行读取文件。 @Pentium10 是的,我知道更大的文件 - 我只是想在您的参考中附加更多内容。【参考方案3】:

导出的建议很好,我只是想提一下还有另一种方式。

您调用的查询 API (jobs.query()) 没有返回完整的数据集;它只返回一页数据,即结果的前 2 MB。您可以设置maxResults 标志(描述为here)以将其限制为一定数量的行。

如果返回的行数少于表中的行数,您将在响应中获得 pageToken 字段。然后,您可以通过提供作业 ID(也在查询响应中)和页面令牌来使用 jobs.getQueryResults() API 获取剩余部分。这将继续返回新行和新页面令牌,直到您到达表的末尾。

示例here 显示了运行查询并逐页获取结果的代码(在 python 中的 java 中)。

API 中还有一个选项可以通过在 URL 查询字符串中指定 alt='csv' 直接转换为 CSV,但我不确定如何在 PHP 中执行此操作。

【讨论】:

事实证明,这正是我所做的 :) 值得注意的是,为了使用它,您需要使用 $jobs->insert 而不是$jobs->query 返回完整的日期集。使用 Insert 后,您应该使用 $jobs->get(PROJ_ID, $jobId) 定期查询作业的状态,直到它处于状态“DONE”。之后,您可以使用 $jobs->getQueryResults(PROJECT_ID, $jobId, $params) 从 X 偏移量中获取 N 行。 (请注意,在部分抓取时,您还必须使用 pageToken,如 Jordan 所说) 其实jobs.query() 真的不应该返回超过2MB的数据...我已经重现了这个问题并提交了内部错误。

以上是关于Google Big Query + PHP -> 如何在不耗尽内存的情况下获取大型数据集的主要内容,如果未能解决你的问题,请参考以下文章

Google Big Query 中的功能

Google Data Studio:将用户输入写回 Google Big Query 表

Google Big Query 的奇怪活动

如何在 Google Big Query 中总结月份?

如何将 Google Cloud SQL 与 Google Big Query 集成

将多行文本插入 Google Big Query