
Apache Arrow 统计信息 Schema 规范以 Arrow 数组标准化表达统计信息的完整指南【免费下载链接】arrowApache Arrow is the universal columnar format and multi-language toolbox for fast data interchange and in-memory analytics项目地址: https://gitcode.com/GitHub_Trending/arrow3/arrow导读本文详解 Apache Arrow 官方格式规范文档 StatisticsSchema.rst 中定义的统计信息 SchemaStatistics schema——一套将数据集统计信息行数、空值数、去重数、最大/最小值、字节宽度等标准化表示为 Apache Arrow 数组的规范。该规范解决了查询引擎在通过 Arrow C Stream 接口交换数据时无法传递列统计信息的问题是跨系统统计信息互操作的基础。读完本文你将掌握统计信息 Schema 的完整结构、全部预定义统计名称、精确/近似值变体约定以及通过 RecordBatch::MakeStatisticsArray() 等源码接口生成和消费统计数组的方法。⚠️注意本规范仍处于**实验性experimental**阶段由 StatisticsSchema.rst 明确标注实际采用时需留意版本演进。一、设计动机为什么需要标准化的统计信息 Schema1.1 背景查询引擎需要统计信息统计信息对快速查询处理至关重要。许多查询引擎依赖统计信息来优化查询计划query plan——例如根据列的去重基数、空值比例、最小/最大值来推断选择性、决定连接顺序或选择扫描策略。然而 Apache Arrow 格式本身不携带统计信息。矛盾点在于能够被读取为 Apache Arrow 数据的外部格式如 Apache Parquet通常带有统计信息。例如Apache Parquet C 实现可以读取 Parquet 文件并输出为 Apache Arrow 数据而 Parquet 文件本身可能带有列级统计信息。1.2 核心思路用 Arrow 数组承载统计信息本规范的出发点非常直接将统计信息的表示标准化为一个 Apache Arrow 数组以便于交换。也就是说统计信息本身也是一份 Arrow 数据遵循统一的 Schema 结构从而可以在任何支持 Arrow 的系统之间自由传递而不需要额外约定私有协议。1.3 典型使用场景C Stream Interface 中的数据交换规范以 C Stream InterfaceArrowArrayStream结构为例描述了典型链路模块 A 读取 Apache Parquet 文件将其转换为 Apache Arrow 数据模块 A 通过 Arrow C Stream 接口把数据传递给模块 B模块 B 处理接收到的 Arrow 数据。如果模块 A 能同时把与 Parquet 文件关联的统计信息传给模块 B模块 B 就能用它优化自己的查询计划。规范特别指出DuckDB 就采用了这种数据交换方式但由于此前缺少面向 Apache Arrow 数据的统计信息标准化表示DuckDB 无法有效利用统计信息。本规范正是为了填补这一空白而提出。1.4 目标与非目标类别内容Goals目标建立一种将统计信息表示为 Apache Arrow 数组的标准方式Non-goals非目标① 不规定传递统计数组的标准方式② 不规定如何把统计信息嵌入Arrow 数组本身可以看出本规范刻意保持最小范围只定义统计信息的 Schema至于如何传输、如何嵌入留给上层实现或后续规范解决。二、统计信息 Schema 结构详解2.1 总体轮廓规范给出的统计 Schema 顶层结构如下struct column: int32, statistics: map key: dictionaryvalues: utf8, indices: int32, items: dense_union...all needed types... 这是一个嵌套三层的结构外层struct描述目标对象某列或整个数据集中间层map按统计名称组织键值内层dense_union承载异构类型的统计值。2.2 顶层 struct 字段名称数据类型可空说明columnint32true从零开始的列索引若统计信息描述的是整个 record batch 或 array则为null。列索引的计算规则与 IPC 的 record batch 消息 中定义的规则一致statisticsmapfalse目标列、record batch 或 array 的统计信息详见下方map结构2.3 statistics 的 map 结构键或值数据类型可空说明keydictionaryvalues: utf8, indices: int32false字符串键是统计名称。采用字典编码是为了节省空间——同一统计名可能在不同列上重复出现。精确与近似统计值使用不同的键。每种统计的详细说明见下文itemsdense_unionfalse统计值采用dense union类型其子类型至少覆盖 keys 中出现的所有统计类型。例如同时有int64的去重计数和float64的平均字节宽度统计时union 中至少要有int64和float64两种子类型关于 dense union 字段命名规范特别说明dense union 数组的每个字段都有名字但本规范不标准化这些字段名——因为可以通过**类型码type code**访问正确的字段字段名可以使用任意合法名称。这一设计避免了无意义的命名约束。三、标准统计名称Standard Statistics3.1 命名机制每种统计都有一个名称作为各列或整个 record batch/array 的 statistics map 中的 key。名称通过dictionaryvalues: utf8, indices: int32编码以节省空间。关键约定同一统计的变体用不同名称区分而非用标志位flags。例如去重计数的精确值与近似值对应两个不同的统计名称。冒号:用作命名空间分隔符与 Metadata.rst 中format_metadata的约定一致可在名称中出现多次。ARROW前缀是保留命名空间供本规范当前及未来版本的预定义统计名称使用用户自定义统计不得使用。自定义统计示例可使用产品名作为命名空间如MY_PRODUCT:my_statistics:exact。3.2 预定义统计名称总表名称数据类型说明ARROW:average_byte_width:exactfloat64目标列中一行的平均字节大小精确值ARROW:average_byte_width:approximatefloat64目标列中一行的平均字节大小近似值ARROW:distinct_count:exactint64目标列中去重值的数量精确值ARROW:distinct_count:approximatefloat64目标列中去重值的数量近似值ARROW:max_byte_width:exactint64目标列中一行的最大字节大小精确值ARROW:max_byte_width:approximatefloat64目标列中一行的最大字节大小近似值ARROW:max_value:exact取决于目标类型目标列中的最大值精确值ARROW:max_value:approximate取决于目标类型目标列中的最大值近似值ARROW:min_value:exact取决于目标类型目标列中的最小值精确值ARROW:min_value:approximate取决于目标类型目标列中的最小值近似值ARROW:null_count:exactint64目标列中空值的数量精确值ARROW:null_count:approximatefloat64目标列中空值的数量近似值ARROW:row_count:exactint64目标 record batch 或 array 的行数精确值ARROW:row_count:approximatefloat64目标 record batch 或 array 的行数近似值值得注意的类型设计所有计数类统计row_count、null_count、distinct_count的精确值用int64近似值用float64——近似值通常是估算结果可能非整数max_value/min_value的数据类型取决于目标列的类型如目标为字符串则可能是 utf8/binary 系列目标为数值则相应为 int64/float64 等这正是内层使用dense_union承载异构值的根本原因字节宽度类统计average_byte_width、max_byte_width衡量一行的字节大小可用于评估列压缩收益与 IO 成本。3.3 扩展新统计如果发现某个统计可能对多个系统都有用规范建议在 Apache Arrow 开发邮件列表中提出提案。生产者与消费者遵循事先约定的统计规范时互操作性会更好——这再次强调了标准化名称的价值。四、源码级印证统计 Schema 在 Arrow C 中的落地本规范并非纸上谈兵Arrow C 库中已有对应的实现证据。4.1 统计名称宏定义C ABI在 cpp/src/arrow/c/abi.h 中14 个预定义统计名称被定义为 C 宏常量与文档表格一一对应# define ARROW_STATISTICS_KEY_AVERAGE_BYTE_WIDTH_EXACT ARROW:average_byte_width:exact # define ARROW_STATISTICS_KEY_AVERAGE_BYTE_WIDTH_APPROXIMATE ARROW:average_byte_width:approximate # define ARROW_STATISTICS_KEY_DISTINCT_COUNT_EXACT ARROW:distinct_count:exact # define ARROW_STATISTICS_KEY_DISTINCT_COUNT_APPROXIMATE ARROW:distinct_count:approximate # define ARROW_STATISTICS_KEY_MAX_BYTE_WIDTH_EXACT ARROW:max_byte_width:exact # define ARROW_STATISTICS_KEY_MAX_BYTE_WIDTH_APPROXIMATE ARROW:max_byte_width:approximate # define ARROW_STATISTICS_KEY_MAX_VALUE_EXACT ARROW:max_value:exact # define ARROW_STATISTICS_KEY_MAX_VALUE_APPROXIMATE ARROW:max_value:approximate # define ARROW_STATISTICS_KEY_MIN_VALUE_EXACT ARROW:min_value:exact # define ARROW_STATISTICS_KEY_MIN_VALUE_APPROXIMATE ARROW:min_value:approximate # define ARROW_STATISTICS_KEY_NULL_COUNT_EXACT ARROW:null_count:exact # define ARROW_STATISTICS_KEY_NULL_COUNT_APPROXIMATE ARROW:null_count:approximate # define ARROW_STATISTICS_KEY_ROW_COUNT_EXACT ARROW:row_count:exact # define ARROW_STATISTICS_KEY_ROW_COUNT_APPROXIMATE ARROW:row_count:approximate4.2 ArrayStatistics 结构C APIcpp/src/arrow/array/statistics.h 定义了arrow::ArrayStatistics结构从 C API 角度落实了文档中的字段模型row_count、null_count、distinct_count均为std::optionalCountType即int64_t或double——当为int64_t表示精确值为double表示近似值与文档的命名约定吻合max_byte_widthstd::optionalSizeType同理区分精确/近似average_byte_widthstd::optionaldouble配合is_average_byte_width_exact标志min/maxstd::optionalValueType其中ValueType std::variantbool, int64_t, uint64_t, double, std::string通过MinArrowType()/MaxArrowType()依据目标数组类型如 binary 类类型推导出对应的 Arrow 数据类型提供Equals()用于统计信息的相等比较。4.3 MakeStatisticsArray从 RecordBatch 生成统计数组cpp/src/arrow/record_batch.cc 中的RecordBatch::MakeStatisticsArray()是规范的直接实现它按文档中的 Schema 轮廓代码注释中同样写明了structcolumn: int32, statistics: mapkey: dictionary..., items: dense_union...结构构造统计数组其关键构建步骤包括收集 union 子类型遍历统计信息动态收集去重后的值类型列表构造dense_union类型构建字典键statistics.key使用StringDictionary32Builder构建dictionary(int32(), utf8(), false)组装完整类型struct_({field(column, int32()), field(statistics, map(keys_type, values_type, false))})并行构建分别用Int32Builder、StringDictionary32Builder、DenseUnionBuilder、MapBuilder填充各层数据。4.4 测试验证cpp/src/arrow/record_batch_test.cc 提供了成体系的单元测试如MakeStatisticsArrayRowCount、MakeStatisticsArrayNullCountExact、MakeStatisticsArrayNullCountApproximate、MakeStatisticsArrayDistinctCountExact、MakeStatisticsArrayMaxByteWidthExact、MakeStatisticsArrayAverageByteWidthApproximate等逐一验证各统计名称的精确/近似值变体如何被正确编码进统计数组。五、示例一简单 Record Batch5.1 数据与统计目标Schemavendor_id: int32 passenger_count: int64Datavendor_id: [5, 1, 5, 1, 5] passenger_count: [1, 1, 2, 0, null]期望的统计结果目标统计名称值Record batch行数5vendor_id空值数0vendor_id去重数2vendor_id最大值5vendor_id最小值1passenger_count空值数1passenger_count去重数3passenger_count最大值2passenger_count最小值05.2 列索引索引目标0vendor_id1passenger_count5.3 统计 Schema本示例所有统计值都是int64因此 dense union 只有一个int64子类型struct column: int32, statistics: map key: dictionaryvalues: utf8, indices: int32, items: dense_union0: int64 5.4 统计数组column: [ null, # record batch 0, # vendor_id 1, # passenger_count ] statistics: offsets: [ 0, 1, # record batch: 1 value: [0] 5, # vendor_id: 4 values: [1, 2, 3, 4] 9, # passenger_count: 4 values: [5, 6, 7, 8] ] key: values: [ ARROW:row_count:exact, ARROW:null_count:exact, ARROW:distinct_count:exact, ARROW:max_value:exact, ARROW:min_value:exact, ] indices: [ 0, # ARROW:row_count:exact 1, # ARROW:null_count:exact 2, # ARROW:distinct_count:exact 3, # ARROW:max_value:exact 4, # ARROW:min_value:exact 1, # ARROW:null_count:exact 2, # ARROW:distinct_count:exact 3, # ARROW:max_value:exact 4, # ARROW:min_value:exact ] items: children: 0: [ # int64 5, # record batch: ARROW:row_count:exact 0, # vendor_id: ARROW:null_count:exact 2, # vendor_id: ARROW:distinct_count:exact 5, # vendor_id: ARROW:max_value:exact 1, # vendor_id: ARROW:min_value:exact 1, # passenger_count: ARROW:null_count:exact 3, # passenger_count: ARROW:distinct_count:exact 2, # passenger_count: ARROW:max_value:exact 0, # passenger_count: ARROW:min_value:exact ] types: [ # all values are int64 0, 0, 0, 0, 0, 0, 0, 0, 0, ] offsets: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, ]解读关键点column数组首元素为null表示该行统计描述整个 record batch行数5map 的offsets把 9 个统计值切分为三段record batch 1 个、vendor_id4 个、passenger_count4 个字典key.values只存储 5 个唯一统计名称indices通过整数索引引用这正是字典编码节省空间的体现dense union 的types数组全部为0int64offsets为递增序列——这是 dense union 的标准布局。六、示例二复杂 Record Batch嵌套类型6.1 数据与统计目标本示例引入嵌套类型展示了嵌套列的统计目标寻址方式。Schemacol1: structa: int32, b: listitem: int64, c: float64 col2: utf8Datacol1: [ {a: 1, b: [20, 30, 40], c: 2.9}, {a: 2, b: null, c: -2.9}, {a: 3, b: [99], c: null}, ] col2: [x, null, z]统计结果目标统计名称值Record batch行数3col1空值数0col1.a空值数0col1.a去重数3col1.a近似最大值5col1.a近似最小值0col1.b空值数1col1.b.item最大值99col1.b.item最小值20col1.c空值数1col1.c近似最大值3.0col1.c近似最小值-3.0col2空值数1col2去重数26.2 列索引嵌套列展开索引目标0col11col1.a2col1.b3col1.b.item4col1.c5col2嵌套列的索引计算规则同样遵循 IPC record batch 消息 中的约定struct和list等嵌套类型会逐层展开子字段因此col1内部的a、b、b.item、c各自占据独立索引。6.3 统计 Schemastruct column: int32, statistics: map key: dictionaryvalues: utf8, indices: int32, items: dense_union # For the number of rows, the number of nulls and so on. 0: int64, # For the max/min values of col1.c. 1: float64 由于col1.c的最大/最小值是浮点数dense union 需要int64 和 float64 两个子类型。6.4 统计数组column: [ null, # record batch 0, # col1 1, # col1.a 2, # col1.b 3, # col1.b.item 4, # col1.c 5, # col2 ] statistics: offsets: [ 0, 1, # record batch: 1 value: [0] 2, # col1: 1 value: [1] 6, # col1.a: 4 values: [2, 3, 4, 5] 7, # col1.b: 1 value: [6] 9, # col1.b.item: 2 values: [7, 8] 12, # col1.c: 3 values: [9, 10, 11] 14, # col2: 2 values: [12, 13] ] key: values: [ ARROW:row_count:exact, ARROW:null_count:exact, ARROW:distinct_count:exact, ARROW:max_value:approximate, ARROW:min_value:approximate, ARROW:max_value:exact, ARROW:min_value:exact, ] indices: [ 0, # ARROW:row_count:exact 1, # ARROW:null_count:exact 1, # ARROW:null_count:exact 2, # ARROW:distinct_count:exact 3, # ARROW:max_value:approximate 4, # ARROW:min_value:approximate 1, # ARROW:null_count:exact 5, # ARROW:max_value:exact 6, # ARROW:min_value:exact 1, # ARROW:null_count:exact 3, # ARROW:max_value:approximate 4, # ARROW:min_value:approximate 1, # ARROW:null_count:exact 2, # ARROW:distinct_count:exact ] items: children: 0: [ # int64 3, # record batch: ARROW:row_count:exact 0, # col1: ARROW:null_count:exact 0, # col1.a: ARROW:null_count:exact 3, # col1.a: ARROW:distinct_count:exact 5, # col1.a: ARROW:max_value:approximate 0, # col1.a: ARROW:min_value:approximate 1, # col1.b: ARROW:null_count:exact 99, # col1.b.item: ARROW:max_value:exact 20, # col1.b.item: ARROW:min_value:exact 1, # col1.c: ARROW:null_count:exact 1, # col2: ARROW:null_count:exact 2, # col2: ARROW:distinct_count:exact ] 1: [ # float64 3.0, # col1.c: ARROW:max_value:approximate -3.0, # col1.c: ARROW:min_value:approximate ] types: [ 0, # int64: record batch: ARROW:row_count:exact 0, # int64: col1: ARROW:null_count:exact 0, # int64: col1.a: ARROW:null_count:exact 0, # int64: col1.a: ARROW:distinct_count:exact 0, # int64: col1.a: ARROW:max_value:approximate 0, # int64: col1.a: ARROW:min_value:approximate 0, # int64: col1.b: ARROW:null_count:exact 0, # int64: col1.b.item: ARROW:max_value:exact 0, # int64: col1.b.item: ARROW:min_value:exact 0, # int64: col1.c: ARROW:null_count:exact 1, # float64: col1.c: ARROW:max_value:approximate 1, # float64: col1.c: ARROW:min_value:approximate 0, # int64: col2: ARROW:null_count:exact 0, # int64: col2: ARROW:distinct_count:exact ] offsets: [ 0, # int64: record batch: ARROW:row_count:exact 1, # int64: col1: ARROW:null_count:exact 2, # int64: col1.a: ARROW:null_count:exact 3, # int64: col1.a: ARROW:distinct_count:exact 4, # int64: col1.a: ARROW:max_value:approximate 5, # int64: col1.a: ARROW:min_value:approximate 6, # int64: col1.b: ARROW:null_count:exact 7, # int64: col1.b.item: ARROW:max_value:exact 8, # int64: col1.b.item: ARROW:min_value:exact 9, # int64: col1.c: ARROW:null_count:exact 0, # float64: col1.c: ARROW:max_value:approximate 1, # float64: col1.c: ARROW:min_value:approximate 10, # int64: col2: ARROW:null_count:exact 11, # int64: col2: ARROW:distinct_count:exact ]解读关键点dense union 的两个子数组各自独立存储children[0]int64共 12 个值、children[1]float64共 2 个值types数组按统计值出现的顺序标注其 union 类型码offsets则给出每个值在其所属子数组内部的偏移——注意 float64 子数组的 offsets 是0, 1从各自子数组重新计数这正是 dense union 与 sparse union 的本质区别同一个统计名称如ARROW:null_count:exact在不同列上复用字典索引1验证了字典编码的压缩效果注意col1.a的 max/min 使用近似名称值5/0未必是真实的精确最值而col1.b.item使用精确名称说明生产者可以按需为不同目标选择不同精度的统计。七、示例三简单 Array7.1 数据与统计目标当统计目标是单个数组而非 record batch时column字段同样适用。Schemaint64Data[1, 1, 2, 0, null]统计结果目标统计名称值Array行数5Array空值数1Array去重数3Array最大值2Array最小值0列索引索引目标0Array7.2 统计 Schema 与统计数组struct column: int32, statistics: map key: dictionaryvalues: utf8, indices: int32, items: dense_union0: int64 column: [ 0, # array ] statistics: offsets: [ 0, 5, # array: 5 values: [0, 1, 2, 3, 4] ] key: values: [ ARROW:row_count:exact, ARROW:null_count:exact, ARROW:distinct_count:exact, ARROW:max_value:exact, ARROW:min_value:exact, ] indices: [ 0, # ARROW:row_count:exact 1, # ARROW:null_count:exact 2, # ARROW:distinct_count:exact 3, # ARROW:max_value:exact 4, # ARROW:min_value:exact ] items: children: 0: [ # int64 5, # array: ARROW:row_count:exact 1, # array: ARROW:null_count:exact 3, # array: ARROW:distinct_count:exact 2, # array: ARROW:max_value:exact 0, # array: ARROW:min_value:exact ] types: [ # all values are int64 0, 0, 0, 0, 0, ] offsets: [ 0, 1, 2, 3, 4, ]解读关键点数组场景下column取0而非null因为整个数组就是唯一的统计目标列索引 0。与 record batch 场景的唯一区别在于没有描述整个数据集的null行——数组中不存在列与非列的区分。八、示例四复杂 Array嵌套类型8.1 数据与统计目标Schemastructa: int32, b: listitem: int64, c: float64Data[ {a: 1, b: [20, 30, 40], c: 2.9}, {a: 2, b: null, c: -2.9}, {a: 3, b: [99], c: null}, ]统计结果目标统计名称值Array行数3Array空值数0a空值数0a去重数3a近似最大值5a近似最小值0b空值数1b.item最大值99b.item最小值20c空值数1c近似最大值3.0c近似最小值-3.0列索引嵌套展开索引目标0Array1a2b3b.item4c8.2 统计 Schema 与统计数组struct column: int32, statistics: map key: dictionaryvalues: utf8, indices: int32, items: dense_union # For the number of rows, the number of nulls and so on. 0: int64, # For the max/min values of c. 1: float64 column: [ 0, # array 1, # a 2, # b 3, # b.item 4, # c ] statistics: offsets: [ 0, 2, # array: 2 values: [0, 1] 6, # a: 4 values: [2, 3, 4, 5] 7, # b: 1 value: [6] 9, # b.item: 2 values: [7, 8] 12, # c: 3 values: [9, 10, 11] ] key: values: [ ARROW:row_count:exact, ARROW:null_count:exact, ARROW:distinct_count:exact, ARROW:max_value:approximate, ARROW:min_value:approximate, ARROW:max_value:exact, ARROW:min_value:exact, ] indices: [ 0, # ARROW:row_count:exact 1, # ARROW:null_count:exact 1, # ARROW:null_count:exact 2, # ARROW:distinct_count:exact 3, # ARROW:max_value:approximate 4, # ARROW:min_value:approximate 1, # ARROW:null_count:exact 5, # ARROW:max_value:exact 6, # ARROW:min_value:exact 1, # ARROW:null_count:exact 3, # ARROW:max_value:approximate 4, # ARROW:min_value:approximate ] items: children: 0: [ # int64 3, # array: ARROW:row_count:exact 0, # array: ARROW:null_count:exact 0, # a: ARROW:null_count:exact 3, # a: ARROW:distinct_count:exact 5, # a: ARROW:max_value:approximate 0, # a: ARROW:min_value:approximate 1, # b: ARROW:null_count:exact 99, # b.item: ARROW:max_value:exact 20, # b.item: ARROW:min_value:exact 1, # c: ARROW:null_count:exact ] 1: [ # float64 3.0, # c: ARROW:max_value:approximate -3.0, # c: ARROW:min_value:approximate ] types: [ 0, # int64: array: ARROW:row_count:exact 0, # int64: array: ARROW:null_count:exact 0, # int64: a: ARROW:null_count:exact 0, # int64: a: ARROW:distinct_count:exact 0, # int64: a: ARROW:max_value:approximate 0, # int64: a: ARROW:min_value:approximate 0, # int64: b: ARROW:null_count:exact 0, # int64: b.item: ARROW:max_value:exact 0, # int64: b.item: ARROW:min_value:exact 0, # int64: c: ARROW:null_count:exact 1, # float64: c: ARROW:max_value:approximate 1, # float64: c: ARROW:min_value:approximate ] offsets: [ 0, # int64: array: ARROW:row_count:exact 1, # int64: array: ARROW:null_count:exact 2, # int64: a: ARROW:null_count:exact 3, # int64: a: ARROW:distinct_count:exact 4, # int64: a: ARROW:max_value:approximate 5, # int64: a: ARROW:min_value:approximate 6, # int64: b: ARROW:null_count:exact 7, # int64: b.item: ARROW:max_value:exact 8, # int64: b.item: ARROW:min_value:exact 9, # int64: c: ARROW:null_count:exact 0, # float64: c: ARROW:max_value:approximate 1, # float64: c: ARROW:min_value:approximate ]解读关键点与复杂 Record Batch示例相比本示例的差别仅在于column数组首元素为0array 本身而非null其余 map、字典、dense union 的布局逻辑完全一致。两个示例共同验证了嵌套类型统计的目标寻址规则struct与list的子字段如b.item都拥有独立列索引并可独立携带统计。九、生产与消费实践要点结合规范与源码实现可以归纳出以下实践要点Schema 是唯一约定传输方式留给上层本规范只定义统计数组长什么样不定义怎么传。在 C Stream Interface 场景下通常由生产者额外暴露一个统计数组接口消费者按本 Schema 解析即可。精确/近似命名分离是硬约定不要用标志位表达近似性而要选用对应的统计名称如ARROW:distinct_count:approximate而非ARROW:distinct_count:exact加布尔标志这样才能保证跨系统语义一致。dense_union 子类型按需构建如 MakeStatisticsArray() 所示union 的字段集合由实际出现的统计类型动态决定——先枚举统计值收集去重类型再构建 union。消费端应通过类型码而非字段名访问值。ARROW 命名空间不可侵占自定义统计必须以ARROW之外的命名空间前缀开头如MY_PRODUCT:my_statistics:exact避免与未来版本预定义名称冲突。嵌套列索引遵循 IPC 规则统计数组的column字段对嵌套类型逐层展开编号计算规则与 IPC record batch 消息 一致消费端需按相同规则对齐。注意实验性状态规范、C ABI 宏abi.h及 C APIstatistics.h仍在演进接入时建议跟随上游版本更新并关注 记录统计相关测试 所覆盖的行为边界。十、总结Apache Arrow 统计信息 Schema 规范用一份标准的嵌套 Arrow 数组structcolumn, mapdictionary key, dense_union items统一了如何用 Arrow 数据表达列统计信息这一跨系统互操作问题。它通过ARROW:保留命名空间、冒号分隔的统计名称、以及 exact/approximate 名称变体在简洁性与可扩展性之间取得了平衡同时以 dictionary 编码与 dense union 兼顾了空间效率与异构类型表达。规范配套的 C 实现ArrayStatistics、MakeStatisticsArray与 C ABI 宏定义使其不仅是一份文档更是可直接落地的工程方案——这正是查询引擎跨模块传递统计信息、优化查询计划所缺失的关键一环。【免费下载链接】arrowApache Arrow is the universal columnar format and multi-language toolbox for fast data interchange and in-memory analytics项目地址: https://gitcode.com/GitHub_Trending/arrow3/arrow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考