Как сделать запрос и перебрать массив структур в Афине (Престо)? - PullRequest
0 голосов
/ 15 марта 2019

У меня есть корзина S3 с 500 000+ json записей, например.

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

Я создал новую таблицу в Афине

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, который сглаживал массив доходов так, чтоПример данных выше будет охватывать 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. Как должен выглядеть результат?

Ответы [ 2 ]

3 голосов
/ 15 марта 2019

Вы можете объединить filter с cardinality для фильтрации элементов массива, имеющих incomeType = 'SALARY' более одного раза.

Это можно еще улучшить, так что промежуточный массив не материализуется с помощью reduce (см. Примеры в документации; я не цитирую их здесь, поскольку они не отвечают непосредственно на ваш вопрос) .

2 голосов
/ 15 марта 2019

UNNEST - очень мощная функция, и с ее помощью можно решить эту проблему. Тем не менее, я думаю, что использование лямбда-функций Presto более просто:

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

Это решение использует FILTER в массиве profile.primaryApplicant.incomes, чтобы получить только те, которые имеют incomeType из SALARY, а затем CARDINALITY для извлечения длины этого результата.


Чувствительность к регистру никогда не бывает легкой с движками SQL. В общем, я думаю, что вы не должны ожидать, что они будут уважать дело, и многие этого не делают. В частности, Афина явно преобразует имена столбцов в нижний регистр .

...