UnsafeRow
Pollux 支持两种开箱即用的数据序列化格式: PrestoPage 和 UnsafeRow。这些格式用于数据 shuffle。Pollux 应用程序 也可以注册自己的格式。
PrestoPage 格式的描述请参阅 Presto 文档。 本文介绍来自 Apache Spark 的 UnsafeRow 格式。
一行是由 3 个部分组成的连续缓冲区:
null bits | fixed-width data | variable-width data
每个 部分按 8 字节对齐。
空位部分每列包含一位。0 位表示非空值。1 位表示空值。
“固定宽度数据”部分每列包含 8 个字节。适合 8 个字节的固定宽度列的值(布尔值、整数、浮点数、短小数)将直接存储。
可变宽度列(字符串、数组、映射)的值以及宽度超过 8 个字节的固定宽度列(长小数)的值会被拆分到固定宽度和可变宽度部分中。固定宽度部分的 8 个字节用于存储值在可变宽度部分中的大小和位置。
“可变宽度数据”部分存储可变宽度列的值。每个值都与 8 个字节对齐。
字符串直接存储,不包含以空字符结尾的字节。
数组以 8 个字节存储,大小与数组大小相同,数组元素大多以 UnsafeRow 格式序列化。固定宽度数组元素 仅使用必要的字节数进行序列化,例如,TINYINT 和 BOOLEAN元素每个元素使用 1 个字节,SMALLINT 元素每个元素使用 2 个字节,BIGINT元素每个元素使用 8 个字节。“固定宽度数据”部分 仍然按 8 个字节对齐。
array size | null bits | fixed-width data | variable-width data
“空位”为每个数组元素存储一位,用于指示哪些元素为空。
Map 以 8 个字节的大小存储,大小等于序列化后的键数组的大小,后跟序列化为 UnsafeRow 的键数组和值数组。
序列化后的键数组的大小(以字节为单位)| <键数组> | <值数组>
其中 <键数组> 为
键的数量 | 空位 | 固定宽度数据 | 可变宽度数据
而 <值数组> 为
值的数量 | 空位 | 固定宽度数据 | 可变宽度数据
上述键的数量和值的数量相同,且等于 Map 的大小。这些键和值的数量在序列化后的数据中是重复的。
结构体字段以“空位”形式存储,后跟固定宽度字段值和可变宽度字段值。
Pollux 类型 UNKNOWN 的值(仅限空值)将被视为固定宽度类型。顶层列和结构体字段中的 UNKNOWN 值在空值部分占用 1 位,在固 定宽度部分占用 8 个字节。序列化为数组元素或映射值的 UNKNOWN 值使用 1 位作为空值标志,并使用零字节作为值。
长小数将以二进制形式存储,其内容使用 Java BigInteger 进行序列化,BigInteger 具有用于序列化的函数“toByteArray”和用于反序 列化的构造函数“BigInteger(byte[] var)”。
Examples
包含 INTEGER 和 BIGINT 两列的行,序列化大小固定为 24 字节。其中 8 字节用于空值标志。8 字节用于第一列的值。 8 字节用于第二列的值。请注意,任何值,包括 BOOLEAN 和 TINYINT,都至少占用 8 个字节。
包 含单个 BIGINT 数组的行,序列化大小可变。一个包含 10 个元素的数组 [0, 11, 22, 33, 44, 55, 66, 77, 88, 99] 占用 112 个字节。
- 8 字节用于空值标志。
- 8 字节用于可变宽度数据的大小和偏移量。
- 8 字节用于数组大小 (10)。
- 8 字节用于数组元素的空值标志。
- 10 个固定宽度数组元素占用 80 (= 8 * 10) 个字节。
包含单个 TINYINT 数组的行具有可变的序列化大小。包含 10 个元素的数组 [0, 11, 22, 33, 44, 55, 66, 77, 88, 99] 使用 48 个字节。
- 8 个字节用于空标志。
- 8 个字节用于可变宽度数据的大小和偏移量。
- 8 个字节用于数组大小(10)。
- 8 个字节用于数组元素的空标志。
- 10 个固定宽度数组元素占用 16 个字节(每个元素 1 个字节,以 8 字节对齐)。
包含单个 BIGINT 到 BIGINT MAP 的行具有可变的序列化大小。大小为 3 的 map
[1 => 10, 2 => 20, 3 => 30] 使用 104 个字节。
- 8 个字节用于空标志。
- 8 个字节用于可变宽度数据的大小和偏移量。
- 8 个字节用于序列化键数组的大小(40)。
- 8 个字节用于键的数量。
- 8 个字节用于键的空标志。
- 24(= 8 * 3)个字节用于 3 个固定宽度键。
- 8 个字节用于值的数量。
- 8 个字节用于值的空标志。
- 24(= 8 * 3)个字节用于 3 个固定宽度的值。
包含单个 BIGINT 和 DOUBLE 结构体的行,其序列化大小固定为 40 字节。
- 8 字节用于空值标志。
- 8 字节用于可变宽度数据的大小和偏移量。
- 8 字节用于结构体字段的空值标志。
- 8 字节用于第一个结构体字段的值。
- 8 字节用于第二个结构体字段的值。
Batches of Rows
引擎通常需要对一批行进行序列化。在这种情况下,可以通过依次序列化行大小和 UnsafeRow 缓冲区来创建一批序列化的 UnsafeRow,具体方式如下:
行大小 | UnsafeRow | 行大小 | UnsafeRow | ...
请注意,“行大小”整数需要为 4 个字节,并使用 大端格式进行编码。需要注意的是,这与 UnsafeRow 负载中序列化的其他整数不同,其他整数均应为小端。