1 个不稳定版本

0.5.0 2023年1月13日
0.4.1 2021年11月15日
0.3.4 2021年6月23日

#1387 in 解析器实现

31 每月下载量

MIT/Apache

120KB
2K SLoC

schema_analysis

类似通用的模式分析

是否曾想过要找出那个json文件中的内容?或者它可能是xml... 嗯,yaml?它肯定不是toml。

然而,许多优秀的工具只能处理其中一种格式,而互联网并不是一个那么友好的地方,以至于最终理解到,不,xml不是一个可接受的文档格式。

现在,这个小巧实用的工具,是我们的朋友serde支持的任何自描述格式的单一接口。

功能

  • 与任何具有Serde实现的自我描述格式一起工作。
  • 适用于大文件。
  • 跟踪每个类型的一些有用信息。
  • 分别跟踪null/正常/缺失/重复值。
  • Schemarsjson_typegen集成,如果需要,则生成类型和json模式。
  • 这里有一个演示网站这里

用法

let data: &[u8] = b"true";

// Just pick your format, and deserialize InferredSchema as if it were a normal type.
let inferred: InferredSchema = serde_json::from_slice(data)?;
// let inferred: InferredSchema = serde_yaml::from_slice(data)?;
// let inferred: InferredSchema = serde_cbor::from_slice(data)?;
// let inferred: InferredSchema = toml::from_slice(data)?;
// let inferred: InferredSchema = rawbson::de::from_bytes(data)?;
// let inferred: InferredSchema = quick_xml::de::from_reader(data)?;

// InferredSchema is a wrapper around Schema
let schema: Schema = inferred.schema;
let expected: Schema = Schema::Boolean(Default::default());
assert!(schema.structural_eq(&expected));

// The wrapper is there so we can both do the magic above, and also store the data for later
let serialized_schema: String = serde_json::to_string_pretty(&schema)?;

就是这样。

查看Schema以了解您获得的信息,以及targets以查看可用的集成(包括代码和json模式生成)。

高级用法

我知道,我知道,互联网是邪恶的,它决定用成千上万,甚至数百万的文件来困扰你。

不幸的是,Serde依赖于类型信息来工作,所以我们对此无能为力我们可以拿出重型武器:DeserializeSeed。它拥有您喜欢的Serde的所有特性,但具有运行时状态。

let a_lot_of_json_files: &[&str] = &[ "1", "2", "1000" ];
let mut iter = a_lot_of_json_files.iter();

if let Some(file) = iter.next() {
    // We use the first file to generate a new schema to work with.
    let mut inferred: InferredSchema = serde_json::from_str(file)?;

    // Then we iterate over the rest to expand the schema.
    for file in iter {
        let mut json_deserializer = serde_json::Deserializer::from_str(file);
        // DeserializeSeed is implemented on &mut InferredSchema
        // So here it borrows the data mutably and runs it against the deserializer.
        let () = inferred.deserialize(&mut json_deserializer)?;
    }

    // The result in this case would be a simple integer schema
    // that 'has met' the numbers 1, 2, and 100.
    let mut context: NumberContext<i128> = Default::default();
    context.aggregate(&1);
    context.aggregate(&2);
    context.aggregate(&1000);

    assert_eq!(inferred.schema, Schema::Integer(context));
}

此外,如果您需要生成单独的模式(例如在多个线程上运行分析),您可以使用Coalesce特征在事后合并它们。

我真心希望我能将那个Schema转换成一些真正有用的东西。

您很幸运!您可以在这里查看与json_typegenSchemars的集成,以将分析转换为有用的文件,例如Rust类型和json架构。您还可以在这里找到一个演示网站。

它是如何工作的?

对于更详细的故事,请点击这里,有趣的部分是Serde很体贴地允许格式告诉我们它在处理什么,我们根据这些信息构建一个漂亮的架构。

性能

这些不是正式的基准测试,但应该能给出在一个i7-7700HQ笔记本电脑(2017年)上的大致性能概念,其中原始数据已加载到内存中。

大小 wasm (MB/s) 原生 (MB/s) 格式 文件编号
~180MB ~20s (9) ~5s (36) json 1
~650MB ~150s (4.3) ~50s (13) json 1
~1.7GB ~470s (3.6) ~145s (11.7) json 1
~2.1GB a ~182s (11.5) json 1
~13.3GBb ~810s (16.4) xml ~200k

a 这个看起来在Web Worker中获取数据时超过了某种浏览器限制,我相信我不得不拆分大文件来处理它。

b ~2.7GB压缩。这看起来可能是一个最坏的情况,因为它包括了解压缩开销,并且文件有一个格式为文本的部分,导致架构非常糟糕。(json格式化的架构接近0.5GB!)

依赖关系

~3–5.5MB
~103K SLoC