如何通过Snowflake UDF将API返回的JSON数据保存为Snowflake表?
如何通过Snowflake UDF将API返回的JSON数据保存为Snowflake表?
看起来你遇到的问题是API返回的JSON里存在混合类型的字段,导致Pandas转成Arrow格式时触发了类型冲突错误。我来给你几个实用的解决方案,帮你把非结构化数据顺利存入Snowflake表:
方案1:直接存储整个JSON为单个VARIANT字段(最简单推荐)
Snowflake的VARIANT类型天生就是为非结构化JSON数据设计的,完全能处理嵌套、混合类型的内容。你不需要把JSON拆成多列,直接把整个API返回结果作为一行的单个字段插入即可:
import requests as rq import snowflake.snowpark as snowpark def getData (session: snowpark.Session): apiurl = 'https://exmaple.com' header = { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Bearer bearer_token' } response = rq.post(apiurl, headers = header) data = response.json() # 将整个JSON对象包装成Snowpark DataFrame的一行 snow_df = session.create_dataframe([[data]], schema=["API_RESPONSE"]) # 写入表,Snowflake会自动将该字段识别为VARIANT类型 snow_df.write.mode("overwrite").save_as_table("DEV_1_RAW.SCHEMA!.RAW_SEGMENT") return "数据已成功保存"
之后你可以用Snowflake的JSON函数(比如GET_PATH、FLATTEN)来查询、解析这个VARIANT字段里的内容。
方案2:处理混合类型字段,统一转为JSON字符串
如果你还是想把JSON拆分成多列存储,但某些列存在混合类型(比如你提到的fimFranchisee),可以把这些有问题的列转成JSON字符串,让Pandas能正常处理:
import requests as rq import pandas as pd import snowflake.snowpark as snowpark import json def getData (session: snowpark.Session): apiurl = 'https://exmaple.com' header = { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Bearer bearer_token' } response = rq.post(apiurl, headers = header) data = response.json() df = pd.DataFrame(data) # 将混合类型的列转为JSON字符串,消除类型冲突 df['fimFranchisee'] = df['fimFranchisee'].apply(lambda x: json.dumps(x) if x is not None else None) # 写入Snowflake表 session.write_pandas(df, table_name= 'RAW_SEGMENT', database='DEV_1_RAW', schema='SCHEMA!', auto_create_table=True, overwrite=True) return "数据已成功保存"
写入后该字段会是STRING类型,之后你可以用Snowflake的PARSE_JSON函数把它转回VARIANT来操作。
方案3:用Snowpark DataFrame直接处理,跳过Pandas
Snowpark对Snowflake的原生数据类型支持更好,你可以跳过Pandas直接用Snowpark解析JSON,自动处理混合类型问题:
import requests as rq import snowflake.snowpark as snowpark def getData (session: snowpark.Session): apiurl = 'https://exmaple.com' header = { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Bearer bearer_token' } response = rq.post(apiurl, headers = header) data = response.json() # 根据API返回的是列表还是单个对象,创建Snowpark DataFrame if isinstance(data, list): snow_df = session.create_dataframe(data) else: snow_df = session.create_dataframe([data]) # 写入表,Snowpark会自动推断合适的类型(混合类型字段会转为VARIANT) snow_df.write.mode("overwrite").save_as_table("DEV_1_RAW.SCHEMA!.RAW_SEGMENT") return "数据已成功保存"
错误原因说明
你遇到的pyarrow.lib.ArrowInvalid错误,本质是fimFranchisee列里同时存在列表和其他非列表的非空值(比如字典、字符串),PyArrow在转换时无法统一这种混合类型。而Snowflake的VARIANT类型专门用来处理这类非结构化数据,所以通过上面的方法将这类字段转为VARIANT或JSON字符串,就能解决类型冲突问题。
备注:内容来源于stack exchange,提问作者Victor Gallo
相关产品推荐
相关产品推荐

