Apache Fury行式存储格式深度解析

Apache Fury行式存储格式深度解析

incubator-fury incubator-fury 项目地址: https://gitcode.com/gh_mirrors/in/incubator-fury

什么是行式存储格式

行式存储格式是一种将数据按行进行序列化和存储的二进制格式。与传统的序列化方式相比,行式存储格式具有更高的序列化/反序列化效率,支持零拷贝读取,并且能够实现跨语言数据交换。

核心特性

  1. 高性能序列化:相比传统Java序列化,性能提升5-50倍
  2. 零拷贝访问:可以直接访问二进制数据而不需要完全反序列化
  3. 跨语言支持:Java、Python、C++等多语言互通
  4. Arrow兼容:可与Apache Arrow生态系统无缝集成
  5. 部分反序列化:可选择性地只反序列化需要的字段

Java实现详解

基本使用

首先定义数据模型类:

public class Bar {
  String f1;
  List<Long> f2;
}

public class Foo {
  int f1;
  List<Integer> f2;
  Map<String, Integer> f3;
  List<Bar> f4;
}

创建编码器和序列化数据:

RowEncoder<Foo> encoder = Encoders.bean(Foo.class);
Foo foo = new Foo();
// 填充数据...
BinaryRow binaryRow = encoder.toRow(foo);

零拷贝读取

// 零拷贝读取List<Integer> f2
BinaryArray binaryArray2 = binaryRow.getArray(1);

// 零拷贝读取List<Bar> f4中的第11个元素
BinaryRow barStruct = binaryArray4.getStruct(10);

// 零拷贝读取嵌套结构中的数据
barStruct.getArray(1).getLong(5);  // 读取第11个Bar元素的f2列表中的第6个long值

部分反序列化

RowEncoder<Bar> barEncoder = Encoders.bean(Bar.class);
// 只反序列化单个Bar对象
Bar newBar = barEncoder.fromRow(barStruct);

Python实现详解

基本使用

定义数据模型:

@dataclass
class Bar:
    f1: str
    f2: List[pa.int64]

@dataclass
class Foo:
    f1: pa.int32
    f2: List[pa.int32]
    f3: Dict[str, pa.int32]
    f4: List[Bar]

序列化和反序列化:

encoder = pyfury.encoder(Foo)
foo = Foo(f1=10, f2=list(range(1000_000)),
         f3={f"k{i}": i for i in range(1000_000)},
         f4=[Bar(f1=f"s{i}", f2=list(range(10))) for i in range(1000_000)])

# 序列化为二进制
binary: bytes = encoder.to_row(foo).to_bytes()

# 反序列化
foo_row = pyfury.RowData(encoder.schema, binary)

性能对比

与Python标准库pickle的对比测试:

# Fury格式处理
print(f"start: {datetime.datetime.now()}")
foo_row = pyfury.RowData(encoder.schema, binary)
print(foo_row.f2[100000], foo_row.f4[100000].f1, foo_row.f4[200000].f2[5])
print(f"end: {datetime.datetime.now()}")

# pickle处理
binary = pickle.dumps(foo)
print(f"pickle start: {datetime.datetime.now()}")
new_foo = pickle.loads(binary)
print(new_foo.f2[100000], new_foo.f4[100000].f1, new_foo.f4[200000].f2[5])
print(f"pickle end: {datetime.datetime.now()}")

测试结果显示Fury格式在大型数据集处理上性能显著优于pickle。

Apache Arrow集成

Fury格式与Apache Arrow深度集成,可以高效地在两者之间转换数据。

Java实现

Schema schema = TypeInference.inferSchema(BeanA.class);
ArrowWriter arrowWriter = ArrowUtils.createArrowWriter(schema);
Encoder<BeanA> encoder = Encoders.rowEncoder(BeanA.class);
for (int i = 0; i < 10; i++) {
  BeanA beanA = BeanA.createBeanA(2);
  arrowWriter.write(encoder.toRow(beanA));
}
return arrowWriter.finishAsRecordBatch();

Python实现

import pyfury
encoder = pyfury.encoder(Foo)
# 转换为Arrow RecordBatch
encoder.to_arrow_record_batch([foo] * 10000)
# 转换为Arrow Table
encoder.to_arrow_table([foo] * 10000)

C++实现

std::shared_ptr<ArrowWriter> arrow_writer;
EXPECT_TRUE(
    ArrowWriter::Make(schema, ::arrow::default_memory_pool(), &arrow_writer)
        .ok());
for (auto &row : rows) {
  EXPECT_TRUE(arrow_writer->Write(row).ok());
}
std::shared_ptr<::arrow::RecordBatch> record_batch;
EXPECT_TRUE(arrow_writer->Finish(&record_batch).ok());

最佳实践

  1. 大数据集处理:对于包含数百万元素的大型集合,Fury行式格式性能优势明显
  2. 跨语言数据交换:在Java和Python服务间交换数据时,使用Fury格式可避免序列化开销
  3. 数据分析场景:与Arrow集成后,可直接用于数据分析流程
  4. 选择性读取:对于大型嵌套结构,只反序列化需要的部分数据

性能优化建议

  1. 对于频繁访问的字段,使用零拷贝方式直接读取
  2. 对于大型集合,考虑分批处理
  3. 在跨语言场景中,预先定义好统一的数据模型
  4. 利用Arrow集成实现与现有数据分析生态系统的无缝对接

Fury行式存储格式为高性能数据序列化和跨语言数据交换提供了优秀的解决方案,特别适合大数据量、低延迟要求的应用场景。

incubator-fury incubator-fury 项目地址: https://gitcode.com/gh_mirrors/in/incubator-fury

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

毛炎宝Gardener

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值