更快地解析 BigQuery JSON 结果

Posted

技术标签:

【中文标题】更快地解析 BigQuery JSON 结果【英文标题】:Faster parsing of BigQuery JSON results 【发布时间】:2019-10-24 13:03:26 【问题描述】:

我正在构建一个使用 BigQuery 作为数据源的 API。我们在数据存储、分区和查询优化方面做了大量工作,但是,我在有效解析查询结果方面遇到了一些麻烦。例如,在某些情况下,有 50 多行 JSON,我看到解析需要 3 秒或更长时间,这在查询执行和 HTTP 请求/响应之上远非理想。

下面是我使用公共 BigQuery 数据集所做的简化版本,我的查询要复杂得多,但是解析是相同的,这是我需要一些帮助的地方。

from google.cloud import bigquery
import json

sql = """
SELECT TO_JSON_STRING(t) FROM (
SELECT * FROM
`bigquery-public-data.hacker_news.stories`
LIMIT 50 OFFSET 0
) as t
"""

client = bigquery.Client()
job_config = bigquery.QueryJobConfig()
query_job = client.query(sql,job_config=job_config)
results = query_job.result()

# Begin parsing results to valid
# JSON for API response
json_response = '['
i = 0
for row in results:
    json_response = json_response + row[0]
    if i != total_rows:
        json_response = json_response + ","
    i += 1

json_response = json_response + ']'    

print(json_response)

我尝试遵循here 中列出的一些性能提示,但不断遇到我无法克服的错误。

注意:我是 Python 的新手,在过去的几年里一直使用 Ruby 编写代码。

编辑: 我尝试了几种构建 JSON 响应的替代方法,针对 Micah 的评论,我运行了一些分析,结果如下。

版本1(原版如上)

json_response = '['
i = 0
for row in results:
    json_response = json_response + row[0]
    if i != total_rows:
        json_response = json_response + ","
    i += 1

json_response = json_response + ']'  

建立响应的平均时间 = 1.7962 秒

第 2 版

json_list = [ json.loads(row[0]) for row in results]
json_response = json.dumps(json_list)

构建响应的平均时间 = 2.4789 秒

我猜这里 json.loads 和 json.dumps 会增加延迟。

版本 3(基于 Micah 的建议)

a = [row[0] for row in results]
json_response = ",".join(a) 

建立响应的平均时间 = 1.9623 秒

我更喜欢 V2&3 的代码,但 V1 仍然是最快的方法,尽管速度很慢。

【问题讨论】:

大的 JSON 数据从何而来?它是来自存储 JSON 的某个列还是作为您的示例查询,您形成了一个要从 BigQuery 返回的 JSON。解决方案可能不同。 它来自后来/第二个选项。该表有很多列,使用 TO_JSON_STRING() 命令返回 JSON 行。 这可能有助于进行更多分析。 a =[row[0] for row in results] 需要多长时间? ",".join(a) 需要多长时间?无论哪种情况,加入都应该比您当前的循环更快。 我在上面做了一些编辑,我已经介绍了两种新方法 【参考方案1】:

我通常是这样做的:

from google.cloud import bigquery
import json


# BigQuery Setup and Query
project_name = 'my_project'
client = bigquery.Client(project=project_name)
query = 'select to_json_string(t) as my_stuff from schema.dataset'

job_config = bigquery.QueryJobConfig()
job_config.use_query_cache = False
query_job = client.query(query, job_config = job_config)

results = query_job.result()

json_list = []

for row in results:
    json_list.append(row.my_stuff)

with open('data.json', 'w') as f:
    json.dump(json_list,f)

如果您需要字段名称或多个字段,请使用to_json_string(struct(t))to_json_string(struct(a,b,c) as values))

【讨论】:

以上是关于更快地解析 BigQuery JSON 结果的主要内容,如果未能解决你的问题,请参考以下文章

如何解析来自 Bigquery 结果的 json 响应?

Google BigQuery:将 ExecuteQuery 结果以 json 格式上传到 Google Cloud Storage

SwiftyJson 是不是可以更快地解析 swift json?

使用 Java 从 BigQuery 到 BigQuery 表的表复制中的 JSON 解析错误

如何使用 JSON_EXTRACT 或 JSON_EXTRACT_SCALAR 在 Big Query 中读取多级 JSON 数据

无法导出 Big Query 表