将BigQuery数据导入Python DataFrame报错:QueryJob无法JSON序列化
BigQuery数据转DataFrame报错:TypeError: Object of type 'QueryJob' is not JSON serializable
问题描述
我正在探索将BigQuery数据导入Python的方法,以下是我的代码:
from google.cloud import bigquery from pandas.io import gbq client = bigquery.Client.from_service_account_json("path_to_my.json") project_id = "my_project_name" query_job = client.query(""" #standardSQL SELECT date, SUM(totals.visits) AS visits FROM `projectname.dataset.ga_sessions_20*` AS t WHERE parse_date('%y%m%d', _table_suffix) between DATE_sub(current_date(), interval 3 day) and DATE_sub(current_date(), interval 1 day) GROUP BY date """) results = query_job.result() # 等待任务完成 #for row in results: # print("{}: {}".format(row.date, row.visits)) results_df = gbq.read_gbq(query_job,project_id=project_id)
注释掉的循环代码可正确返回查询结果,但该形式数据无法直接使用。我希望将其转为DataFrame,却触发错误:TypeError: Object of type 'QueryJob' is not JSON serializable。请问代码出错原因是什么?或推荐更优的BigQuery数据转DataFrame方法?
问题原因
你遇到的错误核心逻辑很直白:gbq.read_gbq() 函数的第一个参数要求传入字符串格式的SQL查询语句,但你传给它的是一个QueryJob对象——这是BigQuery客户端执行查询后返回的任务实例,它本身不属于JSON可序列化的类型,自然会触发序列化失败的报错。
解决方案
这里给你两种可行的处理方式,优先推荐第一种:
方法1:用QueryJob原生的to_dataframe()方法(最优方案)
BigQuery的Python客户端已经内置了直接将QueryJob结果转为Pandas DataFrame的方法,不需要额外借助pandas.io.gbq模块,而且能复用你已经执行完成的查询结果,效率更高:
# 你已经调用过query_job.result()等待查询完成,这一步也可以省略,to_dataframe会自动等待任务结束 results_df = query_job.to_dataframe()
这个方法会直接把QueryJob返回的结果集转换成DataFrame,完全匹配你的需求,代码也更简洁。
方法2:如果坚持使用gbq.read_gbq()
如果你还是想使用这个函数,需要把原始的SQL查询语句单独提取出来,作为参数传给它,而不是传QueryJob对象:
from google.cloud import bigquery from pandas.io import gbq client = bigquery.Client.from_service_account_json("path_to_my.json") project_id = "my_project_name" # 单独定义SQL查询字符串 sql_query = """ #standardSQL SELECT date, SUM(totals.visits) AS visits FROM `projectname.dataset.ga_sessions_20*` AS t WHERE parse_date('%y%m%d', _table_suffix) between DATE_sub(current_date(), interval 3 day) and DATE_sub(current_date(), interval 1 day) GROUP BY date """ # 直接将SQL字符串传入gbq.read_gbq results_df = gbq.read_gbq(sql_query, project_id=project_id)
不过要注意,这种方式相当于重新提交了一次查询请求,不如第一种方法高效,因为你之前已经通过client.query执行过一次查询了。
内容的提问来源于stack exchange,提问作者Ben P
相关产品推荐
相关产品推荐

