在动态JSON字段中查询AWS Athena中的第一个非空值

时间:2019-05-21 21:58:19

标签: mysql amazon-s3 presto amazon-athena

我将事件数据存储在S3中,并希望使用Athena来查询数据。字段之一是动态JSON字段,我不知道其字段名称。因此,我需要查询JSON中的键,然后使用这些键来查询该字段的第一个非null值。以下是S3中存储的数据的示例。

{
 timestamp: 1558475434,
 request_id: "83e21b28-7c12-11e9-8f9e-2a86e4085a59",
 user_id: "example_user_id_1",
 traits: {
  this: "is",
  dynamic: "json",
  as: ["defined","by","the", "client"]
 }
}

因此,我需要一个查询以从traits列(存储为JSON)中提取键,并使用这些键获取每个字段的第一个非空值。

我能找到的最接近的样本是使用min_by采样值,但这不允许我添加where子句而不返回空值。我将需要使用presto的“ first_value”选项,但是我无法使用它来处理从动态JSON字段提取的JSON密钥。

SELECT DISTINCT trait, min_by(json_extract(traits, concat('$.', cast(trait AS varchar))), received_at) AS value
FROM TABLE
CROSS JOIN UNNEST(regexp_extract_all(traits,'"([^"]+)"\s*:\s*("[^"]+"|[^,{}]+)', 1)) AS t(trait)
WHERE json_extract(traits, concat('$.', cast(trait AS varchar))) IS NOT NULL OR json_size(traits, concat('$.', cast(trait AS varchar))) <> 0
GROUP BY  trait

1 个答案:

答案 0 :(得分:0)

我不清楚您期望得到的结果以及“第一个非空值”的含义。在您的示例中,您同时具有字符串和数组值,而且都不为空。如果您提供更多示例以及预期的输出,将会很有帮助。

作为解决方案的第一步,这是一种从traits中过滤出空值的方法:

如果将traits列的类型设置为map<string,string>,则应该可以执行以下操作:

SELECT
  request_id,
  MAP_AGG(ARRAY_AGG(trait_key), ARRAY_AGG(trait_value)) AS trait
FROM (
  SELECT
    request_id,
    trait_key,
    trait_value
  FROM some_table CROSS JOIN UNNEST (trait) AS t (trait_key, trait_value)
  WHERE trait_value IS NOT NULL
)

但是,如果您还想过滤数组值并挑选出第一个非空值,那就变得更加复杂了。可以结合使用强制转换为JSON,filter函数和COALESCE来实现。