如何查询和迭代 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" }
],
我不知道该怎么做。
如何查询结构数组以查找重复的 incomeTypes
of "SALARY"
?
我必须遍历数组吗?
结果应该是什么样的?
您可以组合 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.
我有一个包含 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
中创建了一个新的 tableCREATE 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" }
],
我不知道该怎么做。
如何查询结构数组以查找重复的
incomeTypes
of"SALARY"
?我必须遍历数组吗?
结果应该是什么样的?
您可以组合 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.