Под капотом Apache NiFi: внутренний язык выражений

Автор Категория ,
Под капотом Apache NiFi: внутренний язык выражений

В рамках обучения разработчиков Data Flow и инженеров данных разберем основные принципы внутреннего языка выражений Apache NiFi: что такое атрибуты FlowFile, как манипулировать ими. Синтаксис функций, типы данных, иерархия переменных и другие тонкости Apache NiFi для дата-инженера.

Язык выражений в Apache NiFi как способ манипулировать атрибутами

Напомним, все данные в Apache NiFi представлены абстракцией потокового файла (FlowFile), который состоит из двух основных частей: контента и атрибутов. Контент – это непосредственно данные, с которыми нужно работать. Например, если файл получен из локальной файловой системы с помощью обработчика GetFile, содержимое файла станет контентом FlowFile.

Часть атрибутов FlowFile представляет информацию о самих данных или метаданных. Атрибуты — это пары ключ-значение, которые представляют собой сведения о данных и информацию, полезную для их правильной маршрутизации и обработки. Например, для файла, полученным из локальной файловой системы, FlowFile будет иметь соответствующий атрибут, который отражает имя исходного файла в файловой системе. Также FlowFile будет иметь атрибут пути, отражающий каталог в файловой системе, где находился исходный файл и атрибут уникального идентификатора FlowFile – UUID.

Язык выражений (Expression Language) NiFi позволяет ссылаться на эти атрибуты, сравнивать их с другими значениями и манипулировать значениями. Язык выражений NiFi всегда начинается с начального разделителя ${ и заканчивается конечным разделителем }. Между начальным и конечным разделителями находится текст самого выражения. В своей самой простой форме Expression может состоять только из имени атрибута. Например, ${filename} вернет значение атрибута имени файла. Причем между символами $ и не должно быть пробела!

Можно манипулировать этими значениями, к примеру, вернуть версию имени файла в верхнем регистре, вызвав функцию toUpper: ${filename:toUpper()}. Вызов функции toUpper в данном случае состоит из следующих элементов:

  • разделитель вызова функции – знак двоеточие (:);
  • имя функции (toUpper)
  • открывающая скобка ((), за которой следуют аргументы функции, если они требуются. У функции toUpper нет аргументов, поэтому этот элемент опущен.
  • закрывающая скобка ()) указывает на конец вызова функции.

Язык выражений поддерживает множество различных функций для разных целей. Некоторые функции работают со строками (текстом), другие – позволяют сравнивать значения числовых и булевых переменных. Есть функции для управления датами и временем, а также для выполнения математических операций. При вызове функции для атрибута, к нему идет обращение как к предмету функции. Можно объединить несколько вызовов функций, где возвращаемое значение первой функции становится предметом второй функции, а его возвращаемое значение становится предметом следующей функции и пр. Например, объединим несколько функций, используя выражение ${filename:toUpper():equals(‘HELLO.TXT’)}. Количество функций, которые можно связать вместе, не ограничено.

На любой атрибут FlowFile можно ссылаться с помощью языка выражений. Но, если имя атрибута содержит специальный символ, такой как $, скобки, знак табуляции, пробелы и пр., имя атрибута необходимо экранировать, заключив его в кавычки. Число также считается специальным символом, если оно является первым символом имени атрибута. Если какой-либо из этих спецсимволов присутствует в атрибуте, он заключается в одинарные или двойные кавычки. Например, для экранирования атрибута с именем my attribute можно использовать следующее: ${“my attribute”} или ${‘my attribute’}.

Также существуют некоторые функции, которые предполагают отсутствие субъекта и вызываются просто, например, ${hostname()}. Затем эти функции также могут быть изменены вместе. Например, ${hostname():toUpper()}. Но попытка использовать для этой функции сравнение с субъектом приведет к ошибке.

Если нужно сравнить значения двух разных атрибутов друг с другом, можно использовать встроенные выражения. Например, проверить, совпадает ли атрибут имени файла с атрибутом uuid: $ {filename:equals(${uuid})}. Язык выражений игнорирует пробелы между разделителями, поэтому данное выражение можно записать как $ {filename: equals(${uuid})} или $ {filename:equals(${uuid})}. Но запись $ {file name:equals(${uuid})} с пробелом между файл (file) и имя (name) будет интерпретировать их как разные токены, т.е. элементы выражения. Напомним, между символами $ и не должно быть пробела!

