Обработка JSON-данных в Apache NiFi с JOLT-преобразованиями

Apache Nifi для дата-инженера примеры курсы обучение, JOLT-процессоры Apache NiFi: JOLTTransformJSON JOLTTransformRecord JOLT NiFi processors JSON transformation, JOLT-процессоры JSON Nifi Примеры курсы обучение, обучение Apache NiFi Для инженеров даннхы, Школа Больших Данных Учебный Центр Коммерсант

В этой статье для обучения дата-инженеров и разработчиков ETL-конвейеров на Apache NiFi рассмотрим, как преобразовать JSON-документы с помощью реализации JOLT-библиотеки в процессорах JOLTTransformJSON и JOLTTransformRecord.

Что такое JOLT и как это работает

Человекочитаемый формат JSON активно используется для представления пакетных и потоковых данных. Он легковеснее XML и прост для понимания, поддерживает простые и сложные типы данных, позволяя описывать объекты с целым набором атрибутов, в единичном виде и как массивы. Однако, обработка JSON-документ со множеством вложенных структур становится не самой простой задачей. Чтобы распарсить сообщение в JSON-формате, дата-инженеру приходится выделять вложенные структуры, приводя документ к плоскому виду.

Автоматизировать такие преобразования позволяет Java-библиотека JOLT (JsOn Language to Transform), которая дает возможность перенастроить исходную структуру JSON, которая называется спецификация. Над этой спецификацией выполняются преобразования в виде цепочки операций. Преобразования JOLT описывают исходную и целевую структуры данных. В целевой части преобразования можно ссылаться на отдельные участки исходной части, включая уровни в дереве JSON и ссылки на имена или значения элементов. Для определенных операций JOLT используется ограниченный набор функций, которые не могут быть вложенными и не имеют широких возможностей настройки. Всего их шесть:

  • сдвиг (shift) для перемещения значений в JSON-документе из одного места в другое, чтобы перейти к полю или объекту и выбрать, где разместить это значение в желаемом выводе. Если в спецификации JOLT не указана операция, по умолчанию применяется операция сдвига.
  • По молчанию (default) — операция для вставки новых полей или объектов со значением по умолчанию, если оно не существует. Если поле или объект существует, эта операция не имеет эффекта. Эта операция позволяет добавлять новые ключи в целевой JSON-документ, например, для назначения значений по умолчанию.
  • удаление (remove) для удаления конкретного поля или объекта, вместо которых назначается пустая строка. Если пустая строка не назначена удаляемому полю/объекту, операция завершится ошибкой.
  • сортировка (sort), которая позволяет отсортировать все поля и объекты в JSON-документе в алфавитном порядке, включая массивы и их члены. Примечательно, что сортировка применяется только к именам полей и объектов, а не к их значениям. Это единственная операция, которая не нуждается в определении спецификации, достаточно определить саму операцию.
  • Кардинальность (cardinality), которая позволяет преобразовывать поля и объекты в списки объектов и наоборот.
  • Изменение (modify)modify-default-beta присвоит значение полю, если оно не существует, modify-overwrite-beta перезапишет любое значение, даже если поле уже существует. Операции модификации могут использовать ограниченный набор функций, которые не могут быть вложенными, например toUpper.

Эти стандартные функции преобразования JOLT подходят для структурных изменений в файле JSON, но не для сложной логики и вычислений. Впрочем, дата-инженер может расширить их самостоятельно с помощью пользовательских преобразований Java. JOLT выполняет несколько последовательных преобразований в цепочке: результат выполненного преобразования является входом для следующего за ним.

Чтобы продемонстрировать, как это работает, рассмотрим исходный JSON-документ с данными о событиях пользовательского поведения на сайте:

{
  "userID": 1234567,
  "events": [
    {
      "page": "/blog",
      "eventsType": [
        "scroll",
        "click"
      ]
    },
    {
      "page": "/about",
      "eventsType": [
        "scroll",
        "highlight"
      ]
    },
    {
      "page": "/course/TTIS",
      "eventsType": [
        "scroll",
        "click",
        "sendform"
      ]
    }
  ]
}

Предположим, необходимо получить данные по страницам сайта и категориям пользовательских действий, которые совершаются на них, в следующем виде:

{
  "userID" : 1234567,
  "/blog" : [ "scroll", "click" ],
  "/about" : [ "scroll", "highlight" ],
  "/course/TTIS" : [ "scroll", "click", "sendform" ]
}

Цепочка JOLT-спецификации для преобразования исходного JSON-документа в целевой будет выглядеть следующим образом:

[
{
  "operation": "shift",
  "spec": {
    "events": {
      "*": {
        "eventsType": {
          "*": {
            "@": "@(3,page)[]"
          }
        }
      }
    },
    "*": "&"
  }
}
]

Провалидировать эту JOLT-спецификацию можно с помощью онлайн-инструмента http://jolt-demo.appspot.com/

JOLT JSON tranformation online
Проверка JOLT-спецификации онлайн

В отличие от XML-преобразований XSLT, о которых мы рассказываем здесь, преобразования JOLT не имеют GUI, что осложняет отладку. Еще одна сложность в том, что в JOLT-преобразовании допускается только однократное использование исходного значения для сопоставления его с целевым. Обойти это ограничение можно, скопировав исходный код в несколько временных структур, чтобы использовать их для частичных преобразований, если они требуют использования одних и тех же значений.

Разобравшись с тем, что такое JOLT и как это позволяет преобразовывать JSON-документы, рассмотрим практическое применение этой Java-библиотеки в Apache NiFi.

Преобразование JSON-документов в Apache NiFi

