9 个版本

0.6.8 2024 年 6 月 10 日
0.6.7 2024 年 5 月 1 日
0.6.6 2024 年 4 月 21 日
0.6.3 2024 年 3 月 29 日

#150Rust 模式

Download history 642/week @ 2024-04-19 525/week @ 2024-04-26 177/week @ 2024-05-03 363/week @ 2024-05-10 412/week @ 2024-05-17 276/week @ 2024-05-24 275/week @ 2024-05-31 1898/week @ 2024-06-07 2449/week @ 2024-06-14 2922/week @ 2024-06-21 3610/week @ 2024-06-28 3310/week @ 2024-07-05 1175/week @ 2024-07-12 1024/week @ 2024-07-19 387/week @ 2024-07-26 661/week @ 2024-08-02

3,921 每月下载量

Apache-2.0 OR MIT

60KB
1.5K SLoC

arrow_convert

arrow-rs 上提供 API,用于在 Rust 类型与 Arrow 之间进行转换。此仓库是从 arrow2-convert 库直接移植过来的,用于与 arrow-rs 一起使用。

Arrow 生态系统提供了许多方法,可以在 Arrow 和多种语言中的其他流行格式之间进行转换。此项目旨在满足以 Rust 为主的数据管道轻松在 Arrow 之间进行转换的需求,具有强类型和任意嵌套。

示例

以下示例执行了一个具有单个字段的结构的往返转换。

请参阅 complex_example.rs 以了解功能齐全的用法。

/// Simple example

use arrow::array::{Array, ArrayRef};
use arrow_convert::{deserialize::TryIntoCollection, serialize::TryIntoArrow, ArrowField, ArrowSerialize, ArrowDeserialize};

#[derive(Debug, Clone, PartialEq, ArrowField, ArrowSerialize, ArrowDeserialize)]
pub struct Foo {
    name: String,
}

fn main() {
    // an item
    let original_array = [
        Foo { name: "hello".to_string() },
        Foo { name: "one more".to_string() },
        Foo { name: "good bye".to_string() },
    ];

    // serialize to an arrow array. try_into_arrow() is enabled by the TryIntoArrow trait
    let arrow_array: ArrayRef = original_array.try_into_arrow().unwrap();

    // which can be cast to an Arrow StructArray and be used for all kinds of IPC, FFI, etc.
    // supported by `arrow`
    let struct_array= arrow_array.as_any().downcast_ref::<arrow::array::StructArray>().unwrap();
    assert_eq!(struct_array.len(), 3);

    // deserialize back to our original vector via TryIntoCollection trait.
    let round_trip_array: Vec<Foo> = arrow_array.try_into_collection().unwrap();
    assert_eq!(round_trip_array, original_array);
}

API

实现 ArrowFieldArrowSerializeArrowDeserialize 特性的类型可以通过 try_into_arrowtry_into_collection 方法在 Arrow 之间进行转换。

可以使用 ArrowFieldArrowSerializeArrowDeserialize derive 宏为结构和枚举生成这些特性的实现。也可以通过手动实现这些特性为任何需要转换为 Arrow 或从 Arrow 转换的类型定义自定义实现。

要将数据序列化为arrow格式,可以使用TryIntoArrow::try_into_arrow将任何可迭代对象序列化为arrow::Arrayarrow::Chunk。其中,arrow::Array代表内存中的Arrow布局,而arrow::Chunk代表列组,可以与arrow API结合使用,例如转换为parquet格式和arrow flight RPC。

要从arrow反序列化,可以使用TryIntoCollection::try_into_collectionarrow::Array表示形式反序列化为实现了FromIterator的任何容器。

默认实现

以下类型提供了上述特质的默认实现:

  • 数值类型
    • [u8], [u16], [u32], [u64], [i8], [i16], [i32], [i64], [f32], [f64]
    • i128通过type属性支持。请参阅i128部分以获取更多详细信息。
  • 其他类型
  • 时间类型
  • 如果T实现了ArrowField,则为Option
  • 如果T实现了ArrowField,则为Vec
  • [T; SIZE]如果T实现了ArrowField
  • 支持大型Arrow类型LargeBinaryLargeStringLargeList,可通过type属性实现。请参阅complex_example.rs以获取用法。
  • 支持固定大小类型FixedSizeBinaryFixedSizeList,可通过FixedSizeVec类型覆盖实现。

