【问题标题】:Casting a JSON field to STRING in BigQuery's LoadJobConfig在 BigQuery 的 LoadJobConfig 中将 JSON 字段转换为 STRING
【发布时间】:2021-05-03 17:05:30
【问题描述】:

我从 API 调用中提取数据并将其加载到 JSON 中,然后再将其加载到 bigquery 表中。我注意到有些字段同时包含数字和字符串,但是,在每日负载的基础上,它可能不会同时包含两者,因此 JSON 架构会根据当天包含的内容将该字段推断为 INTEGER 或 STRING。

BigQuery 表将此字段作为字符串...。有没有办法在加载之前在 BigQuery 的 LoadJobConfig 中将这个字段转换为 JSON 中的字符串?否则我会收到“提供的架构在某些日子与表不匹配错误”。

我对这一切都很陌生,所以我不确定是否有更好的方法。

这是我的 API 调用:

response = requests.post(url, json=data, headers=headers)
j = json.loads(response.text)
return j

然后我加载结果 vi:

def insert_rows_append(table_name, rows):
    bq_client = get_big_query_client()
    print('Inserting {} rows into {}'.format(table_name, len(rows)))
    job_config = bigquery.LoadJobConfig()
    # job_config.autodetect = True
    job_config.write_disposition = "WRITE_APPEND"
    job_config.source_format = bigquery.SourceFormat.NEWLINE_DELIMITED_JSON
    # bq_table = bq_client.table(ORDERS_TABLE)
    try:
        load_job = bq_client.load_table_from_json(
            rows,
            table_name,
            job_config=job_config
            #, row_ids=[None] * len(rows_to_insert)
        ) 

for row in rows:
        if 'ad_name' in row:
            if not isinstance(row['ad_name'], str): row['ad_name'] = str(row['ad_name'])
        if 'ad_group' in row:
            if not isinstance(row['ad_group'], str): row['ad_group'] = str(row['ad_group'])

我做了一些额外的检查。使用以下方法检查我传递给load_job = bq_client.load_table_from_json 的“行”:

def getList(dict):
        for key, value in dict.items():
            print(key, type(value))
    print(getList(rows[0]))
Inserting dev:test.table rows into 29090
ad <class 'str'>
ad_group <class 'str'>
ad_group_name <class 'str'>
ad_name <class 'str'>
browser <class 'str'>
campaign <class 'str'>
campaign_name <class 'str'>
click_through_rate <class 'NoneType'>
clicked_at_date <class 'str'>
clicked_at_hour <class 'int'>
clicks <class 'int'>
clicks_unique <class 'int'>
cost_amount <class 'float'>
cost_currency <class 'str'>
country <class 'str'>
goal_rate <class 'NoneType'>
goal_revenue_amount <class 'NoneType'>
goal_revenue_currency <class 'NoneType'>
goals <class 'list'>
impressions <class 'int'>
impressions_unique <class 'int'>
influencer <class 'str'>
network <class 'str'>
network_name <class 'str'>
sub1 <class 'str'>
sub2 <class 'str'>
sub3 <class 'str'>
sub4 <class 'str'>
sub5 <class 'str'>
team_id <class 'int'>
team_name <class 'str'>
user_id <class 'str'>
network_click_through_rate <class 'NoneType'>
network_clicks <class 'NoneType'>
network_cost_amount <class 'NoneType'>
network_cost_currency <class 'NoneType'>
network_impressions <class 'NoneType'>
None
error occurred
400 Provided Schema does not match Table dev:test.table. Field ad_name has changed type from STRING to INTEGER

所以据此,JSON 中的 ad_name 是一个字符串。所以我不知道 INTEGER 是从哪里来的。

编辑:查看字段的值。我没有看到 ad_name 列的类型和字符串类型值。在字段中没有类型的情况下,python 是否将字段归类为 INTEGER?

【问题讨论】:

  • 这是一个非常可靠的问题,但它需要 API 调用、JSON 和示例错误。换句话说,考虑添加一个 MRE,一个最小的可重现示例。
  • 更新了帖子。对这一切都超级陌生,所以如果还有什么遗漏,请告诉我。
  • 由于您正在执行write_append,Bigquery 将不支持动态更新列的数据类型。加载前可以不更新json数据吗?
  • @PeterJeong 好多了!
  • @AnkurSaxena 我接受了 yoru 的建议,但 atm 遇到了一些麻烦。这就是我将值转换为字符串的方法:``` for row in result['results']: if "ad_name" in row: row['ad_name'] == str(row['ad_name'] ) ``` 这似乎并没有被覆盖。

标签: python google-cloud-platform google-bigquery


【解决方案1】:

我可以通过将架构传入job_config.schema 来解决此问题

似乎即使关闭了自动检测,bigquery 仍在以某种方式在幕后尝试转换或转换字段。

【讨论】:

    猜你喜欢
    • 2021-06-05
    • 1970-01-01
    • 1970-01-01
    • 2019-05-31
    • 2019-07-18
    • 1970-01-01
    • 1970-01-01
    • 2020-01-02
    • 2018-01-01
    相关资源
    最近更新 更多