Как стать автором
Обновить

Apache NiFi & Jolt Transform

Время на прочтение5 мин
Количество просмотров1.7K

Добрый день! Продолжаем тематику использования Jolt Transform. Возможно, кто-то уже ознакомился с моей предыдущей статьей на этут тему. Сегодня я попробую разобрать реализацию ещё одной задачи с помощью Apache NiFi и Jolt Transform.

Итак, задача с телеграмм-канала Powerful NiFi, участник dubrovski82 задал вопрос. Есть json:

{
  "Предупреждения" : {
    "ПРЕДУПРЕЖДЕНИЕ" : "Этот картриджей."
  },
  "Основные характеристики" : {
    "Назначение" : "Для печатающих устройств",
    "Производитель" : "Static Control",
    "Цвет чернил" : "Пурпурный (Magenta)",
    "Тип оборудования" : "Картридж",
    "описание" : "Великолепный картридж",
    "Модель" : "002-01-VF353A"
  }
}

Надо обратиться к последнему элементу общего списка, чтобы из него вытащить одно поле.

dubrovski82: Дело в том, что тут как раз задача стоит в том, чтобы вытянуть это поле "описание" из последнего блока в json файле.

Предполагается, что в файле будет, как минимум, один блок. И, соответственно, мне вначале надо определить последний блок, потом из него вытянуть "описание".
В приведенном примере выше всего два блока в файле: Предупреждения и Основные характеристики. И "последний" блок это "Основные характеристики". Для других файлов это могут быть другие названия.

Исходя из обсуждения было определено, что исходный json должен быть помещён в поле "isDescript"."details". А поле "описание" нужно перенести в поле "isDescript"."description". Итак, ожидаемый результат трансформации выглядит так:

{
  "isDescript": {
    "details": {
      "Предупреждения": {
        "ПРЕДУПРЕЖДЕНИЕ": "Этот картриджей."
      },
      "Основные характеристики": {
        "Назначение": "Для печатающих устройств",
        "Производитель": "Static Control",
        "Цвет чернил": "Пурпурный (Magenta)",
        "Тип оборудования": "Картридж",
        "Модель": "002-01-VF353A"
      }
    },
    "description": "Великолепный картридж"
  }
}

Будем рассчитывать, что поле "описание" должно присутствовать в искомом блоке. Понятие "последний блок" для JSON несколько не специфично, поскольку стандарт не декларирует порядок "блоков". Иначе, всё сильно усложняется и задача может не иметь решения средствами Jolt Transform.

Добавляем в нашу процессорную группу процессор JoltTransformJSON

В настройках процессора пока ничего не меняем, сразу переходим в Properties -> Advanced

И помещаем в поле JSON Input наш исходный JSON

В поле Jolt Specification будем описывать спецификацию для трансформации нашего JSON

Для решения нашей задачи спецификация получается довольно простой. Думаю, что нет смысла описывать процесс написания, сразу приведу её и попробую выполнить.

[{
	"operation": "shift",
	"spec": {
		"*": {
			"описание": "isDescript.description",
			"*": "isDescript.details.&1.&"
		}
	}
}]

Проверяем, что оно работает.

Как мы видим, результат совпадает с ожидаемым.

{
	"isDescript": {
		"details": {
			"Предупреждения": {
				"ПРЕДУПРЕЖДЕНИЕ": "Этот картриджей."
			},
			"Основные характеристики": {
				"Назначение": "Для печатающих устройств",
				"Производитель": "Static Control",
				"Цвет чернил": "Пурпурный (Magenta)",
				"Тип оборудования": "Картридж",
				"Модель": "002-01-VF353A"
			}
		},
		"description": "Великолепный картридж"
	}
}
Разверните, чтобы увидеть пояснение по данной спецификации

Итак, для поиска поля "описание" мы должны просканировать второй уровень исходного джейсона. Для этого мы просматриваем все элементы первого уровня, об этом говорит первая звёздочка "*": { ... }

"описание": "isDescript.description" - на втором уровне вложенности мы ищем поле "описание" и кладём его в результирующий json в поле isDescript.description.

"*": "isDescript.details.&1.&" - все остальные поля второго уровня кладём в те же поля в структуре первого уровня, но помещая саму структуру в поле isDescript.details

Это решение я и привел в качестве ответа на вопрос. Но, потом подумал...

Немного усложним задачу. Что, если на первом уровне появится поле, которое не содержит вложенных полей. Или простое поле, массив, пустой массив, или null.

{
	"Предупреждения": {
		"ПРЕДУПРЕЖДЕНИЕ": "Этот картриджей."
	},
	"Основные характеристики": {
		"Назначение": "Для печатающих устройств",
		"Производитель": "Static Control",
		"Цвет чернил": "Пурпурный (Magenta)",
		"Тип оборудования": "Картридж",
		"описание": "Великолепный картридж",
		"Модель": "002-01-VF353A"
	},
  
  	"Пустой объект": {},
    "Массив": [1,2,3],
    "Пустой массив": [],
  	"Что-то": "ещё",
    "Null": null  
}

