Json JQ:为输入的子集计算每个组的对象数

Json JQ:为输入的子集计算每个组的对象数,json,stream,grouping,jq,Json,Stream,Grouping,Jq,我需要用JQ计算每个组中的对象数,但只计算N个最近的对象 样本输入,对于N=3: {"modified":"Mon Sep 25 14:20:00 +0000 2018","object_id":1,"group_id":"C"} {"modified":"Mon Sep 25 14:23:00 +0000 2018","object_id":2,"group_id":"A"} {"modified":"Mon Sep 25 14:21:00 +0000 2018","object_id":3,

我需要用JQ计算每个组中的对象数,但只计算N个最近的对象

样本输入,对于N=3:

{"modified":"Mon Sep 25 14:20:00 +0000 2018","object_id":1,"group_id":"C"}
{"modified":"Mon Sep 25 14:23:00 +0000 2018","object_id":2,"group_id":"A"}
{"modified":"Mon Sep 25 14:21:00 +0000 2018","object_id":3,"group_id":"B"}
{"modified":"Mon Sep 25 14:22:00 +0000 2018","object_id":4,"group_id":"A"}
预期产出:

{"A",2}
{"B",1}

我甚至没有选择一个基于日期的子集来保存对象的结构:这是我所能做到的最好的:

 [
   .modified |= strptime("%a %b %d %H:%M:%S %z %Y") |
   .modified |= mktime |
   .modified |= strftime("%Y-%m-%d %H:%M:%S")
 ]  |
 sort_by(.modified) |
 .[] |
 {modified, object_id, group_id}
由于某些原因,结果仍然没有分类

我也无法将这样的列表转换为数组,以便只选择N个最近的条目

在那之后,我需要以某种方式计算每组对象的数量



总的来说,我需要一个非常直观的解释,说明数组和对象列表是如何相互转换的,以及如何修改它们的一些字段,然后只提取所需的字段。不幸的是,到目前为止我发现的教程没有帮助。

假设您的输入文件是:

cat file
{"modified":"Mon Sep 25 14:20:00 +0000 2018","object_id":1,"class_id":"C"}
{"modified":"Mon Sep 25 14:23:00 +0000 2018","object_id":2,"class_id":"A"}
{"modified":"Mon Sep 25 14:21:00 +0000 2018","object_id":3,"class_id":"B"}
{"modified":"Mon Sep 25 14:22:00 +0000 2018","object_id":4,"class_id":"A"}
您可以尝试以下操作:

<file jq -s '
   [ .[] | 
     (.modified |= (strptime("%a %b %d %H:%M:%S +0000 %Y") | mktime)) 
   ] | 
   sort_by(.modified) |              # sort using converted time
   .[-3:] |                          # take the last 3
   group_by(.class_id) |             # group ids together
   .[] |                             
   {(.[0].class_id): length}'        # create the object using the id name and table length
{
   "A": 2
}
{
  "B": 1
}
使用
-s
命令行选项,该选项要求将整个输入数据放入内存中。对于非常大的数据集,这可能是不可能的

自2015年发布jq 1.5以来,有一种替代方案可用。因此,这里提出了一种使用
输入的高效内存解决方案

关键功能封装在以下jq过滤器中:

# Return an array of n items as if by 
# [stream] | sort_by(filter) | .[-n:]
def maxn(stream; filter; n):
  def maxn:
    sort_by(filter) | .[-n :];
  reduce stream as $x ([]; . + [$x] | maxn);
现在,只需另外三行即可获得手头问题(N==3)的解决方案:

maxn(inputs; .modified | strptime("%a %b %d %H:%M:%S +0000 %Y") | mktime; 3)
| group_by(.class_id)[]
| {(.[0].class_id): length}
请注意,这假定使用了-n命令行选项。如果省略,将忽略输入的第一行

大的
对于大型数据集,如果N的值也很大,则可能值得费心调整以上内容,以使用jq对二进制搜索(
bsearch
)的支持,而不是
sort\u by
。同样值得缓存
mktime
值。

非常感谢,它确实有效!有两件事需要澄清:(1)如何将其输出转换为CSV,即字面上的
“A”,2\n“B”,1“
?(2)您能否分享一些易于阅读的关于Slurp开关的描述,解释为什么您的代码可以使用它(没有它就不能工作),以及更一般地,什么时候应该/不应该使用Slurp的经验法则?@wassrublef(1)使用
[([0].class_id),length]|@csv
-r
选项。(2)我想这超出了这里的范围,应该有它自己的问题……哇,内存方面确实是我的一个可能的问题,所以感谢您提供的替代解决方案——肯定也会尝试一下。