Иерархия и практика применения языка выражений

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

  • Поиск FlowFile для атрибута/ключа;
  • Поиск переменных группы процессов для атрибута/ключа;
  • Поиск файла реестра файлов для атрибута/ключа;
  • Поиск свойств NiFi JVM для атрибута/ключа;
  • Поиск переменных системной среды для атрибута/ключа.

NiFi будет искать и возвращать первое вхождение соответствующего свойства. Если соответствующее свойство не найдено, возвращается null. Язык выражений широко используется во всем приложении NiFi для настройки свойств процессора, но не все свойства процессора поддерживают Expression Language. Независимо от того, поддерживает ли свойство язык выражений, разработчик процессора NiFi определяет его при написании. Само приложение стремится четко проиллюстрировать для каждого свойства, поддерживается ли язык выражений. Например, при настройке свойства компонента веб-GUI предоставляет значок информации (Info) рядом с именем свойства. При наведении указателя мыши на этот значок отображается всплывающая подсказка с полезной информацией о свойстве, включая описание, значение по умолчанию, ранее сконфигурированные значения и область оценки этого свойства для языка выражений:

  • NONE— язык выражений не поддерживается для этого свойства;
  • VARIABLE_REGISTRY (реестр переменных) строится иерархически – переменные определяются на уровне группы процессов, а затем, рекурсивно, до группы процессов более высокого уровня до корневой группы процессов. Далее следуют переменные, определенные в файлах пользовательских свойств через свойство nifi.variable.registry.properties в файле nifi.properties, а затем переменные среды, определенные на уровне JVM и свойствах системы;
  • FLOWFILE_ATTRIBUTES (атрибуты потокового файла) – будут использоваться атрибуты каждого отдельного файла потока, а также те переменные, которые определены в реестре переменных.

При настройке значения свойства «Процессор» веб-GUI NiFi помогает работать с языком выражений с помощью встроенного редактора, который выделяет открывающие/закрывающие скобки, предоставляет контекстно-зависимую справку со списком всех доступных функций. Функции предоставляют удобный способ управления и сравнения значений атрибутов. Язык выражений предоставляет множество различных функций для удовлетворения потребностей автоматизированного потока данных. Каждая функция принимает ноль или более аргументов и возвращает одно значение. Функции могут быть объединены в цепочку для создания мощных выражений для оценки условий и управления значениями. Каждый аргумент функции и каждое значение, возвращаемое функцией, имеют определенный тип данных:

  • Строка (String) — последовательность символов из цифр, букв, пробелов и спецсимволов;
  • Число (Number) — целое число из одной или нескольких цифр от 0 до 9. При преобразовании в числа из типов данных Date они представляются как количество миллисекунд с полуночи по Гринвичу 1 января 1970 года.
  • Decimal — числовое значение, которое может поддерживать десятичные и более крупные значения с минимальной потерей точности, числовой тип с плавающей запятой двойной точности. Этот тип данных не рекомендуется использовать для очень точных значений, включая денежные значения.
  • Дата (Date) — объект, который содержит дату и время. Используя функции Date Manipulation и Type Coercion, этот тип данных можно преобразовать в/из строк и чисел.
  • Логическое значение (Boolean) – истина (true) или ложь (false).

После оценки функций языка выражений все атрибуты сохраняются как тип String. Язык выражений обычно может автоматически приводить значение одного типа данных к соответствующему типу данных для функции. Также пользователь NiFi может вручную привести значения к определенному типу данных.

Шестнадцатеричные значения поддерживаются для числовых и десятичных типов, но они должны быть заключены в кавычки и начинаться с «0x», когда они интерпретируются как литералы. Например, эти два выражения допустимы, но без кавычек или “0x” они не будут работать корректно: ${literal(“0xF”):toNumber()} и ${literal(“0xF.Fp10”):toDecimal()}.

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

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

Источники

  1. https://nifi.apache.org/docs/nifi-docs/html/expression-language-guide.html