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

Posted

技术标签:

【中文标题】在 AWS Athena 中查询第一个非空值的动态 JSON 字段【英文标题】:Querying dynamic JSON fields for first non-null value in AWS Athena 【发布时间】:2019-10-08 08:29:54 【问题描述】:

我将事件数据存储在 S3 中,并希望使用 Athena 来查询数据。其中一个字段是动态 JSON 字段,我不知道它的字段名称。因此,我需要查询 JSON 中的键,然后使用这些键来查询该字段的第一个非空值。下面是存储在 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"]
 

所以,我需要一个查询来从特征列(存储为 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】:

我不清楚您期望的结果是什么,以及“第一个非空值”是什么意思。在您的示例中,您同时具有字符串和数组值,并且它们都不是空值。如果您提供更多示例和预期输出,将会很有帮助。

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

如果您将traits 列的类型设置为map&lt;string,string&gt;,您应该可以执行以下操作:

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 来完成。

【讨论】:

以上是关于在 AWS Athena 中查询第一个非空值的动态 JSON 字段的主要内容,如果未能解决你的问题,请参考以下文章

从大表中选择非空字段

AWS Athena - GENERIC_INTERNAL_ERROR:分区值的数量与过滤器的数量不匹配

如何在 Java 中获取第一个非空值?

数据库怎么用非空值填充为空值?

AWS Athena 无法将 FIRST_VALUE() 识别为聚合表达式

如何在 Amazon Athena 上查询(搜索)具有 JSON 值的 sql?