Передовые методы JQ

#json #performance #jq

Вопрос:

Я ищу некоторую помощь, чтобы увеличить свой jq-foo, и мне не помешало бы небольшое руководство. У меня есть несколько заданий etl, которые я пишу с помощью JQ, и я хочу посмотреть, есть ли способ сделать запуски более эффективными с точки зрения загрузки процессора и / или скорости.

Вот образец полезной нагрузки:

 {  "timestamp": 1636601959,  "uniqueId": "Foo",  "value": 10 }, {  "timestamp": 1636601859,  "uniqueId": "Bar",  "value": 13 }  

и я хочу сделать что-то вроде (псевдокода):

 if [ (epoch 15 minutes ago) -le timestamp ]; then   name=uniqueId; value_total=value(total); uniqueId_count=(uniqueId(count_total)) fi  

Прямо сейчас я делаю что-то вроде (псевдокода):

 for jq[timestamps] in $(json); do  if [ (epoch 15 minutes ago) -le timestamp ]; then   name=uniqueId; value_total=(value_total   value); uniqueId_count=(uniqueId_count   1).   fi done  

Есть ли способ упростить это без использования цикла for для перебора каждого объекта, вызывая jq 'select() ...' его снова и снова?

Комментарии:

1. Должно .uniqueId_count ли поле в выводе суммироваться по всему входу или увеличиваться от элемента к элементу?

2. Это число будет равняться общему количеству раз, когда UniqueID появляется в документе json. Поэтому мне в основном нужно получить общее количество groupby(уникальных идентификаторов), которые приходятся на последние 15 минут. Значения также будут суммированы аналогичным образом. Поэтому, если » foo » появляется в разных временных метках, но все в течение 15 минут назад, мне нужно общее значение(10 n n и т. Д.)

3. Но в вашем псевдокоде проверка timestamp -le (epoch 15 minutes ago) обнаружит эти элементы старше 15 минут, а не «в течение последних 15 минут».

4. Ах, совершенно верно, я объяснил это неправильно… это должно быть в течение 15 минут… фактический код выглядит так if [ "${minutes_ago}" -le "${time}" ]; then , где minutes_ago эпоха 15 минут назад и time является отметкой времени json

5. Обновил свой ответ, чтобы отразить все изменения (я надеюсь).

Ответ №1:

Если вы либо избавитесь от запятых между объектами, либо заключите весь ввод в квадратные скобки массива (чтобы получить правильный JSON), то вы можете сделать (используйте -s опцию для {}{}{} стиля или отбросьте ее для [{],{},{}] стиля):

 jq -s --argjson delta $((15*60)) --argjson addvalue 10 '   (now - $delta) as $pivot  | map(select(.timestamp gt;= $pivot))  | group_by(.uniqueId)  | map({  name: first.uniqueId,  value_total: map(.value) | (add   $addvalue),  uniqueId_count: length  })  '   

Комментарии:

1. Это потрясающе, спасибо за это! Я собираюсь попробовать и посмотреть, повезет ли мне… было бы здорово не for зацикливаться на каждом объекте

2. Кроме того, я отредактировал свою операцию, значение=10 на самом деле должно было быть value_total=значение(всего)