我有一个JSON数据集,从Redis商店中提取了大约870万个密钥值对,其中每个密钥保证是一个8位数字,密钥是8个字母数字字符值,即
[{
"91201544":"INXX0019",
"90429396":"THXX0020",
"20140367":"ITXX0043",
...
}]
为了减少Redis内存的使用,我想将其转换为哈希哈希,其中哈希前缀键是密钥的前6个字符(请参阅this link),然后将其存储回Redis。 / p>
具体来说,我想要生成的JSON数据结构(我将编写一些代码来解析这个JSON结构并创建一个由HSET组成的Redis命令文件),看起来更像是
[{
"000000": { "00000023": "INCD1234",
"00000027": "INCF1423",
....
},
....
"904293": { "90429300": "THXX0020",
"90429302": "THXX0024",
"90429305": "THXY0013"}
}]
由于jq给我留下了深刻的印象,并且我想要更精通函数式编程,我想使用 jq 来完成这项任务。到目前为止,我已经提出以下建议:
% jq '.[0] | to_entries | map({key: .key, pfx: .key[0:6], value: .value}) | group_by(.pfx)'
这给了我类似的东西
[
[
{
"key": "00000130",
"pfx": "000001",
"value": "CAXX3231"
},
{
"key": "00000162",
"pfx": "000001",
"value": "CAXX4606"
}
],
[
{
"key": "00000238",
"pfx": "000002",
"value": "CAXX1967"
},
{
"key": "00000256",
"pfx": "000002",
"value": "CAXX0727"
}
],
....
]
我尝试了以下内容:
% jq 'map(map({key: .pfx, value: {key, value}}))
| map(reduce .[] as $item ({}; {key: $item.key, value: [.value[], $item.value]} ))
| map( {key, value: .value | from_entries} )
| from_entries'
确实给了我正确的结果,但也为每次减少(我相信)
打印出错误jq: error: Cannot iterate over null
最终结果是
{
"000001": {
"00000130": "CAXX3231",
"00000162": "CAXX4606"
},
"000002": {
"00000238": "CAXX1967",
"00000256": "CAXX0727"
},
...
}
这是正确的,但我怎么能避免抛出这个stderr警告呢?
答案 0 :(得分:2)
我不确定这里有足够的数据来评估问题的根源。我发现很难相信你所尝试的结果会导致这种情况发生。我一路上都遇到了错误。
请尝试使用此过滤器:
.[0]
| to_entries
| group_by(.key[0:6])
| map({
key: .[0].key[0:6],
value: map(.key=.key[6:8]) | from_entries
})
| from_entries
给出如下数据:
[{
"91201544":"INXX0019",
"90429396":"THXX0020",
"20140367":"ITXX0043",
"00000023":"INCD1234",
"00000027":"INCF1423",
"90429300":"THXX0020",
"90429302":"THXX0024",
"90429305":"THXY0013"
}]
结果如下:
{
"000000": {
"23": "INCD1234",
"27": "INCF1423"
},
"201403": {
"67": "ITXX0043"
},
"904293": {
"00": "THXX0020",
"02": "THXX0024",
"05": "THXY0013",
"96": "THXX0020"
},
"912015": {
"44": "INXX0019"
}
}
答案 1 :(得分:0)
我知道这不是你所要求的,但是,仅仅为了参考,我认为用Redis的内置Lua脚本编写它会更快。
事实证明它更直接:
for _,key in pairs(redis.call('keys', '*')) do
local val = redis.call('get', key)
local short_key = string.sub(key, 0, -2)
redis.call('hset', short_key, key, val)
redis.call('del', key)
end
这将在没有从/向Redis转移到/从JSON转换的情况下完成。
从控制台运行:
$ redis-cli eval "$(cat script.lua)" 0
答案 2 :(得分:0)
对于记录,jq的group_by
依赖于排序,当输入足够大时,这当然会显着减慢速度。即使输入数组只有100,000个项目,以下内容大约快40%:
def compress:
. as $in
| reduce keys[] as $key ({};
$key[0:6] as $k6
| $key[6:] as $k2
| .[$k6] += {($k2): $in[$key]} );
.[0] | compress
鉴于Jeff的输入,输出相同。