在代码复杂度方面,编写 JQ 查询时有哪些常见陷阱?任何分析工具?

What are common traps when writing JQ queries in terms on code complexity? Any profiling tools?

我有一个 300 行的 JQ 代码,在我处理的文件上 运行(字面意思是小时)(200K-2.5M JSON 对象的简单列表,500MB-6GB 大小)。

乍一看代码的复杂度是线性的,但我很容易漏​​掉一些东西。

在 JQ 的代码复杂性方面,是否有最常见的陷阱需要注意?或者一些工具来识别我的代码中的关键瓶颈?

我有点不情愿编写我的代码 public,一方面是因为大小和复杂性,另一方面是因为它有些专有性质。

PS。修剪输入文件以仅保留最相关的对象并将其预缩小以仅保留我需要的字段是优化处理流程的明显步骤。我想知道在查询复杂性方面可以具体做什么。

既然你显然不是初学者,你犯初学者错误的可能性似乎很小,所以如果你想不出办法分享你的程序和数据的一些细节,你可以试试 分解程序,以便您可以看到计算资源被消耗的位置。适当的 debug 语句在这方面会有所帮助。

以下用于计算经过的时钟时间的过滤器也可能有帮助:

def time(f):
  now as $start | f as $out | (now - $start | stderr) | "", $out;

def time(f; $msg):
  now as $start | f as $out | ("\(now - $start): \($msg)" | stderr) | "", $out;

例子

def ack(m;n):
  m as $m | n as $n
  | if $m == 0 then $n + 1
    elif $n == 0 then ack($m-1; 1)
    else ack($m-1; ack($m; $n-1))
    end ;

time( ack(3;7) | debug)

输出:

["DEBUG:",1021]
0.7642250061035156
1021

通常,一个比预期花费更长的时间的程序也会产生不正确的结果,所以也许首先要检查的是结果是否正确。如果是,那么以下内容可能值得检查:

  • 避免吸食(即优先使用 input and/or inputs);
  • 当心参数大于 0 的函数调用它们自己;
  • 避免不必要地重新计算中间结果,例如通过将它们存储在 $-variables 中,或通过将它们包含在过滤器的输入中;
  • 尽可能使用具有“短路”语义的函数,特别是 anyall
  • 酌情使用limit/2first/1、and/orforeach
  • index/1 在数组上的实现对于大型数组可能是个问题,因为它首先计算所有索引;
  • 请记住 uniquegroup_by 应谨慎使用,因为两者都涉及 sort.
  • 使用 bsearch 对排序数组中的项目进行插入和二进制搜索;
  • 使用 JSON 对象作为字典通常是个好主意。

另请注意,流式解析器(使用 --stream 选项调用)旨在在时间和 space 之间进行权衡以支持后者。成功了!

最后,jq是面向流的,使用流有时比使用数组更高效。