JQ:计算每个组的对象数,用于输入的子集
Posted
技术标签:
【中文标题】JQ:计算每个组的对象数,用于输入的子集【英文标题】:JQ: count number of objects per group, for a subset of input 【发布时间】:2019-03-01 01:01:42 【问题描述】:我需要用 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 个最近的条目。
然后我需要以某种方式计算每组的对象数量。
总的来说,看起来我需要一个非常直观的解释,说明数组和对象列表如何相互转换,以及如何修改它们的一些字段,然后只提取所需的字段。不幸的是,到目前为止我发现的教程没有帮助。
【问题讨论】:
【参考方案1】:假设您的输入文件是:
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
请注意,在我的系统上,strptime
的选项 %z
不起作用。所以我把它换成了+0000
(反正时间转换中没有用到)。
【讨论】:
非常感谢,它确实有效!需要澄清两件事:(1)如何将其输出转换为 CSV,即字面意思是"A",2 \n "B",1"
? (2) 您能否分享一些关于 Slurp 开关的易于阅读的描述,以解释为什么您的代码可以使用它(并且没有它就无法工作),以及更一般地说,应该/不使用 Slurp 的经验法则?
@was-s-rubleff (1) 使用[(.[0].class_id), length] | @csv
和-r
选项。 (2)我猜这超出了范围,值得提出自己的问题......【参考方案2】:
accepted answer 使用-s
命令行选项,它要求整个输入数据适合内存。对于非常大的数据集,这可能是不可能的。
自 jq 1.5 发布(2015 年)以来,有一个替代方案可用。因此,这里提出了一种使用inputs
的内存高效解决方案。
关键功能封装在以下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
对于大型数据集,如果 N 的值也很大,那么调整上面的内容以使用 jq 的支持 fot binary search (bsearch
) 而不是 sort_by
可能是值得的。缓存mktime
值可能同样值得。
【讨论】:
哇,在我的情况下,内存方面确实是一个可能的问题,所以感谢您提供的替代解决方案——肯定也会尝试一下。以上是关于JQ:计算每个组的对象数,用于输入的子集的主要内容,如果未能解决你的问题,请参考以下文章