Прежде всего рассмотрим, когда есть необходимость применять JOLT-преобразования в Apache NiFi. Одним из таких случаев является необходимость использования JSONPath, чтобы добраться к определенным элементам исходного JSON-документа. Или же требуется создать сообщение для вызова API из исходных данных в формате JSON, получаемых из внешнего источника. Еще одним сценарием использования JOLT-преобразований в Apache NiFi может стать генерация атрибутов потокового файла, которые содержат информацию о маршрутизации из выражений JSONPath. Чтобы не захочется назначать каждому атрибуту отдельное поле, можно расширить исходный потоковый файл ими в подходящей форме, чтобы упростить маршрутизацию на их основе.

Для работы с JSON-документами в Apache NiFi есть несколько готовых процессоров. Например, процессор FlattenJson может сделать из JSON-документа со вложенными структурами плоский-документ, содержащий только пары ключ/значение. Ключи объединяются на каждом уровне с помощью определяемого пользователем разделителя, который по умолчанию имеет значение «.». Этот процессор поддерживает три режима преобразования (Flatten Mode): normal, keep-arrays (по умолчанию) и dot notation, который часто применяется для запросов в MongoDB.

Для непосредственно JOLT-преобразований в Apache NiFi есть 2 процессора: JOLTTransformJSON и JOLTTransformRecord. Процессор JOLTTransformRecord использует средство чтения и записи записей, а JOLTTransformJSON работает с содержимым потокового файла JSON. В обоих случаях вывод представляется в содержимом потокового файла, а конфигурация преобразования в этих процессорах одна и та же.

Процессоры JOLTTransformJSON и JOLTTransformRecord применяют список спецификаций JOLT к полезной нагрузке JSON потокового файла. При успешном создании нового FlowFile с преобразованным содержимым он направляется в отношение success. Если преобразование JSON завершается с ошибкой, исходный FlowFile направляется в отношение failure. В свойствах процессора определяется исходный и целевой JSON-документы, а также сама JOLT-спецификация с цепочкой операций для этого преобразования.

JOLT-процессоры Apache NiFi: JOLTTransformJSON  JOLTTransformRecord JOLT NiFi processors JSON transformation
JOLT-процессоры Apache NiFi: JOLTTransformJSON и JOLTTransformRecord

Утилиты JOLT в Apache NiFi не основаны на потоках, поэтому преобразование больших JSON-документов может потреблять большие объемы памяти. В настоящее время поддерживается содержимое FlowFile UTF-8 и спецификации JOLT. Спецификация может быть определена с использованием языка выражений, где атрибуты могут указываться слева или справа в синтаксисе спецификации. Поддерживаются пользовательские JOLT-преобразования, которые реализуют интерфейс преобразования. Модули, содержащие пользовательские библиотеки, которых нет в текущем пути к классу, могут быть включены через свойство каталога пользовательских модулей. Если дата-инженер выбирает преобразование по умолчанию при настройке процессора, но предоставляет спецификацию цепочки, Apache NiFi не предупреждает о том, что спецификация недействительна, и создает потоковые файлы с ошибками.

Кроме непосредственного указания JOLT-спецификации в свойствах процессора в GUI без внешних зависимостей, можно также обратиться к пользовательскому классу Java и дополнительным модулям в файловой системе NiFi. Но это потребует размещения соответствующих файлов на сервере NiFi, что может быть сложно автоматизировать в настройках CI/CD. Однако, для сложных преобразований и вычислений необходим именно такой вариант.

В заключение отметим несколько рекомендаций по использованию JOLT-преобразований в Apache NiFi:

  • Поскольку JOLT-преобразования не являются потоковыми, обрабатываемые JSON-Документы хранятся в памяти, что чревато проблемами в случае их большого объема. Тогда лучше разделить исходный JSON-документ и обработать его по частям.
  • Тестировать и отлаживать свои преобразования проще всего онлайн, например, с помощью уже упомянутого инструмента http://jolt-demo.appspot.com/. Это намного быстрее и удобнее, чем каждый раз выполнять изменения в самом NiFi.
  • Не стоит выполнить сложное преобразование сразу, лучше представить его как цепочку нескольких последовательных шагов.
  • Чтобы реализовать поиск по ключу/значению, придется использовать несколько источников; поле, которое содержит ключ для поиска и ссылочный объект, содержащий значение. Эти источники необходимо объединить и использовать для присвоения целевого значения.
  • Операция сортировки определенных элементов в сообщении не специфична и сортирует все (содержимое массива, ключи в объектах). Операции изменения (модификации) позволяют использовать функцию сортировки. Однако, сортировка не выполняется рекурсивно и не может просортировать объекты на основе ключа внутри объекта.
  • В одном и том же JOLT-преобразовании (сдвиге) один источник ввода с множеством вложенных объектов можно использовать только один раз. Если необходимо многократное использование входных данных для разных целей, их следует скопировать их в несколько элементов, применяя к каждому из них свое преобразование.

Какие уязвимости связаны с рассмотренными процессорами, читайте в нашей новой статье.

Как эффективно применять Apache NiFi  для построения высокопроизводительных ETL-конвейеров потоковой аналитики больших данных, вы узнаете на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:

Я даю свое согласие на обработку персональных данных и соглашаюсь с политикой конфиденциальности.

Источники

  1. https://medium.com/big-industries/howto-series-JOLT-part-1-44ebc818ffd6
  2. https://habr.com/ru/post/585184/
  3. https://technology.amis.nl/tech/apache-nifi-having-fun-with-JOLT-transformations/
  4. https://nifi.apache.org/docs/nifi-docs/components/org.apache.nifi/nifi-standard-nar/1.5.0/org.apache.nifi.processors.standard.JOLTTransformJSON/
  5. https://intercom.help/godigibee/en/articles/4044359-transformer-getting-to-know-jolt

Поиск по сайту