#columnar #columnar-format #memory #derive #fields #data #column

已删除 columnar_derive

内存中的列式数据格式(Derive)

使用旧Rust 2015

0.0.1 2017年10月27日

#16#columnar

MIT/Apache

23KB
462

column 是一个Rust库,用于以列式格式表示特定类型的向量。当迭代大量元素但只查看类型字段的子集时,列式表示非常有用。

许可证

许可方式如下:

任选其一。

贡献

除非你明确声明,否则任何有意提交以包含在你的作品中的贡献,根据Apache-2.0许可证的定义,应如上所述双重许可,不附加任何额外条款或条件。

示例

要使用 column,请将以下依赖项添加到你的项目 Cargo.toml 文件中

[dependencies]
column = { git = "https://github.com/antiguru/column-rs.git" }

这将从Github引入 column crate(这可能会改变!),这应该允许你使用基于列的内存布局中的常规结构体。

extern crate column;
#[macro_use] extern crate column_derive;

#[derive(Column, Debug)]
struct Data {
    id: usize,
    val: f64,
}

fn main() {
    let mut u = <Data as Column>::new();

    let ds = vec![Data { id: 0, val: 3.141 }, Data { id: 1, val: 42.}];
    u.extend(ds);

    for e in u.iter() {
        println!("Element: {:?}", e);
    }
    for mut e in u.iter_mut() {
        *e.val *= 2.;
    }
    for e in u.iter() {
        println!("Element: {:?}", e);
    }

}

此示例包含在 column crate 中,你可以通过在crate的根目录中键入以下内容来运行它

% cargo run --example columnar
Running `target/debug/examples/columnar`
Element: DataRef { id: 0, val: 3.141 }
Element: DataRef { id: 1, val: 42 }
Element: DataRef { id: 0, val: 6.282 }
Element: DataRef { id: 1, val: 84 }

泛型类型

生成的代码对 to_owned 进行解引用以实例化元素。这意味着值必须实现 Copy 特性才能正常工作。否则,Rust 将会报错。例如,这将产生一个有效的泛型列式类型

#[derive(Column)]
struct DataGen<A: Copy> {
    id: A,
}

筛选集合

当使用列式类型时,它们可能被传递到不同的下游功能中,而不暴露集合中的所有元素。为了避免中间复制,此crate包含一个筛选集合(FilteredCollection)。它是一个围绕 &IntoIterator 的包装,并结合一个存储目标集合中哪些项可用的 Vec<bool>

以下示例实例化了 FilteredCollection 并使用其 retain 方法仅保留集合中的子集。请注意,这不会更改底层数据。

use column::bitmap::FilteredCollection;
let mut bitmap_container = FilteredCollection::new(&container, container.len());
bitmap_container.retain(|u| p(u));

调试

在编译过程中,列创建所需的实现。有时事情会出错,并且调试生成的代码相当繁琐。因此,存在一个名为 verbose 的标志。它强制 column 将中间代码写入目标目录。对于类型 Data,它将生成文件 target/derive_column_Data.rs。(如果有更优雅的方法,请提交一个 issue 或发送一个 pull request!)在 Cargo.toml 中插入以下片段以启用详细输出

[dependencies]
column = { git = "https://github.com/antiguru/column-rs.git", features = [ "verbose" ] }

此功能也可以在处理此项目时在命令行上激活。以下 cargo 调用测试并转储中间文件

cargo test --features verbose

性能

有一个小型的基准测试。它表明,对于某些操作,列格式可以显著更快。使用 Rust 夜间版运行它,如下所示

% rustup run nightly cargo bench
[...]
running 6 tests
test data_bitmap_column_add_assign   ... bench:  13,178,990 ns/iter (+/- 405,043) = 1909 MB/s
test data_bitmap_vec_add_assign      ... bench:  39,891,687 ns/iter (+/- 714,537) = 630 MB/s
test data_column                     ... bench:   1,949,104 ns/iter (+/- 79,882) = 4303 MB/s
test data_column_add_assign          ... bench:   5,495,641 ns/iter (+/- 203,841) = 4579 MB/s
test data_row                        ... bench:  16,817,910 ns/iter (+/- 264,722) = 498 MB/s
test data_row_add_assign             ... bench:  32,581,004 ns/iter (+/- 759,734) = 772 MB/s

test result: ok. 0 passed; 0 failed; 0 ignored; 6 measured; 0 filtered out

对性能数据进行评估时请保持谨慎。使用列表示法获得的速度提升源于加载更少且更密集的数据到内存中。它只会显示出当结构体中并非所有元素都在紧密循环中访问时的好处,因为只有这样我们才能减少传输到 CPU 的字节数。然而,当所有数据都被触及时,即所有列都必须被加载时,这种加速可能是微不足道的,甚至可能是负的。此外,将基于行的表示形式转换为列表示形式也有一定的成本。

依赖关系

~1.7–3MB
~69K SLoC