逆向还原 json schema
问题定义
典型的 json schema 可以表示成一个树结构(多根节点是森林) ,因为数据实际生成传输和存储过程中字段允许缺省, 我们抓包一条看到是局部树结构, 只要收集足够多局部树结构, 理论上可以拼凑出完整树结构。
下面说说怎么做:
我们假定手上有1G json 碎片文件, 没有原始 json schema:
这 1G 文件全部来自一份 json 树
这 1G 文件已经完整包含 json 树每个分支
不失一般性,每个碎片 json 写成 1行, 所有文件放到一个文件 xxx.json, 我的测试样本大约1000000行。
问题解决
jq -c 'paths(.)' xxx.json | sed '/^\[[0-9]*\]$/d; s/^\[[0-9]*,/X,/; s/,[0-9]*,/,X,/g; s/,[0-9]*\]$/,X/; s/\]$//; s/^\[//; s/\"//g' | awk '!unique[$0]++' | awk -F"," '{from="";for(i=1;i<NF;i++){from=from""$i;to=from""$(i+1);printf("[%s]{label: \"%s\"} -> [%s]{label: \"%s\"}\n", from, $i, to, $(i+1))}}' | sort -u | graph-easy --as dot | dot -Tpng > datastructure.png
这就是全部代码,7 行后面会逐行解释功能。
输出 json schema
代码解析
上面7行代码对应管道7个部分, 按行依次说明:
构造树
jq : 用 ‘paths’ 方法提取每一条从根节点到叶子节点的路径 root -> p1 -> p2 -> ... -> leaf, 这一步问题已经解决一半。
压缩树
sed:替换数字和字符串,将叶子节点的value 的差异抹平,这样可以突出 key 构成的树形结构。例如:所有 name: xxx 经过替换变成一样的记录。
awk:压缩上一步结果,只保留结构部分, 叶子节点的差异丢弃, 100万子树变成1000个子树。这一步很重要。
合并树
awk:将 jq 的paths 输出 root -> p1 -> p2 -> ... 两两处理, 拆分成 from -> to 关系:
[root] {label: root} -> [root.p1] {label: p1}
[root.p1] {label: p1} -> [root.p1.p2] {label: p2}
注意节点的 [identifier] 保留了前序全部信息,这样是区分树结构中可能包含的同名字段; {label} 的作用是让显示更精简。 这是整个管道唯一需要注意的技巧。
sort:对以上结果排序并去重,这个重复会很多;注意 from -> to 的关系不受排序影响。
画树
graph-easy: 是 python 的一个模块,也是一键安装。 这个管道可以不要, 在第四步 awk 的print 语句直接写成 dot 格式即可。
dot:画图。 dot 接受 from -> to 标记的节点关系,通过调用布局算法自动渲染出美观的图表。
以上管道, graph-easy 是可删除的;jq ,dot 是需要额外安装的, 在主流发行版都是一句话的事, 其余都是操作系统内置工具。
- 点赞
- 收藏
- 关注作者
评论(0)