Производительная и портативная обертка JQ, которая облегчает потребление и вывод форматов, отличных от JSON; Использование фильтров JQ для преобразования данных.
Фон
Я использовал JQ Некоторое время для преобразования документа Master JSON в зависимые от партнера структуры для их потребления. Однако до недавнего времени все партнерские структуры также были в JSON. С тех пор jq
Не поддерживает вывод XML самостоятельно, я начал осматриваться, чтобы увидеть, есть ли какие -либо библиотеки, которые позволят использовать jq
Фильтры для преобразования данных, но вывод XML в дополнение к JSON. Я закончил тем, что нашел библиотеку Python под названием yq Это казалось идеальным.
Он поддерживает вывод в XML и JSON, в то же время способный использовать то же самое JQ
Фильтр для обоих. Показав с этим на некоторое время стало ясно, что, хотя и довольно быстро для небольших файлов, это действительно боролось с некоторыми из более крупных документов, которые мне нужно было обработать. Тот факт, что это Python, также усложняет вещи, поскольку Python должен быть установлен для его использования, не проходя через какой -то дополнительный процесс, чтобы сделать его единственным бинарным бинарным. Таким образом, идея для более эффективного и портативного варианта начала формироваться.
Введение
Используя относительно новое Кристалл язык; Я создал OQ С основными целями – портативность, производительность и расширение форматов, которые JQ
поддержка.
Применение
OQ
Имеет три дополнительных аргумента, которые устанавливают входные/выходные форматы для использования, в дополнение к имени корневого элемента, если сериализация на XML. Все остальные аргументы передаются jq
.
Примеры
Потребление JSON и вывода XML
echo '{"name": "Jim"}' | oq -o xml .Jim
Потребление JSON и вывода YAML
echo '{"name": "Jim"}' | oq -o yaml . -------- name: Jim
Потребляйте YAML из файла и вывода XML
Data.yaml
-------- name: Jim numbers: - 1 - 2 - 3
oq -i yaml -o xml . data.yamlJim 1 2 3
Потреблять JSON, преобразовать его и вывести XML
data.json
{ "guests": [ { "name": "Jim", "age": 17, "numbers": [ 1, 2, 3 ] }, { "name": "Bob", "age": 51, "numbers": [ 4, 5, 6 ] }, { "name": "Susan", "age": 85, "numbers": [ 7, 8, 9 ] } ] }
фильтр
.guests | { "person": [ .[] | { "age": { "@scale": .scale, "#text": .age }, "name": .name, "favorite_numbers": { "number": .numbers } } ] }
oq -o xml --xml-root people -f filter data.json289 Jim 1 2 3 51 Bob 4 5 6 31025 Susan 7 8 9
Подход к обработке JSON к транскодированию XML основан на Эта статья Анкет
Тесты
Я также провел немного тесты для jq
, yq
В и OQ
Чтобы показать, как они сравниваются в различных ситуациях.
Настраивать
ОПЕРАЦИОННЫЕ СИСТЕМЫ: #1 SMP Debian 4.9.168-1+deb9u3 (2019-06-16)
ЦП: Intel i7-7700K
Память: 32 ГБ @ 3000 МГц
SSD: Samsung 850 Pro - 512 ГБ
Тесты выполняются через /usr/bin/time -v
командование
Простой
Сначала я использовал data.json
Файл, чтобы увидеть, как они выполняют, просто анализируя файл и выводит сам через Анкет
фильтр.
jq
jq . data.json | wc -l Command being timed: "jq . data.json" User time (seconds): 0.02 System time (seconds): 0.01 Percent of CPU this job got: 68% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.06 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 16236 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 0 Minor (reclaiming a frame) page faults: 3860 Voluntary context switches: 224 Involuntary context switches: 8 Swaps: 0 File system inputs: 0 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0 31
yq
yq . spec/assets/data1.json | wc -l Command being timed: "yq . data.json" User time (seconds): 0.08 System time (seconds): 0.01 Percent of CPU this job got: 77% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.11 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 16252 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 1 Minor (reclaiming a frame) page faults: 7179 Voluntary context switches: 189 Involuntary context switches: 10 Swaps: 0 File system inputs: 1672 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0 31
ок
oq . data.json | wc -l Command being timed: "oq . data.json" User time (seconds): 0.02 System time (seconds): 0.04 Percent of CPU this job got: 74% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.10 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 16140 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 0 Minor (reclaiming a frame) page faults: 4499 Voluntary context switches: 306 Involuntary context switches: 13 Swaps: 0 File system inputs: 0 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0 31
Для этого первого теста все три в значительной степени равны, с использованной только незначительной разницей в WallClock/Memory.
Jeopardy.json (#2)
Следующий эталон использует jeopardy.json
~ 56 МБ файл, как получено в JQ
Стандартная страница вики.
Во -первых, простой Длина jeopardy.json
командование
jq
jq length jeopardy.json 216930 Command being timed: "jq length jeopardy.json" User time (seconds): 0.64 System time (seconds): 0.10 Percent of CPU this job got: 97% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.76 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 230080 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 0 Minor (reclaiming a frame) page faults: 63213 Voluntary context switches: 240 Involuntary context switches: 13 Swaps: 0 File system inputs: 0 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0
yq
yq length jeopardy.json 216930 Command being timed: "yq length jeopardy.json" User time (seconds): 152.45 System time (seconds): 1.27 Percent of CPU this job got: 100% Elapsed (wall clock) time (h:mm:ss or m:ss): 2:33.04 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 3853532 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 0 Minor (reclaiming a frame) page faults: 1117041 Voluntary context switches: 13708 Involuntary context switches: 3189 Swaps: 0 File system inputs: 0 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0
ок
oq length jeopardy.json 216930 Command being timed: "oq length jeopardy.json" User time (seconds): 0.67 System time (seconds): 0.17 Percent of CPU this job got: 105% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.80 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 230224 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 0 Minor (reclaiming a frame) page faults: 63839 Voluntary context switches: 13832 Involuntary context switches: 12 Swaps: 0 File system inputs: 0 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0
Большие файлы не судят хорошо с yq
, с этим, занимая ~ 190x длиннее, чем OQ
или jq
, в то же время используя почти на 17 раз больше памяти.
Yaml => xml
Последний эталон, который я сделал, – это дал оба yq
и OQ
Большой файл YAML (~ 57 МБ), затем их преобразование в XML. С тех пор jq
Не могу потреблять Yaml
, Я исключил это.
Используемый файл: Invitems.yaml
из Eve Online SDE Export Анкет
Пример ввода:
- flagID: 0 itemID: 0 locationID: 0 ownerID: 0 quantity: -1 typeID: 0 - flagID: 0 itemID: 1 locationID: 0 ownerID: 0 quantity: -1 typeID: 0 ...
yq
Для YQ мне пришлось дать ему фильтр и несколько дополнительных аргументов для правильного вывода
yq -s -x --xml-root items --xml-dtd '{"item": .[] | .}' invItems.yaml > invItems.yq.xml Command being timed: "yq -s -x --xml-root items --xml-dtd {"item": .[] | .} invItems.yaml" User time (seconds): 309.21 System time (seconds): 2.76 Percent of CPU this job got: 100% Elapsed (wall clock) time (h:mm:ss or m:ss): 5:11.90 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 7817608 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 0 Minor (reclaiming a frame) page faults: 2262904 Voluntary context switches: 32918 Involuntary context switches: 2504 Swaps: 0 File system inputs: 0 File system outputs: 195072 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0
Пример вывода
0 0 0 0 -1 0 - ...
0 1 0 0 -1 0
ок
oq -i yaml -o xml --xml-root items . invItems.yaml > invItems.oq.xml Command being timed: "oq -i yaml -o xml --xml-root items . invItems.yaml" User time (seconds): 20.08 System time (seconds): 0.48 Percent of CPU this job got: 107% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:19.13 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 1332328 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 0 Minor (reclaiming a frame) page faults: 522235 Voluntary context switches: 30478 Involuntary context switches: 974 Swaps: 0 File system inputs: 0 File system outputs: 195072 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0
Пример вывода
0 0 0 0 -1 0 - ...
0 1 0 0 -1 0
Аналогично jeopary.json
эталон, yq
Просто трудно справиться с более крупными входами с этим тестовым примером, занимающим ~ 16x длиннее и используя почти 6x память, чем OQ
Анкет
Дорога до 1.0.0
Поскольку этот проект все еще в начале развития, я собрал дорожную карту того, что я хотел бы сделать, прежде чем называть его 1.0.0
:
- Поддержка входного формата XML
- Адресовать ошибки/проблемы, которые возникают
- Небольшие запросы функций
- Возможно, дополнительные форматы
Не стесняйтесь представлять проблемы/PRS.
Оригинал: “https://dev.to/blacksmoke16/oq-a-portable-performant-jq-wrapper-18ka”