【问题标题】:How to query and iterate over array of structures in Athena (Presto)?如何在 Athena (Presto) 中查询和迭代结构数组?
【发布时间】:2019-08-06 02:46:25
【问题描述】:

我有一个包含 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 中创建了一个新表

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'

我对@9​​87654324@ 感兴趣,例如。 "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 一起工作得很好,它展平了收入数组,因此上面的数据示例将跨越 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"SALARY"

  2. 我必须遍历数组吗?

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

【问题讨论】:

    标签: sql json amazon-athena presto


    【解决方案1】:

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

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

    此解决方案使用profile.primaryApplicant.incomes 数组上的FILTER 来仅获取具有SALARYincomeType 的那些,然后使用CARDINALITY 提取该结果的长度。


    使用 SQL 引擎,区分大小写绝非易事。总的来说,我认为你不应该期望他们尊重案例,很多人不这样做。尤其是雅典娜explicitly converts column names to lower case

    【讨论】:

    • 感谢 @Theo 解释并提供一个很好的解决方案。这是一个非常快速和有效的。
    【解决方案2】:

    您可以将filtercardinality 组合使用,以过滤多次具有incomeType = 'SALARY' 的数组元素。

    这可以进一步改进,这样中间数组就不会通过使用 reduce 实现(请参阅文档中的示例;我没有在此处引用它们,因为它们不会直接回答您的问题)。

    【讨论】:

    • 感谢@PiotrFindeisen。西奥也有类似的想法。
    猜你喜欢
    • 2020-01-13
    • 2019-11-25
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 1970-01-01
    • 2017-06-17
    • 2020-08-15
    相关资源
    最近更新 更多