Rust列式存储库columnar_derive的使用,高效数据序列化与压缩的派生宏工具
Rust列式存储库columnar_derive的使用,高效数据序列化与压缩的派生宏工具
安装
在项目目录中运行以下Cargo命令:
cargo add columnar_derive
或者在Cargo.toml中添加以下行:
columnar_derive = "0.3.0"
完整示例
以下是一个使用columnar_derive的完整示例:
use columnar_derive::Columnar;
// 定义一个结构体并使用Columnar派生宏
#[derive(Columnar, Debug)]
struct Person {
id: u64,
name: String,
age: u8,
is_active: bool,
#[columnar(strategy = "delta")]
salary: f64,
}
fn main() {
// 创建一些示例数据
let people = vec![
Person {
id: 1,
name: "Alice".to_string(),
age: 30,
is_active: true,
salary: 75000.0,
},
Person {
id: 2,
name: "Bob".to_string(),
age: 25,
is_active: false,
salary: 80000.0,
},
Person {
id: 3,
name: "Charlie".to_string(),
age: 35,
is_active: true,
salary: 85000.0,
},
];
// 序列化数据
let mut buffer = Vec::new();
let cursor = std::io::Cursor::new(&mut buffer);
let mut writer = columnar::Writer::new(cursor);
for person in &people {
writer.write(person).unwrap();
}
writer.finish().unwrap();
println!("Serialized size: {} bytes", buffer.len());
// 反序列化数据
let cursor = std::io::Cursor::new(buffer);
let mut reader = columnar::Reader::new(cursor).unwrap();
let mut decoded_people = Vec::new();
while let Some(person) = reader.next().unwrap() {
decoded_people.push(person);
}
println!("Decoded people: {:?}", decoded_people);
}
关键点说明
#[derive(Columnar)]
宏自动为结构体生成序列化和反序列化的实现- 可以使用
#[columnar(strategy = "...")]
属性为字段指定压缩策略 - 支持的类型包括:
- 整数类型 (u8, u16, u32, u64, i8, i16, i32, i64)
- 浮点数 (f32, f64)
- 布尔值
- 字符串
- 嵌套结构体
压缩策略
columnar_derive支持多种压缩策略:
- delta - 适用于数值变化较小的列
- rle (Run-Length Encoding) - 适用于重复值较多的列
- bitpack - 适用于小范围整数
- dictionary - 适用于低基数字符串列
可以通过字段属性指定策略,例如:
#[columnar(strategy = "rle")]
status: String,
性能特点
- 列式存储布局,提高压缩率
- 支持选择性读取,只解码需要的列
- 零拷贝反序列化
- 支持迭代式解码,减少内存使用
所有者
- Frank McSherry
- Moritz Hoffmann
完整示例代码
use columnar_derive::Columnar;
use serde::{Serialize, Deserialize};
// 定义一个更复杂的数据结构
#[derive(Columnar, Debug, Serialize, Deserialize)]
struct Employee {
#[columnar(strategy = "bitpack")] // 员工ID通常是连续的小整数
employee_id: u32,
#[columnar(strategy = "dictionary")] // 部门名称通常重复率高
department: String,
#[columnar(strategy = "delta")] // 工资变化通常较小
salary: f64,
#[columnar(strategy = "rle")] // 职位状态变化较少
is_manager: bool,
skills: Vec<String>, // 没有指定策略,使用默认编码
}
fn main() {
// 创建员工数据
let employees = vec![
Employee {
employee_id: 1001,
department: "Engineering".to_string(),
salary: 85000.0,
is_manager: false,
skills: vec!["Rust".to_string(), "Python".to_string()],
},
Employee {
employee_id: 1002,
department: "Engineering".to_string(),
salary: 90000.0,
is_manager: true,
skills: vec!["Java".to_string(), "Go".to_string()],
},
Employee {
employee_id: 1003,
department: "Marketing".to_string(),
salary: 75000.0,
is_manager: false,
skills: vec!["Writing".to_string(), "SEO".to_string()],
},
];
// 序列化数据
let mut buffer = Vec::new();
let cursor = std::io::Cursor::new(&mut buffer);
let mut writer = columnar::Writer::new(cursor);
for emp in &employees {
writer.write(emp).unwrap();
}
writer.finish().unwrap();
println!("序列化后大小: {} 字节", buffer.len());
println!("原始大小: {} 字节", std::mem::size_of_val(&employees[0]) * employees.len());
// 反序列化数据
let cursor = std::io::Cursor::new(buffer);
let mut reader = columnar::Reader::new(cursor).unwrap();
let mut decoded_employees = Vec::new();
while let Some(emp) = reader.next().unwrap() {
decoded_employees.push(emp);
}
println!("解码后的员工数据: {:#?}", decoded_employees);
// 选择性读取示例 - 只读取部门信息
let cursor = std::io::Cursor::new(buffer);
let mut reader = columnar::Reader::new(cursor).unwrap();
let mut departments = Vec::new();
while let Some(emp) = reader.next().unwrap() {
departments.push(emp.department.clone());
}
println!("只读取部门信息: {:?}", departments);
}
1 回复
Rust列式存储库columnar_derive使用指南
概述
columnar_derive
是一个Rust派生宏工具,用于实现高效的数据序列化与压缩,特别适合列式存储场景。它通过自动生成序列化和反序列化代码,简化了列式数据结构的处理。
主要特性
- 自动派生列式存储的序列化/反序列化逻辑
- 支持高效的数据压缩
- 类型安全的操作
- 减少样板代码
使用方法
1. 添加依赖
首先在Cargo.toml中添加依赖:
[dependencies]
columnar_derive = "0.1"
columnar = "0.1"
2. 基本使用
use columnar_derive::{Columnar, ColumnarDecoder, ColumnarEncoder};
#[derive(Columnar, Debug, PartialEq)]
struct Person {
id: u32,
name: String,
age: u8,
is_active: bool,
}
3. 序列化和反序列化
fn main() {
// 创建示例数据
let people = vec![
Person {
id: 1,
name: "Alice".to_string(),
age: 30,
is_active: true,
},
Person {
id: 2,
name: "Bob".to_string(),
age: 25,
is_active: false,
},
];
// 序列化
let mut encoder = ColumnarEncoder::new();
for person in &people {
encoder.encode(person).unwrap();
}
let encoded_data = encoder.finish().unwrap();
// 反序列化
let mut decoder = ColumnarDecoder::new(&encoded_data);
let decoded_people: Vec<Person> = decoder.decode_all().unwrap();
assert_eq!(people, decoded_people);
}
4. 自定义压缩选项
#[derive(Columnar, Debug)]
#[columnar(compress = "zstd")]
struct SensorData {
timestamp: u64,
temperature: f32,
humidity: f32,
#[columnar(compress = "none")] // 这个字段不压缩
sensor_id: String,
}
高级用法
1. 处理嵌套结构
#[derive(Columnar, Debug)]
struct Order {
id: u64,
customer: Customer, // 嵌套结构
items: Vec<OrderItem>, // 嵌套集合
}
#[derive(Columnar, Debug)]
struct Customer {
id: u32,
name: String,
}
#[derive(Columnar, Debug)]
struct OrderItem {
product_id: u32,
quantity: u16,
price: f64,
}
2. 使用字典编码优化字符串
#[derive(Columnar, Debug)]
#[columnar(dict_encode = true)]
struct LogEntry {
level: String, // 会被字典编码
message: String,
#[columnar(dict_encode = false)]
trace_id: String, // 不应用字典编码
}
完整示例demo
// 完整示例:使用columnar_derive处理电商订单数据
use columnar_derive::{Columnar, ColumnarDecoder, ColumnarEncoder};
// 定义嵌套数据结构
#[derive(Columnar, Debug, PartialEq)]
struct Order {
order_id: u64,
customer: Customer,
items: Vec<OrderItem>,
total: f64,
#[columnar(compress = "none")] // 订单ID不压缩
order_code: String,
}
#[derive(Columnar, Debug, PartialEq)]
struct Customer {
id: u32,
#[columnar(dict_encode = true)] // 客户名称使用字典编码
name: String,
email: String,
}
#[derive(Columnar, Debug, PartialEq)]
struct OrderItem {
product_id: u32,
#[columnar(compress = "zstd")] // 产品名称使用zstd压缩
product_name: String,
quantity: u16,
price: f64,
}
fn main() {
// 创建示例订单数据
let orders = vec![
Order {
order_id: 1001,
customer: Customer {
id: 1,
name: "张三".to_string(),
email: "zhangsan@example.com".to_string(),
},
items: vec![
OrderItem {
product_id: 101,
product_name: "Rust编程指南".to_string(),
quantity: 1,
price: 99.99,
},
OrderItem {
product_id: 205,
product_name: "高性能笔记本".to_string(),
quantity: 2,
price: 5999.99,
},
],
total: 6099.98,
order_code: "ORD-2023-1001".to_string(),
},
Order {
order_id: 1002,
customer: Customer {
id: 2,
name: "李四".to_string(),
email: "lisi@example.com".to_string(),
},
items: vec![
OrderItem {
product_id: 305,
product_name: "无线耳机".to_string(),
quantity: 1,
price: 299.99,
},
],
total: 299.99,
order_code: "ORD-2023-1002".to_string(),
},
];
// 序列化
let mut encoder = ColumnarEncoder::new();
for order in &orders {
encoder.encode(order).unwrap();
}
let encoded_data = encoder.finish().unwrap();
println!("序列化后数据大小: {} 字节", encoded_data.len());
// 反序列化
let mut decoder = ColumnarDecoder::new(&encoded_data);
let decoded_orders: Vec<Order> = decoder.decode_all().unwrap();
// 验证数据一致性
assert_eq!(orders, decoded_orders);
println!("数据反序列化验证成功!");
}
性能建议
- 对于高基数字段(如ID),禁用压缩可能更高效
- 对小数据集,字典编码可能增加开销
- 批量处理数据比单条处理更高效
注意事项
- 确保所有字段类型都实现了必要的trait
- 大型结构可能需要调整默认的压缩设置
- 版本兼容性:序列化格式可能随库版本变化
columnar_derive
通过简化列式存储的实现,使得在Rust中处理大数据集变得更加高效和方便。