You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS Athena中如何映射JSON的List<List<Object>>数据类型?

问题:JSON中data字段与Athena数据类型映射失败

问题背景

我正在将以下JSON格式的数据上传至AWS S3存储桶:

{
  "time": 1663090620000,
  "data": [
    [
      1,
      [
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
      ]
    ]
  ]
}

该JSON字段对应的自定义数据类型如下:

time - Long
data - List<List<Object>>

我尝试通过指向S3存储桶并使用分区投影功能在Athena中创建了如下表结构,但无法将JSON中的data字段映射到AWS Athena支持的数据类型:

CREATE EXTERNAL TABLE `test_data_db`.`test_data_table`(
  `time` bigint COMMENT 'from deserializer', 
  `data` array<array<double>> COMMENT 'from deserializer')
PARTITIONED BY ( 
  `id` string, 
  `creation_date` date
)
ROW FORMAT SERDE 
  'org.apache.hive.hcatalog.data.JsonSerDe' 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://test-data-bucket/test-data'
TBLPROPERTIES (
  'has_encrypted_data'='false', 
  'projection.creation_date.format'='yyyy-MM-dd', 
  'projection.creation_date.range'='2010-01-01,2050-12-31', 
  'projection.creation_date.type'='date', 
  'projection.enabled'='true', 
  'projection.id.type'='injected', 
  'storage.location.template'='s3://test-data-bucket/test-data/id=${id}/creation_date=${creation_date}', 
  'transient_lastDdlTime'='1663357524')

问题分析

你的data字段是嵌套数组结构,且内层数组包含两种不同类型:数值和另一个数组,而你定义的array<array<double>>仅支持双层数值数组,类型不匹配导致映射失败。Athena基于Hive生态,需要用更灵活的类型或SerDe来适配这种混合嵌套结构。

解决方法

方案1:改用OpenX JSON SerDe + JSON类型

OpenX的JSON SerDe比Hive原生版本更适配复杂嵌套结构,配合Athena的json类型可直接存储任意JSON结构:

CREATE EXTERNAL TABLE `test_data_db`.`test_data_table`(
  `time` bigint COMMENT 'from deserializer', 
  `data` array<json> COMMENT 'from deserializer')
PARTITIONED BY ( 
  `id` string, 
  `creation_date` date
)
ROW FORMAT SERDE 
  'org.openx.data.jsonserde.JsonSerDe' 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://test-data-bucket/test-data'
TBLPROPERTIES (
  'has_encrypted_data'='false', 
  'projection.creation_date.format'='yyyy-MM-dd', 
  'projection.creation_date.range'='2010-01-01,2050-12-31', 
  'projection.creation_date.type'='date', 
  'projection.enabled'='true', 
  'projection.id.type'='injected', 
  'storage.location.template'='s3://test-data-bucket/test-data/id=${id}/creation_date=${creation_date}', 
  'transient_lastDdlTime'='1663357524')

查询时可通过JSON函数解析数据:

SELECT 
  time,
  json_extract_array_element_text(data[1], 0) AS first_value,
  json_extract_array_element(data[1], 1) AS nested_array
FROM test_data_db.test_data_table

方案2:使用UnionType强类型约束

如果需要严格的类型定义,可以用Hive的uniontype适配混合类型:

CREATE EXTERNAL TABLE `test_data_db`.`test_data_table`(
  `time` bigint COMMENT 'from deserializer', 
  `data` array<array<uniontype<bigint, array<double>>>> COMMENT 'from deserializer')
PARTITIONED BY ( 
  `id` string, 
  `creation_date` date
)
ROW FORMAT SERDE 
  'org.apache.hive.hcatalog.data.JsonSerDe' 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://test-data-bucket/test-data'
TBLPROPERTIES (
  'has_encrypted_data'='false', 
  'projection.creation_date.format'='yyyy-MM-dd', 
  'projection.creation_date.range'='2010-01-01,2050-12-31', 
  'projection.creation_date.type'='date', 
  'projection.enabled'='true', 
  'projection.id.type'='injected', 
  'storage.location.template'='s3://test-data-bucket/test-data/id=${id}/creation_date=${creation_date}', 
  'transient_lastDdlTime'='1663357524')

查询时通过get_union_type提取对应类型的值:

SELECT 
  time,
  get_union_type(data[1][0], 0) AS first_value,
  get_union_type(data[1][1], 1) AS nested_array
FROM test_data_db.test_data_table

方案3:先存为字符串,查询时解析

如果上述方案不适用,可先将data存为字符串,再在查询时解析:

CREATE EXTERNAL TABLE `test_data_db`.`test_data_table`(
  `time` bigint COMMENT 'from deserializer', 
  `data` string COMMENT 'from deserializer')
PARTITIONED BY ( 
  `id` string, 
  `creation_date` date
)
ROW FORMAT SERDE 
  'org.apache.hive.hcatalog.data.JsonSerDe' 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://test-data-bucket/test-data'
TBLPROPERTIES (
  'has_encrypted_data'='false', 
  'projection.creation_date.format'='yyyy-MM-dd', 
  'projection.creation_date.range'='2010-01-01,2050-12-31', 
  'projection.creation_date.type'='date', 
  'projection.enabled'='true', 
  'projection.id.type'='injected', 
  'storage.location.template'='s3://test-data-bucket/test-data/id=${id}/creation_date=${creation_date}', 
  'transient_lastDdlTime'='1663357524')

查询示例:

SELECT 
  time,
  json_extract_array_element_text(json_parse(data)[0], 0) AS first_value,
  json_extract_array_element(json_parse(data)[0], 1) AS nested_array
FROM test_data_db.test_data_table

总结

优先推荐方案1,OpenX SerDe配合JSON类型既保留了数据结构的灵活性,又能方便地在查询时解析;如果需要强类型约束,可选择方案2的UnionType方案。

内容的提问来源于stack exchange,提问作者Shivakumar Sajjan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 13:45:48