#arrow #arrow2 #convert #格式转换 #嵌套 #数组 #类型

arrow2_convert

使用 arrow2 在嵌套 Rust 类型与 Arrow 之间进行转换

7 个版本 (4 个破坏性更新)

0.5.0 2023 年 5 月 9 日
0.4.2 2023 年 2 月 12 日
0.3.2 2022 年 9 月 30 日
0.3.0 2022 年 8 月 25 日
0.1.0 2022 年 3 月 3 日

#202Rust 模式

Download history 2315/week @ 2024-03-14 1882/week @ 2024-03-21 2232/week @ 2024-03-28 1583/week @ 2024-04-04 2637/week @ 2024-04-11 2803/week @ 2024-04-18 2549/week @ 2024-04-25 1935/week @ 2024-05-02 1779/week @ 2024-05-09 2720/week @ 2024-05-16 2552/week @ 2024-05-23 2592/week @ 2024-05-30 1833/week @ 2024-06-06 3072/week @ 2024-06-13 2955/week @ 2024-06-20 2087/week @ 2024-06-27

每月 10,264 次下载
用于 8 个 crate(4 个直接使用)

Apache-2.0 OR MIT

52KB
1K SLoC

arrow2_convert

arrow2 之上提供 API,用于在 Rust 类型与 Arrow 之间进行转换。

Arrow 生态系统提供了许多在 Arrow 与其他多种语言中的流行格式之间进行转换的方法。本项目旨在满足 Rust 中心数据管道的需求,以便轻松地将数据转换为/从 Arrow 转换,同时提供强类型和任意嵌套。

示例

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

请参阅 complex_example.rs 以了解完整功能的用法。

/// Simple example

use arrow2::array::Array;
use arrow2_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: Box<dyn Array> = 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 `arrow2`
    let struct_array= arrow_array.as_any().downcast_ref::<arrow2::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,可以使用 TryIntoArrow::try_into_arrow 将任何可迭代表序列化为 arrow2::Arrayarrow2::Chunkarrow2::Array 代表内存中的 Arrow 布局。 arrow2::Chunk 代表一个列组,可以与 arrow2 API 一起使用,例如将数据转换为 parquet 和 arrow flight RPC。

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

默认实现

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

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

枚举

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

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

i128

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

例如,要在结构体字段中使用i128

use arrow2_convert::field::I128;
use arrow2_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> 转换为/from 箭头。

use arrow2::array::{Array, MutableArray};
use arrow2_convert::serialize::arrow_serialize_to_mutable_array;
use arrow2_convert::deserialize::arrow_array_deserialize_iterator_as_type;
use arrow2_convert::field::I128;
use std::borrow::Borrow;

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

嵌套选项类型

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

缺失的功能

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

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

内存

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

内部

与 Serde 的相似之处

设计灵感来自 serde。 ArrowSerializeArrowDeserialize 分别是 serde 的 SerializeDeserialize 的类似物。

然而,与 serde 的 trait 提供了详尽且灵活的数据模型映射不同,arrow2_convert 的 trait 提供了对 arrow2 数据结构更窄的映射。

具体来说,ArrowSerialize trait 提供了将类型序列化为相应的 arrow2::array::MutableArray 的逻辑。 ArrowDeserialize trait 从相应的 arrow2::array::ArrowArray 反序列化类型。

解决方案

部分实现特殊化和泛型关联类型(目前仅在 nightly 版本中可用)等功能可以极大地简化底层实现。

例如,自定义类型需要显式启用 Vec 序列化,方法是在原始类型上使用 arrow_enable_vec_for_type 宏。这是必需的,因为 Vec 在 Arrow 中是一种特殊类型,但没有实现特殊化,就没有方法来特殊情况化它。

泛型关联类型的可用性将简化大型和固定类型实现,因为可以定义一个泛型 MutableArray。理想情况下,为了代码重用,我们不需要为大型和固定大小类型重新实现 ArrowSerializeArrowDeserialize,因为原始类型是相同的。然而,这要求 trait 函数接受一个泛型有界可变数组作为参数,而不是单个数组类型。这要求 ArrowSerializeArrowDeserialize 实现将界限作为关联类型的一部分来指定,这是没有泛型关联类型无法实现的。

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

许可

根据以下任一项获得许可

由您选择。

贡献

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

依赖关系

~7MB
~140K SLoC