如何优化Jsonata计算连续记录时间差的性能?
优化Jsonata数组处理性能:添加elapsed属性
需求说明
我有一个每个对象都包含timestamp属性的数组,需要为数组中的每个对象添加名为elapsed的属性:
- 第一条记录的
elapsed值为当前时间($millis())与该记录timestamp的毫秒差 - 后续记录的
elapsed值为当前记录与前一条记录timestamp的毫秒差
现有代码功能正常,但处理数千条记录时速度极慢,希望通过缓存每次迭代中的timestamp值,避免重复从数组中获取$a[$i-1].timestamp来提升性能。
测试数据
{"events":[ { "a": "alpha", "b": "beta", "counting": 1, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780031105 }, { "a": "alpha", "b": "beta", "counting": 2, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780031532 }, { "a": "alpha", "b": "beta", "counting": 3, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780032058 }, { "a": "alpha", "b": "beta", "counting": 4, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780032544 }, { "a": "alpha", "b": "beta", "counting": 5, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780033056 }, { "a": "alpha", "b": "beta", "counting": 6, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780033559 }, { "a": "alpha", "b": "beta", "counting": 7, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780034034 }, { "a": "alpha", "b": "beta", "counting": 8, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780034564 }, { "a": "alpha", "b": "beta", "counting": 9, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780035036 }, { "a": "alpha", "b": "beta", "counting": 10, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780035589 }, { "a": "alpha", "b": "beta", "counting": 11, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780036035 }, { "a": "alpha", "b": "beta", "counting": 12, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780036564 }, { "a": "alpha", "b": "beta", "counting": 13, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780037036 }, { "a": "alpha", "b": "beta", "counting": 14, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780037559 }, { "a": "alpha", "b": "beta", "counting": 15, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780038059 }, { "a": "alpha", "b": "beta", "counting": 16, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780038560 }, { "a": "alpha", "b": "beta", "counting": 17, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780039066 }, { "a": "alpha", "b": "beta", "counting": 18, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780039538 }, { "a": "alpha", "b": "beta", "counting": 19, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780040061 }, { "a": "alpha", "b": "beta", "counting": 20, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780040567 }, { "a": "alpha", "b": "beta", "counting": 21, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780041039 }, { "a": "alpha", "b": "beta", "counting": 22, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780041561 }, { "a": "alpha", "b": "beta", "counting": 23, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780042050 }, { "a": "alpha", "b": "beta", "counting": 24, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780042567 }, { "a": "alpha", "b": "beta", "counting": 25, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780043040 }, { "a": "alpha", "b": "beta", "counting": 26, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780043567 }, { "a": "alpha", "b": "beta", "counting": 27, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780044041 }, { "a": "alpha", "b": "beta", "counting": 28, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780044606 }, { "a": "alpha", "b": "beta", "counting": 29, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780045040 }, { "a": "alpha", "b": "beta", "counting": 30, "_event": "node:c6cc8e092ff036f1-ff15099a3bf7ad90", "timestamp": 1740780045560 } ]}
现有代码
$map(events, function($v, $i, $a){ $v ~> |$| { "elapsed" : $i = 0 ? ($millis() - $v.timestamp) : $v.timestamp - $a[$i-1].timestamp }| } )
优化方案
使用$reduce替代$map,利用$reduce的累加器维护迭代状态(缓存前一条记录的timestamp),避免每次迭代都去原数组中查找前一个元素,大幅降低大数组处理的性能开销。
优化后的代码
$reduce(events, function($accumulator, $current) { // 计算当前记录的elapsed值 $elapsed := $accumulator.previousTimestamp = null ? ($millis() - $current.timestamp) : ($current.timestamp - $accumulator.previousTimestamp); // 为当前记录添加elapsed属性 $newRecord := $current ~> |$| { "elapsed": $elapsed }|; // 更新累加器:追加新记录到结果数组,缓存当前timestamp { "result": $append($accumulator.result, [$newRecord]), "previousTimestamp": $current.timestamp } }, { "result": [], "previousTimestamp": null }).result
优化点说明
- 状态缓存:通过累加器的
previousTimestamp字段缓存上一条记录的时间戳,每次迭代直接使用该值,无需再通过数组索引查找前一个元素,消除了数组索引访问的性能损耗。 - 单次遍历:
$reduce仅需遍历数组一次,而原$map在每次迭代时都要额外访问数组的前一个元素,相当于对数组进行了多次隐式访问。 - 逻辑清晰:将状态维护和记录处理逻辑整合在一次迭代中,代码可读性和执行效率都得到提升。
内容的提问来源于stack exchange,提问作者Shimbone
相关产品推荐
相关产品推荐

