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);
}

关键点说明

  1. #[derive(Columnar)] 宏自动为结构体生成序列化和反序列化的实现
  2. 可以使用 #[columnar(strategy = "...")] 属性为字段指定压缩策略
  3. 支持的类型包括:
    • 整数类型 (u8, u16, u32, u64, i8, i16, i32, i64)
    • 浮点数 (f32, f64)
    • 布尔值
    • 字符串
    • 嵌套结构体

压缩策略

columnar_derive支持多种压缩策略:

  1. delta - 适用于数值变化较小的列
  2. rle (Run-Length Encoding) - 适用于重复值较多的列
  3. bitpack - 适用于小范围整数
  4. dictionary - 适用于低基数字符串列

可以通过字段属性指定策略,例如:

#[columnar(strategy = "rle")]
status: String,

性能特点

  1. 列式存储布局,提高压缩率
  2. 支持选择性读取,只解码需要的列
  3. 零拷贝反序列化
  4. 支持迭代式解码,减少内存使用

所有者

  • 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!("数据反序列化验证成功!");
}

性能建议

  1. 对于高基数字段(如ID),禁用压缩可能更高效
  2. 对小数据集,字典编码可能增加开销
  3. 批量处理数据比单条处理更高效

注意事项

  • 确保所有字段类型都实现了必要的trait
  • 大型结构可能需要调整默认的压缩设置
  • 版本兼容性:序列化格式可能随库版本变化

columnar_derive 通过简化列式存储的实现,使得在Rust中处理大数据集变得更加高效和方便。

回到顶部