行格式
本页介绍用于高性能、缓存友好的数据访问的行格式序列化。
概述
Apache Fory™ 行格式是一种针对以下场景优化的二进制格式:
- 随机访问:无需反序列化整个对象即可读取任意字段
- 零拷贝:无数据复制的直接内存访问
- 缓存友好:连续内存布局提高 CPU 缓存效率
- 列式转换:易于转换为 Apache Arrow 格式
- 部分序列化:只序列化需要的字段
何时使用行格式
| 使用场景 | 行格式 | 对象图 |
|---|---|---|
| 分析/OLAP | ✅ | ❌ |
| 随机字段访问 | ✅ | ❌ |
| 完整对象序列化 | ❌ | ✅ |
| 复杂对象图 | ❌ | ✅ |
| 引用跟踪 | ❌ | ✅ |
| 跨语言(简单类型) | ✅ | ✅ |
快速开始
#include "fory/encoder/row_encoder.h"
#include "fory/row/writer.h"
using namespace fory::row;
using namespace fory::row::encoder;
// 定义结构体
struct Person {
int32_t id;
std::string name;
float score;
};
// 注册字段元数据(行编码必需)
FORY_FIELD_INFO(Person, id, name, score);
int main() {
// 创建编码器
RowEncoder<Person> encoder;
// 编码一个 person
Person person{1, "Alice", 95.5f};
encoder.Encode(person);
// 获取编码后的行
auto row = encoder.GetWriter().ToRow();
// 随机访问字段
int32_t id = row->GetInt32(0);
std::string name = row->GetString(1);
float score = row->GetFloat(2);
assert(id == 1);
assert(name == "Alice");
assert(score == 95.5f);
return 0;
}
行编码器
基本用法
RowEncoder<T> 模板类提供类型安全的编码:
#include "fory/encoder/row_encoder.h"
// 使用 FORY_FIELD_INFO 定义结构体
struct Point {
double x;
double y;
};
FORY_FIELD_INFO(Point, x, y);
// 创建编码器
RowEncoder<Point> encoder;
// 访问 schema(用于检查)
const Schema& schema = encoder.GetSchema();
std::cout << "Fields: " << schema.field_names().size() << std::endl;
// 编码值
Point p{1.0, 2.0};
encoder.Encode(p);
// 获取结果作为 Row
auto row = encoder.GetWriter().ToRow();
嵌套结构体
struct Address {
std::string city;
std::string country;
};
FORY_FIELD_INFO(Address, city, country);
struct Person {
std::string name;
Address address;
};
FORY_FIELD_INFO(Person, name, address);
// 编码嵌套结构体
RowEncoder<Person> encoder;
Person person{"Alice", {"New York", "USA"}};
encoder.Encode(person);
auto row = encoder.GetWriter().ToRow();
std::string name = row->GetString(0);
// 访问嵌套结构体
auto address_row = row->GetStruct(1);
std::string city = address_row->GetString(0);
std::string country = address_row->GetString(1);
数组 / 列表
struct Record {
std::vector<int32_t> values;
std::string label;
};
FORY_FIELD_INFO(Record, values, label);
RowEncoder<Record> encoder;
Record record{{1, 2, 3, 4, 5}, "test"};
encoder.Encode(record);
auto row = encoder.GetWriter().ToRow();
auto array = row->GetArray(0);
int count = array->num_elements();
for (int i = 0; i < count; i++) {
int32_t value = array->GetInt32(i);
}
直接编码数组
// 直接编码 vector(不在结构体内)
std::vector<Person> people{
{"Alice", {"NYC", "USA"}},
{"Bob", {"London", "UK"}}
};
RowEncoder<decltype(people)> encoder;
encoder.Encode(people);
// 获取数组数据
auto array = encoder.GetWriter().CopyToArrayData();
auto first_person = array->GetStruct(0);
std::string first_name = first_person->GetString(0);
行数据访问
Row 类
Row 类提供对结构体字段的随机访问:
class Row {
public:
// 空值检查
bool IsNullAt(int i) const;
// 基本类型 getter
bool GetBoolean(int i) const;
int8_t GetInt8(int i) const;
int16_t GetInt16(int i) const;
int32_t GetInt32(int i) const;
int64_t GetInt64(int i) const;
float GetFloat(int i) const;
double GetDouble(int i) const;
// 字符串/二进制 getter
std::string GetString(int i) const;
std::vector<uint8_t> GetBinary(int i) const;
// 嵌套类型
std::shared_ptr<Row> GetStruct(int i) const;
std::shared_ptr<ArrayData> GetArray(int i) const;
std::shared_ptr<MapData> GetMap(int i) const;
// 元数据
int num_fields() const;
SchemaPtr schema() const;
// 调试
std::string ToString() const;
};
ArrayData 类
ArrayData 类提供对列表/数组元素的访问:
class ArrayData {
public:
// 空值检查
bool IsNullAt(int i) const;
// 元素数量
int num_elements() const;
// 基本类型 getter(与 Row 相同)
int32_t GetInt32(int i) const;
// ... 其他基本类型
// 字符串 getter
std::string GetString(int i) const;
// 嵌套类型
std::shared_ptr<Row> GetStruct(int i) const;
std::shared_ptr<ArrayData> GetArray(int i) const;
std::shared_ptr<MapData> GetMap(int i) const;
// 类型信息
ListTypePtr type() const;
};
MapData 类
MapData 类提供对 map 键值对的访问:
class MapData {
public:
// 元素数量
int num_elements();
// 以数组形式访问键和值
std::shared_ptr<ArrayData> keys_array();
std::shared_ptr<ArrayData> values_array();
// 类型信息
MapTypePtr type();
};
Schema 和类型
Schema 定义
Schema 定义行数据的结构:
#include "fory/row/schema.h"
using namespace fory::row;
// 以编程方式创建 schema
auto person_schema = schema({
field("id", int32()),
field("name", utf8()),
field("score", float32()),
field("active", boolean())
});
// 访问 schema 信息
for (const auto& f : person_schema->fields()) {
std::cout << f->name() << ": " << f->type()->name() << std::endl;
}
类型系统
行格式可用的类型:
// 基本类型
DataTypePtr boolean(); // bool
DataTypePtr int8(); // int8_t
DataTypePtr int16(); // int16_t
DataTypePtr int32(); // int32_t
DataTypePtr int64(); // int64_t
DataTypePtr float32(); // float
DataTypePtr float64(); // double
// 字符串和二进制
DataTypePtr utf8(); // std::string
DataTypePtr binary(); // std::vector<uint8_t>
// 复杂类型
DataTypePtr list(DataTypePtr element_type);
DataTypePtr map(DataTypePtr key_type, DataTypePtr value_type);
DataTypePtr struct_(std::vector<FieldPtr> fields);