#integer-compression #simd #columnar #float #floating-point

nightly compressed_vec

浮点数和整数压缩向量库,支持SIMD,快速处理/遍历压缩表示

1个不稳定版本

0.1.0 2020年7月2日

#353 in 压缩

Apache-2.0

185KB
3K SLoC

compressed_vec

浮点数和整数压缩向量库,支持SIMD,快速处理/遍历压缩表示。

[dependencies]
compressed_vec = "0.1"

这是一个压缩向量库,而不是压缩库。这意味着什么?一个压缩库会处理一些未压缩的数据,并提供基本的compress()和decompress()函数。通常你必须解压缩数据才能对其进行任何操作,这会导致额外的延迟和分配。

另一方面,这个压缩向量库允许你直接遍历和处理压缩表示。它旨在平衡快速遍历和SIMD处理/过滤,同时使用delta和XOR编码等技术将向量压缩到最佳列压缩技术(如Apache Parquet)的2倍以内。

  • 数据库引擎
  • 大型内存数据处理
  • 需要快速访问大量FP向量/矩阵的游戏和其他应用程序

性能数据

以下数据来自我的笔记本电脑:2.9 GHz Core i9,6/12核心,12MB L3,AVX2;从运行cargo bench vector获得,该命令直接在编码/压缩向量上运行filter-and-count-matches操作。

向量类型 元素/秒 原始GB/秒
u32密集型(无稀疏性) 1.7 Gelems/s 6.8 GB/s
u32稀疏型(99%为零) 13.9 Gelems/s 55.6 GB/s
两个u32向量(稀疏型+密集型)* 1.3-5.2 Gelems/s 5-20 GB/s
u64向量,密集型 955M - 1.1 Gelems/s 7.6 - 9.1 GB/s
f32,XOR编码,60%密度 985 Melems/s 3.9 GB/s
  • 两个u32向量过滤速度(使用MultiVectorFilter)取决于向量的顺序。首先过滤稀疏向量会更快速。

创建,遍历

创建f32压缩向量的最简单方法

    use compressed_vec::VectorF32XorAppender;
    let mut appender = VectorF32XorAppender::try_new(2048).unwrap();
    let encoded_bytes = appender.encode_all(vec![1.0, 1.5, 2.0, 2.5]).unwrap();

遍历此压缩向量的最简单方式(请注意,这不会进行任何分配)

    use compressed_vec::VectorReader;
    let reader = VectorReader::<f32>::try_new(&encoded_bytes[..]).unwrap();
    let sum = reader.iterate().sum::<f32>();   // Yay, no allocations!

过滤和SIMD处理

iterate() 是遍历压缩向量单个元素的简单 API,但它不是最快的。如上例中的过滤和计数基准测试所示,快速数据处理使用的是 Sink,这些在 sink 模块中定义。Sinks 每次操作一个 SIMD 单词,并且 sink API 被设计为内联。

例如,假设我们想将 2.5 添加到上面的 f32 向量中,然后将结果写入到 Vec<f32>。内部,使用 (sink) 执行 XOR 编码和解码。在解码过程中可以堆叠 sinks,几乎实现完全的 SIMD 管道:- XorSink(用于自动 f32 解码)- AddConstSink(添加 2.5,同样使用 SIMD 完成)- VecSink(将输出写入到常规 Vec)

    use compressed_vec::{VectorReader, AddConstSink, VecSink};
    let reader = VectorReader::<f32>::try_new(&encoded_bytes[..]).unwrap();
    let mut vecsink = VecSink::<f32>::new();
    let mut addsink = AddConstSink::new(2.5f32, &mut vecsink);
    reader.decode_to_sink(&mut addsink).unwrap();
    println!("And the transformed vector is: {:?}", vecsink.vec);

向量格式

向量格式的详细信息可以在这里找到:链接

该向量格式遵循大数据和数据库领域中的列式压缩技术,大致遵循 Google Procella 论文中使用的自定义 Artus 格式。

  • 在直接操作数据的情况下,压缩率在 2x 内与 ZSTD 相当
    • 此格式的压缩率与 Parquet 相当,但允许过滤和直接操作数据,无需对整个向量进行单独的解压缩步骤
  • 多遍编码
    • VectorAppender 收集原始数据的 min/max 和其他统计数据,并使用这些数据来决定最佳的编码策略(delta 等)。
  • 将词典索引暴露给查询引擎,并积极将数据格式向下推送
    • 该格式设计用于过滤词典代码,这加快了过滤速度
    • 使用部分可以实现许多针对过滤的优化。例如,null 部分 和 常数部分 允许非常快速的过滤短路。

协作

请与我联系以进行协作!

依赖项

~3MB
~71K SLoC