我正在学习 Parquet File 的内部表示过程,因此我通过 Apache Parquet 的 Github page、Google Dremel 的 paper 来了解定义和重复级别,以及 Twitter 的 blog 来了解有关 Parquet 文件的更多信息。
为了将我通过阅读获得的其表示形式的理解与实际的 Parquet 文件表示形式联系起来,我对示例 Parquet 文件之一使用了
parquet-tools
命令和 meta
选项,并打印了包含 3 个主要部分的详细信息:标题、文件架构和 Row_groups。我理解前 2 部分中提供的详细信息,但我无法完全理解行组部分中提供的所有详细信息。
以下是我的问题。
DO
、FPO
、VC
(这看起来像是当前行组中所有行的计数)是什么。它所代表的含义的扩展可以在 parquet-tools Github page 中找到,但我想获得更多关于它的细节。我明白 SZ
和 ST
是什么。ENC
旁边,我看到了编码方案列表,例如 BIT_PACKED
、PLAIN
、RLE
。我理解它各自的含义,但我不明白为什么总是使用至少 3 种编码方案。 RC
和总大小 TS
旁边,我看到 OFFSET
。对于第一页,它始终是 4。是怎么计算的?.不幸的是,由于安全限制,我无法附加
parquet-tools meta
命令输出的片段,但我希望它不会太形象化我在每个问题中的意思。
此页面有我发现的最好的描述: https://github.com/apache/parquet-mr/tree/master/parquet-tools-deprecated
因此,DO、FPO 似乎只是该特定列的值开始的偏移信息。 VC = 现有非空值的值计数。
使用 pandas 创建 Parquet 文件
import pandas as pd
df = pd.DataFrame({
'w1': ["John", "Max", "Hans"],
'w2': ["Doe", "Mustermann", "Peter"],
'w3': ["New York", "Berlin", "München"],
'w4': [1990, 1980, 1970]})
df.to_parquet('./test_pandas.lz4.parquet', compression="lz4")
parquet-tools.jar 的元输出,带有
java -jar ./parquet-tools-1.10.1.jar meta <file>
file schema: schema
--------------------------------------------------------------------------------
w1: OPTIONAL BINARY O:UTF8 R:0 D:1
w2: OPTIONAL BINARY O:UTF8 R:0 D:1
w3: OPTIONAL BINARY O:UTF8 R:0 D:1
w4: OPTIONAL INT64 R:0 D:1
row group 1: RC:3 TS:440 OFFSET:4
--------------------------------------------------------------------------------
w1: BINARY LZ4 DO:4 FPO:51 SZ:98/79/0.81 VC:3 ENC:PLAIN_DICTIONARY,RLE,PLAIN ST:[min: Hans, max: Max, num_nulls: 0]
w2: BINARY LZ4 DO:165 FPO:219 SZ:106/87/0.82 VC:3 ENC:PLAIN_DICTIONARY,RLE,PLAIN ST:[min: Doe, max: Peter, num_nulls: 0]
w3: BINARY LZ4 DO:337 FPO:394 SZ:115/97/0.84 VC:3 ENC:PLAIN_DICTIONARY,RLE,PLAIN ST:[min: Berlin, max: New York, num_nulls: 0]
w4: INT64 LZ4 DO:524 FPO:565 SZ:121/109/0.90 VC:3 ENC:PLAIN_DICTIONARY,RLE,PLAIN ST:[min: 1970, max: 1990, num_nulls: 0]
我知道这是一个旧的,但在我发现这有帮助的任何地方仍然没有任何记录。
在
org.apache.parquet:parquet-cli:org/apache/parquet/cli/Util.java
public static String encodingsAsString(Set<Encoding> encodings, ColumnDescriptor desc) {
StringBuilder sb = new StringBuilder();
if (encodings.contains(RLE) || encodings.contains(BIT_PACKED)) {
sb.append(desc.getMaxDefinitionLevel() == 0 ? "B" : "R");
sb.append(desc.getMaxRepetitionLevel() == 0 ? "B" : "R");
if (encodings.contains(PLAIN_DICTIONARY)) {
sb.append("R");
}
if (encodings.contains(PLAIN)) {
sb.append("_");
}
} else {
sb.append("RR");
if (encodings.contains(RLE_DICTIONARY)) {
sb.append("R");
}
if (encodings.contains(PLAIN)) {
sb.append("_");
}
if (encodings.contains(DELTA_BYTE_ARRAY)
|| encodings.contains(DELTA_BINARY_PACKED)
|| encodings.contains(DELTA_LENGTH_BYTE_ARRAY)) {
sb.append("D");
}
}
return sb.toString();
}