枚举

枚举仍是一个实验性功能,需要进行集成测试。Rust枚举数组会被转换为Arrow::UnionArray。关于枚举的一些额外说明

  • Rust单元变体使用bool数据类型来表示。

i128

i128表示一个十进制数字,需要指定精度和比例才能作为Arrow数据类型使用。可以通过使用I128类型覆盖来指定精度和比例。

例如,要将i128用作结构体的字段

use arrow_convert::field::I128;
use arrow_convert::ArrowField;

#[derive(Debug, ArrowField)]
struct S {
    #[arrow_field(type = "I128<32, 32>")]
    field: i128,
}

可以使用arrow_serialize_to_mutable_arrayarrow_array_deserialize_iterator_as_type方法将vec<i128>转换为/从arrow进行转换。

use arrow::array::{Array, ArrayBuilder, ArrayRef};
use arrow_convert::serialize::arrow_serialize_to_mutable_array;
use arrow_convert::deserialize::arrow_array_deserialize_iterator_as_type;
use arrow_convert::field::I128;
use std::borrow::Borrow;
use std::sync::Arc;

fn convert_i128() {
    let original_array = vec![1 as i128, 2, 3];
    let b: ArrayRef = Arc::new(arrow_serialize_to_mutable_array::<_, I128<32,32>, _>(
        &original_array).unwrap().finish());
    let round_trip: Vec<i128> = arrow_array_deserialize_iterator_as_type::<_, I128<32,32>>(
        b.borrow()).unwrap().collect();
    assert_eq!(original_array, round_trip);
}

嵌套Option类型

由于Arrow格式只支持一层有效性,嵌套Option类型,如Option<Option<T>>,在序列化到Arrow之后,将丢失任何中间嵌套的None值。例如,Some(None)将被序列化为None,

缺少的功能

  • 目前不支持泛型、切片和引用。

这不是一个详尽的列表。如果您需要功能,请提出问题。

内存

透传转换执行单个内存复制。反序列化执行从arrow到目标位置的复制。序列化执行从源到arrow的复制。就地反序列化在理论上可行,但目前不支持。

内部结构

与Serde的相似之处

设计灵感来自Serde。`ArrowSerialize`和`ArrowDeserialize`分别是Serde的`Serialize`和`Deserialize`的对应物。

然而,与Serde的特质提供对Serde数据模型的详尽且灵活的映射不同,arrow_convert的特质提供对Arrow数据结构的更窄映射。

具体来说,`ArrowSerialize`特质提供了将类型序列化到相应的`arrow::array::ArrayBuilder`的逻辑。`ArrowDeserialize`特质从相应的`arrow::array::ArrowArray`反序列化类型。

解决方案

诸如部分实现特殊化和泛型关联类型(目前仅在nightly构建中可用)等特性可以极大地简化底层实现。

例如,自定义类型需要显式通过在原始类型上使用`arrow_enable_vec_for_type`宏来启用Vec序列化。这是必要的,因为Vec是Arrow中的特殊类型,但没有实现特殊化,就无法为它编写特殊案例。

通用的关联类型的存在将简化大型和固定类型实现,因为可以定义一个通用的ArrayBuilder。理想情况下,为了代码的重用性,我们不必重新实现ArrowSerializeArrowDeserialize对于大型和固定大小的类型,因为这些类型的原始数据类型是相同的。然而,这要求特质的函数将一个通用的有界可变数组作为参数,而不是单个数组类型。这要求ArrowSerializeArrowDeserialize实现能够将界限作为关联类型的一部分指定,而没有泛型关联类型这是不可能的。

因此,我们不得不牺牲代码的重用性,并通过提供分离的ArrowSerializeArrowDeserialize实现来引入一些复杂性,这些实现是通过占位符结构为大型和固定大小类型提供的。这也要求引入Type关联类型到ArrowField,这样箭头类型可以通过宏字段属性来覆盖,而不会影响实际类型。

许可证

根据您选择的以下任何一项许可协议

任选其一。

贡献

除非您明确声明,否则根据Apache-2.0许可证定义的您有意提交给作品的所有贡献,将如上所述双许可,没有额外的条款或条件。

依赖关系

~13–21MB
~288K SLoC