8个版本
0.6.8 | 2024年6月10日 |
---|---|
0.6.7 | 2024年5月1日 |
0.6.6 | 2024年4月21日 |
0.6.3 | 2024年3月29日 |
#143 in #arrow
5,173 每月下载量
用于 arrow_convert
63KB
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
实现 ArrowField
、ArrowSerialize
和 ArrowDeserialize
特性的类型可以通过 try_into_arrow
和 try_into_collection
方法转换为/从Arrow。
可以使用 ArrowField
、ArrowSerialize
和 ArrowDeserialize
derive宏为结构体和枚举生成这些特性的实现。还可以通过手动实现这些特性为任何需要转换为/从Arrow的类型定义自定义实现。
要将数据序列化为arrow格式,可以使用 TryIntoArrow::try_into_arrow
来将任何可迭代序列序列化为一个 arrow::Array
或一个 arrow::Chunk
。其中,arrow::Array
代表内存中的Arrow布局。而 arrow::Chunk
代表一个列组,可以与 arrow
API 结合使用,实现诸如转换为parquet和arrow flight RPC等操作。
要从arrow格式反序列化,可以使用 TryIntoCollection::try_into_collection
将 arrow::Array
表示形式反序列化为实现了 FromIterator
的任何容器。
默认实现
以下提供了上述特质的默认实现:
- 数值类型
- 其他类型
- 时间类型
- 如果 T 实现
ArrowField
,则为 Option - 如果 T 实现
ArrowField
,则为 Vec - 如果 T 实现
ArrowField
,则为[T; SIZE]
- 大 Arrow 类型
LargeBinary
、LargeString
、LargeList
通过type
属性支持。请参阅 complex_example.rs 了解使用方法。 - 固定大小类型
FixedSizeBinary
、FixedSizeList
通过FixedSizeVec
类型覆盖支持。- 注意:不支持
FixedSizeList
的嵌套。
- 注意:不支持
枚举类型
枚举仍然是一个实验性功能,需要集成测试。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_array
和arrow_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的特相比,arrow_convert的特提供了对Arrow数据结构的更窄映射。
具体来说,`ArrowSerialize`特提供了将类型序列化到相应的`arrow::array::ArrayBuilder的逻辑。`ArrowDeserialize`特从相应的`arrow::array::ArrowArray反序列化类型。
解决方案
如部分实现特化和泛型关联类型(目前仅在nightly构建中可用)等功能可以大大简化底层实现。
例如,自定义类型需要通过在原始类型上显式启用Vec序列化来启用`arrow_enable_vec_for_type`宏。这是必要的,因为Vec在Arrow中是一个特殊类型,但如果没有实现特化,就无法为它提供特殊处理。
泛型关联类型的可用性可以简化大类型和固定类型实现,因为可以定义一个泛型ArrayBuilder。理想情况下,为了代码复用,我们不需要为大类型和固定大小类型重新实现ArrowSerialize
和ArrowDeserialize
,因为这些原始类型是相同的。然而,这需要特质函数将一个泛型有界可变数组作为参数,而不是单个数组类型。这要求ArrowSerialize
和ArrowDeserialize
实现能够将界限作为关联类型的一部分指定,而没有泛型关联类型这是不可能的。
因此,我们不得不牺牲代码复用,并通过提供通过占位符结构分离的ArrowSerialize
和ArrowDeserialize
实现来引入一点复杂性,以适应大类型和固定大小类型。这也需要引入Type
关联类型到ArrowField
,这样箭头类型可以通过宏字段属性被覆盖,而不会影响实际类型。
许可证
根据您选择以下任一许可证
- Apache License,版本2.0 (LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
任选其一。
贡献
除非您明确表示,否则您提交的任何旨在包含在作品中并由您定义的贡献,根据Apache-2.0许可证,将根据上述许可证双授权,不附加任何额外条款或条件。
依赖关系
~320–780KB
~18K SLoC