Spark извлекает вложенные элементы массива JSON, используя чисто SQL-запрос - PullRequest
0 голосов
/ 27 сентября 2019

Примечание : это НЕ дубликат следующих (или нескольких других аналогичных обсуждений)


У меня есть таблица Hive, которую я должен прочитать, и обрабатывать чисто с помощью Spark -SQL-запроса .В этой таблице есть столбец string, который содержит JSON дампов из API ;как и ожидалось, он имеет глубоко вложенных строковых JSON .

Давайте возьмем этот пример (он отображает точную глубину / сложность данных, которые я пытаюсь обработать)

{
    "key1": ..
    "key2": ..
    ..
    "bill_summary": {
        "key1": ..
        "key2": ..
        ..
        "items": [
            {
                "item": {
                    "key1": ..
                    "key2": ..
                    ..
                    "type": "item_type_1"
                    ..
                    "total_cost": 57.65
                    ..
                }
            },
            {
                "item": {
                    "key1": ..
                    "key2": ..
                    ..
                    "total_cost": 23.31
                    ..
                }
            }
            ..
            {
                "item": {
                    "key1": ..
                    "key2": ..
                    ..
                    "type": "item_type_1"
                    ..
                }
            }
        ]
        ..
    }
    ..
}

Меня интересует массив items.Я могу получить к нему доступ через

get_json_object(get_json_object('$.bill_summary'), '$.items') AS items

Теперь вот проблема

  • Мне нужно вынуть все (type, total_cost) кортежи из массива
  • Но мне нужны только те записи, где присутствуют оба, в то время как несколько item объектов имеют один из них или ни одного из них

  • Пока яТакже удалось отдельно выбрать все type поля и total_cost поля в два отдельных массива , но из-за второго ограничения, указанного выше (отсутствующие поля), я в итоге потерял связь .
  • В итоге я получаю (используя следующий фрагмент) два массива (возможно, разной длины), но не уверен, что соответствующие элементы каждого массива принадлежат одному и тому же элементу или нет

этот фрагмент содержит только часть моего довольно длинного SQL-запроса.Он использует CTE

..
split(get_json_object(get_json_object(var6, '$.bill_summary'), '$.items[*].item.type'), ',') AS types_array,
split(get_json_object(get_json_object(var6, '$.bill_summary'), '$.items[*].item.total_cost'), ',') AS total_cost_array
..

Теперь вот ограничения

  • У меня нет контроля над источником Hive схема таблицы илиего данные
  • Я хочу сделать это, используя чисто Spark SQL-запрос
  • Я не могу использовать DataFrame манипулирование
  • Я не хочу использовать зарегистрированных udf (я сохраняю это в качестве крайней меры)

Я провел несколько часов в документахи форумы, но документы Spark-SQL редки и обсуждения в основном вращаются вокруг DataFrame API, который я не могу использовать.Решена ли эта проблема даже одним SQL-запросом?

1 Ответ

0 голосов
/ 27 сентября 2019

После нескольких часов работы в Интернете, этот ответ намекал мне, что я могу привести строковый массив JSON к массиву структур в spark-sql.Наконец, вот что я сделал

     ..
     var6_items AS
  (SELECT hash_id,
          entity1,
          dt,
          get_json_object(get_json_object(var6,'$.bill_summary'), '$.items[*].item') AS items_as_string
   FROM rows_with_appversion
   WHERE appversion >= 14),

     filtered_var6_items AS
  (SELECT *
   FROM var6_items
   WHERE items_as_string IS NOT NULL
     AND items_as_string != '')

    SELECT from_json(items_as_string, 'array<struct<type:string,total_cost:string>>') AS items_as_struct_array
    FROM filtered_var6_items
     ..

объяснение

  • выражение get_json_object(get_json_object(var6,'$.bill_summary'), '$.items[*].item') AS items_as_string приводит к items_as_string, содержащему следующий (строковый) JSON (обратите внимание, что один уровень избыточенвложенность вокруг каждого item также была удалена)
[
  {
    "key1": "val1",
    "key2": "val2",
    "type": "item_type_1",
    "total_cost": 57.65
  },
  {
    "key1": "val1",
    "key2": "val2",
    "total_cost": 57.65
  }
  ..
  {
    "key1": "val1",
    "key2": "val2",
    "type": "item_type_1"
  }
]
  • после этого функция from_json позволяет преобразовать вышеуказанную структуру в array из structs.Как только это будет получено, я могу filter структур, которые имеют как type и total_cost, а не NULL

Ссылки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...