逆向还原 json schema

举报
oneliner 发表于 2020/07/13 17:29:07 2020/07/13
【摘要】 从数据中逆向还原 json schema, 7行代码一刀流,有图有真相

问题定义

典型的 json schema 可以表示成一个树结构(多根节点是森林) ,因为数据实际生成传输和存储过程中字段允许缺省, 我们抓包一条看到是局部树结构, 只要收集足够多局部树结构, 理论上可以拼凑出完整树结构。


下面说说怎么做:

我们假定手上有1G json 碎片文件, 没有原始 json schema:

  1. 这 1G 文件全部来自一份 json 树

  2. 这 1G 文件已经完整包含 json 树每个分支

  3. 不失一般性,每个碎片 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 是需要额外安装的, 在主流发行版都是一句话的事, 其余都是操作系统内置工具。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。