如何查询和迭代 Athena (Presto) 中的结构数组?

How to query and iterate over array of structures in Athena (Presto)?

我有一个包含 500,000+ json 条记录的 S3 存储桶,例如

{
  "userId": "00000000001",
  "profile": {
    "created": 1539469486,
    "userId": "00000000001",
    "primaryApplicant": {
      "totalSavings": 65000,
      "incomes": [
        { "amount": 5000, "incomeType": "SALARY", "frequency": "FORTNIGHTLY" },
        { "amount": 2000, "incomeType": "OTHER", "frequency": "MONTHLY" }
      ]
    }
  }
}

我在 Athena

中创建了一个新的 table
CREATE EXTERNAL TABLE profiles (  
  userId string,
  profile struct<
    created:int,
    userId:string,
    primaryApplicant:struct<
      totalSavings:int,
      incomes:array<struct<amount:int,incomeType:string,frequency:string>>,
    >
  >
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES ( 'ignore.malformed.json' = 'true')
LOCATION 's3://profile-data'

我对 incomeTypes 感兴趣,例如。 "SALARY""PENSIONS""OTHER" 等。并且 运行 此查询每次更改 jsonData.incometype

SELECT jsonData
FROM "sampledb"."profiles"

CROSS JOIN UNNEST(sampledb.profiles.profile.primaryApplicant.incomes) AS la(jsonData)

WHERE jsonData.incometype='SALARY'

这与 CROSS JOIN UNNEST 配合使用效果很好,后者将 incomes 数组展平,因此上面的数据示例将跨越 2 行。唯一奇怪的是 CROSS JOIN UNNEST 将所有字段名称都设为小写,例如。一行看起来像这样:

{amount=1520, incometype=SALARY, frequency=FORTNIGHTLY}

现在有人问我有多少用户有两个或更多 "SALARY" 个条目,例如

      "incomes": [
        { "amount": 3000, "incomeType": "SALARY", "frequency": "FORTNIGHTLY" },
        { "amount": 4000, "incomeType": "SALARY", "frequency": "MONTHLY" }
      ],

我不知道该怎么做。

  1. 如何查询结构数组以查找重复的 incomeTypes of "SALARY"

  2. 我必须遍历数组吗?

  3. 结果应该是什么样的?

您可以组合 filter with cardinality 来多次过滤具有 incomeType = 'SALARY' 的数组元素。

这可以进一步改进,以便使用 reduce 不会具体化中间数组(请参阅文档中的示例;我不会在这里引用它们,因为它们不会直接回答您的问题)。

UNNEST 是一个非常强大的功能,使用它可以解决这个问题。但是,我认为使用 Presto's Lambda functions 更直接:

SELECT COUNT(*)
FROM sampledb.profiles
WHERE CARDINALITY(FILTER(profile.primaryApplicant.incomes, income -> income.incomeType = 'SALARY')) > 1

此解决方案使用 FILTER on the profile.primaryApplicant.incomes array to get only those with an incomeType of SALARY, and then CARDINALITY 来提取该结果的长度。


SQL 引擎很难区分大小写。总的来说,我认为你不应该期望他们尊重大小写,而且很多人不这样做。特别是雅典娜 explicitly converts column names to lower case.