Рубрики
Без рубрики

OQ – портативная/исполнительная обертка JQ

Производительная и портативная обертка JQ, которая облегчает потребление и вывод форматов, отличных от JSON; Использование фильтров JQ для преобразования данных. Tagged с Crystal, JQ, JSON, Python.

Производительная и портативная обертка 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.yaml 


  Jim
  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.json


  
    289
    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”