К сожалению, наше решение не работает в таком случае. Результат удручает - некоторые поля потеряны, какие-то выглядят неожиданно:

{
	"isDescript": {
		"details": {
			"Предупреждения": {
				"ПРЕДУПРЕЖДЕНИЕ": "Этот картриджей."
			},
			"Основные характеристики": {
				"Назначение": "Для печатающих устройств",
				"Производитель": "Static Control",
				"Цвет чернил": "Пурпурный (Magenta)",
				"Тип оборудования": "Картридж",
				"Модель": "002-01-VF353A"
			},
			"Массив": {
				"0": 1,
				"1": 2,
				"2": 3
			},
			"Что-то": {
				"ещё": null
			}
		},
		"description": "Великолепный картридж"
	}
}

Будем исправлять, и.... Кажется, нам просто надо взять другой шаблон (подстановочный знак) вместо "*" - "@"

@ - шаблон, который необходим, если вы хотите поместить как входное значение, так и входной ключ куда-нибудь в выходной JSON. Но, если мы напишем просто:

[{
	"operation": "shift",
	"spec": {
		"*": {
			"описание": "isDescript.description",
			"@": "isDescript.details"
		}
	}
}]

то получим следующее:

{
	"isDescript": {
		"details": [{
				"ПРЕДУПРЕЖДЕНИЕ": "Этот картриджей."
			}, {
				"Назначение": "Для печатающих устройств",
				"Производитель": "Static Control",
				"Цвет чернил": "Пурпурный (Magenta)",
				"Тип оборудования": "Картридж",
				"описание": "Великолепный картридж",
				"Модель": "002-01-VF353A"
			}, {},
			[1, 2, 3],
			[], "ещё", null
		],
		"description": "Великолепный картридж"
	}
}

Мы потеряли ключи, надо их вернуть, для этого вернём подстановочный знак & в правую часть:

[{
	"operation": "shift",
	"spec": {
		"*": {
			"описание": "isDescript.description",
			"@": "isDescript.details.&"
		}
	}
}]

& - подстановочный знак, в правой части он обычно используется совместно со знаком "*" в левой части. Полная форма - "&(0,0)".

Первый параметр - это то, где во входном пути искать значение (на каком уровне):

{
   "foo" : {
     "bar": {
       "baz":  // &0 = baz, &1 = bar, &2 = foo
     }
   }
 }

Второй параметр - указывает на ту часть ключа, которую надо использовать:

// Если у нас есть исходный ключ "tag-Foo-Bar" 
"tag-*-*": "&(0,0)" = "tag-Foo-Bar"
"tag-*-*": "&(0,1)" = "Foo"
"tag-*-*": "&(0,2)" = "Bar"

Так как у нас в левой части стоит шаблон "@", то использование второго параметра, отличного от 0 будет приводить к ошибке. А вот с первым будет несколько недетерминированное проведение, а точнее "&" = "&0", что как бы очевидно, но тут еще и "&" = "&0" = "&1" (для "&2" всё ок, как ожидается, на наших входных данных это - root). Скорее всего это вызвано тем, что @ берёт ключ и значение (как бы два уровня), а & всегда означает ключ. Но, нам нет необходимости, в нашем случае, указывать параметры для шаблона.

Финальная спецификация:

[{
	"operation": "shift",
	"spec": {
		"*": {
			"описание": "isDescript.description",
			"@": "isDescript.details.&"
		}
	}
}]

Итак, мы получили в результате:

{
	"isDescript": {
		"details": {
			"Предупреждения": {
				"ПРЕДУПРЕЖДЕНИЕ": "Этот картриджей."
			},
			"Основные характеристики": {
				"Назначение": "Для печатающих устройств",
				"Производитель": "Static Control",
				"Цвет чернил": "Пурпурный (Magenta)",
				"Тип оборудования": "Картридж",
				"описание": "Великолепный картридж",
				"Модель": "002-01-VF353A"
			},
			"Пустой объект": {},
			"Массив": [1, 2, 3],
			"Пустой массив": [],
			"Что-то": "ещё",
			"Null": null
		},
		"description": "Великолепный картридж"
	}
}

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Актуальны ли статьи про Apache NiFi?
16.67% Jolt и ничего более…1
83.33% Что там ещё есть?5
0% В топку…0
Проголосовали 6 пользователей. Воздержался 1 пользователь.
Теги:
Хабы:
Всего голосов 3: ↑3 и ↓0+3
Комментарии9

Публикации

Истории

Работа

Data Scientist
56 вакансий

Ближайшие события

Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн
Антиконференция X5 Future Night
Дата30 мая
Время11:00 – 23:00
Место
Онлайн
Конференция «IT IS CONF 2024»
Дата20 июня
Время09:00 – 19:00
Место
Екатеринбург