#列式 #serde #兼容 #压缩 #列式

serde_columnar

具有前后兼容性的舒适列式存储编码crate

15个版本

0.3.7 2024年8月9日
0.3.6 2024年6月14日
0.3.5 2024年5月27日
0.3.3 2023年11月21日
0.1.0 2022年11月17日

#265 in 编码

Download history 42/week @ 2024-04-27 22/week @ 2024-05-04 66/week @ 2024-05-11 50/week @ 2024-05-18 271/week @ 2024-05-25 91/week @ 2024-06-01 253/week @ 2024-06-08 156/week @ 2024-06-15 34/week @ 2024-06-22 9/week @ 2024-06-29 164/week @ 2024-07-06 69/week @ 2024-07-13 20/week @ 2024-07-20 66/week @ 2024-07-27 166/week @ 2024-08-03 148/week @ 2024-08-10

每月401次下载
5 个crate中(直接使用4个) 使用

MIT/Apache

62KB
1.5K SLoC

serde_columnar

serde_columnar是一个舒适列式存储编码crate,提供前后兼容性。

它允许需要序列化和反序列化的内容通过列式存储编码为二进制,只需使用简单的宏注释即可。

有关更详细的介绍,请参阅此Notion链接:Serde-Columnar

🚧 此crate正在开发中,尚不稳定,不应在生产环境中使用

特性 🚀

serde_columnar具有几个显著特性

  • 🗜️ 结合各种压缩策略使用列式存储,显著减少编码内容的体积。
  • 🔄 内置前后兼容解决方案,无需维护额外的版本代码。
  • 🌳 支持嵌套列式存储。
  • 📦 支持列表和映射容器
  • 🔄 支持使用迭代器格式进行反序列化。

如何使用

安装

cargo add serde_columnar

或编辑您的Cargo.toml并将serde_columnar作为依赖项添加

[dependencies]
serde_columnar = "0.3.4"

容器属性

  • vec:
    • 声明此结构将为类似vec的容器的行
    • 如果同时设置ser,则自动推导RowSer特质
    • 如果同时设置de,则自动推导RowDe特质
  • map:
    • 声明此结构将为类似map的容器的行
    • 如果同时设置ser,则自动推导KeyRowSer特质
    • 如果同时设置de,则自动推导KeyRowDe特质
  • ser:
    • 自动为该结构体推导 Serialize 特性
  • de:
    • 自动为该结构体推导 Deserialize 特性
  • iterable:
    • 声明该结构体可迭代
    • 仅适用于 row 结构体
    • 可迭代 了解更多详情

字段属性

  • strategy:
    • 应用于该字段的列压缩策略。
    • 可选值:Rle/DeltaRle/BoolRle
    • 仅适用于 row 结构体。
  • class:
    • 声明该字段是行容器。字段类型通常是 VecHashMap 及其变体。
    • 可选值:vecmap
    • 仅适用于 table 结构体。
  • skip:
  • borrow:
    • #[serde(borrow)]相同,使用零拷贝反序列化从反序列化器借用数据。
    • 使用 #[columnar(borrow="'a + 'b")] 明确指定应该借用哪些生命周期。
    • 目前仅适用于 table 结构体。
  • iter:
    • 在以 iter 模式反序列化时声明可迭代行类型。
    • 仅适用于标记为 class 的字段。
    • 仅适用于 class="vec"
  • optional & index
    • 为了实现向前和向后兼容,一些可能发生变化的字段可以标记为 optional
    • 为了避免将来可能出现的错误,例如更改可选字段的顺序,需要标记 index
    • 所有 optional 字段都必须在其他字段之后。
    • index 是可选字段的唯一标识符,它将被编码到结果中。如果在反序列化期间找不到相应的标识符,则将使用 Default
    • optional 字段可以在未来版本中添加或删除。兼容性的前提是相同索引的字段类型没有改变或编码格式是兼容的(例如,将 u32 更改为 u64)。

示例

use serde_columnar::{columnar, from_bytes, to_vec};

#[columnar(vec, ser, de)]                // this struct can be a row of vec-like container
struct RowStruct {
    name: String,
    #[columnar(strategy = "DeltaRle")]   // this field will be encoded by `DeltaRle`
    id: u64,
    #[columnar(strategy = "Rle")]        // this field will be encoded by `Rle`
    gender: String,
    #[columnar(strategy = "BoolRle")]    // this field will be encoded by `BoolRle`
    married: bool
    #[columnar(optional, index = 0)]     // This field is optional, which means that this field can be added in this version or deleted in a future version
    future: String
}

#[columnar(ser, de)]                    // derive `Serialize` and `Deserialize`
struct TableStruct<'a> {
    #[columnar(class = "vec")]          // this field is a vec-like table container
    pub data: Vec<RowStruct>,
    #[columnar(borrow)]                 // the same as `#[serde(borrow)]`
    pub text: Cow<'a, str>
    #[columnar(skip)]                   // the same as `#[serde(skip)]`
    pub ignore: u8
    #[columnar(optional, index = 0)]    // table container also supports optional field
    pub other_data: u64

}

let table = TableStruct::new(...);
let bytes = serde_columnar::to_vec(&table).unwrap();
let table_from_bytes = serde_columnar::from_bytes::<TableStruct>(&bytes).unwrap();

您可以在 examplestests 中找到更多 serde_columnar 的示例。

可迭代

当我们在压缩编码中使用列模式时,有一个前提是字段是可迭代的。因此,在反序列化时,我们可以完全借用编码的字节以迭代器的形式获取所有数据,而无需直接分配所有数据的内存。这种实现也可以完全通过宏来完成。

在反序列化时使用iter模式,你只需要做3件事

  1. 使用iterable标记所有行结构体
  2. 使用iter="..."标记行容器的字段
  3. 使用serde_columnar::iter_from_bytes进行反序列化
#[columnar(vec, ser, de, iterable)]
struct Row{
  #[columnar(strategy="Rle")]
  rle: String
  #[columnar(strategy="DeltaRle")]
  delta_rle: u64
  other: u8
}

#[columnar(ser, de)]
struct Table{
  #[columnar(class="vec", iter="Row")]
  vec: Vec<Row>,
  other: u8
}

let table = Table::new(...);
let bytes = serde_columnar::to_vec(&table).unwrap();
let table_iter = serde_columnar::iter_from_bytes::<Table>(&bytes).unwrap();

致谢

  • serde:Rust的序列化框架。
  • postcard:Postcard是一个专注于no_std的Serde序列化和反序列化器。我们使用它作为序列化和反序列化器,以便提供VLE和ZigZag编码。
  • Automerge:Automerge是一个优秀的CRDT框架,我们重用了其中的RLE编码相关代码。

依赖项

~1.4–2.2MB
~46K SLoC