Parquet 中的索引

Posted

技术标签:

【中文标题】Parquet 中的索引【英文标题】:Index in Parquet 【发布时间】:2015-01-10 15:17:57 【问题描述】:

我希望能够对 Parquet 表进行快速范围查询。与总大小相比,要返回的数据量非常小,但由于必须执行全列扫描,因此对于我的用例来说太慢了。

使用索引可以解决这个问题,我读到这将在 Parquet 2.0 中添加。但是,我找不到任何其他信息,所以我猜它不是。如果对数据进行了排序,我认为不会有任何基本障碍阻止添加(多列)索引,在我的情况下是这样。

我的问题是:何时将索引添加到 Parquet,这样做的高级设计是什么?我想我已经对指出正确分区的索引感到满意了。

亲切的问候,

Sjoerd。

【问题讨论】:

很长一段时间。预定v2.0。 你可能会感兴趣:github.com/lightcopy/parquet-index blog.cloudera.com/… 【参考方案1】:

Parquet 目前保留每个数据页的最小/最大统计信息。数据页是一组约 1MB 的值(编码后),用于单个列;多个页面构成Parquet's column chunks。

这些最小/最大值用于过滤列块和组成块的页面。因此,您应该能够通过按要过滤的列对记录进行排序,然后将数据写入 Parquet 来缩短查询时间。这样,您就可以充分利用统计信息过滤。

您还可以通过减小页面和行组大小来使用此技术进行更精细的过滤,但您会牺牲编码效率和 I/O 效率。

【讨论】:

+1 很好的答案。问题虽然。 “您还可以通过减小页面和行组大小来使用此技术进行更精细的过滤” - 您指的是 mapred.max.split.size 还是其他内容? 我指的是两个 Parquet 设置:parquet.block.size(以字节为单位的目标行组大小,默认为 128MB)和parquet.page.size(在压缩前但编码后的目标页面大小,以字节为单位,默认1MB)。 有趣。谢谢你。这不会像使用 Cassandra 那样快,这是我现在所做的,但应该是一个很大的改进。当我有时间时,我会尝试一下。 链接“Parquet 的列块”不再起作用...【参考方案2】:

2018 年 12 月更新

Parquet Format 2.5 版添加了列索引。

https://github.com/apache/parquet-format/blob/master/CHANGES.md#version-250

有关该新功能的子任务列表,请参阅https://issues.apache.org/jira/browse/PARQUET-1201。

请注意,此功能刚刚合并到 Parquet 格式本身,不同的后端(Spark、Hive、Impala 等)需要一些时间才能开始支持它。

这项新功能称为列索引。基本上 Parquet 在 parquet 布局中添加了两个新结构 - 列索引和偏移索引。

下面是更详细的技术说明,它解决了什么以及如何解决

问题陈述

在当前格式中,为 ColumnMetaData 中的 ColumnChunks 和 DataPageHeader 结构中的各个页面存储统计信息。阅读者在阅读页面时,必须对页眉进行处理,以根据统计信息判断是否可以跳过该页面。这意味着读取器必须访问列中的所有页面,因此可能会从磁盘读取大部分列数据。

目标

通过允许基于页面的最小值和最大值直接访问页面,使范围扫描和点查找 I/O 都高效。特别是:

    根据行组的排序列在行组中进行单行查找 rowgroup 将只读取每个检索到的列的一个数据页。范围 对排序列的扫描只需要读取确切的数据页 包含相关数据。 进行其他选择性扫描 I/O 高效:如果我们对非排序有一个非常有选择性的谓词 列,对于其他检索到的列,我们只需要 访问包含匹配行的数据页。 没有额外的解码 在没有选择性谓词的情况下进行扫描,例如全行组 扫描。如果读者确定不需要阅读 索引数据,它不会产生任何开销。 已排序的索引页面 通过仅存储边界元素,列使用最少的存储空间 页面之间。

非目标

支持等效的二级索引,即根据未排序数据的键值排序的索引结构。

技术方法

我们向行组元数据添加两个新的每列结构: ColumnIndex:这允许基于列值导航到列的页面,并用于定位包含扫描谓词匹配值的数据页面 OffsetIndex:这允许按行索引导航,并用于检索通过 ColumnIndex 标识为匹配的行的值。一旦跳过一列的行,就必须跳过其他列中的相应行。因此,RowGroup 中每一列的 OffsetIndexes 存储在一起。

新的索引结构与 RowGroup 分开存储,靠近页脚,因此如果不进行选择性扫描,读取器无需支付 I/O 和反序列化成本来读取它们。索引结构的位置和长度存储在 ColumnChunk 和 RowGroup 中。

Cloudera 的 Impala 团队已对这一新功能进行了一些测试(尚未作为 Apache Impala 核心产品的一部分提供)。以下是他们的性能改进:

如您所见,一些查询在 CPU 时间和必须从磁盘读取的数据量方面都有了巨大的改进。

2016 年的原始答案

struct IndexPageHeader 
  /** TODO: **/

https://github.com/apache/parquet-format/blob/6e5b78d6d23b9730e19b78dceb9aac6166d528b8/src/main/thrift/parquet.thrift#L505

目前还没有实现索引页眉。

参见上面 Parquet 格式的源代码。 我目前在 Parquet 2.0 中也看不到它。

但是是的 - 上面 Ryan Blue 在 Parquet 上的出色回答是它具有伪索引功能(bloom 过滤器)。

如果您对更多细节感兴趣,我推荐关于 Parquet 布隆过滤器和谓词下推如何工作的精彩文档 https://www.slideshare.net/RyanBlue3/parquet-performance-tuning-the-missing-guide 更技术性的实施特定文件 - https://homepages.cwi.nl/~boncz/msc/2018-BoudewijnBraams.pdf

【讨论】:

还是一样:github.com/apache/parquet-format/blob/… Tagar,我还没有在镶木地板中看到任何布隆过滤。您能否启发您的答案,或参考来源? @Paul-ArmandVerhaegen 布隆过滤器始终存在,通常您无需执行任何操作即可启用它们。我为你添加了一些参考资料。 @Tagar,感谢您提供出色的阅读材料,但我很困惑。据我了解,您指的是使用 parquet 存储格式来实现布隆过滤器的框架。我们之前也使用过这个,例如,在无需读取整个 parquet 文件的情况下,是否有可能在 parquet 文件中找到一个 guid。如果需要,这可以存储在 parquet 文件的元数据中,但不支持 parquet 本身的布隆过滤。例如,请参阅 issues.apache.org/jira/browse/PARQUET-41 了解正在完成的工作。 是的,列索引在两个月前才被提交为 parquet 格式。 Parquet 阅读器依赖于实现,正如我在上面的答案中提到的,“请注意,这个功能刚刚合并到 Parquet 格式本身,不同的后端(Spark、Hive、Impala 等)需要一些时间才能开始支持它。 "

以上是关于Parquet 中的索引的主要内容,如果未能解决你的问题,请参考以下文章

为啥索引名称总是出现在用 pandas 创建的 parquet 文件中?

我可以通过索引访问 Parquet 文件而不将整个文件读入内存吗?

Azure Blob (pyarrow) 上的分区 Parquet 文件

使用谓词过滤 pyarrow.parquet.ParquetDataset 中的行

在 HIVE 中使用 CDH 5.4 和 Spark 1.3.0 和 Parquet 表的 PySpark 中的 Parquet 错误

Spark SQL 中的 Parquet 文件