type
status
date
slug
summary
tags
category
icon
password
索引
支持多种索引:HBASE, INMEMORY, BLOOM, GLOBAL_BLOOM, SIMPLE, GLOBAL_SIMPLE, BUCKET
以下索引不建议使用:
- INMEMRY 索引
根据内存中的索引数据去匹配,基本不可用
- SIMPLE 索引
根据新数据所在的分区,获取受影响的分区文件列表,直接读取该部分 parquet 文件的 partition_key 和 record_key,与新数据执行 leftOutJoin 产生索引数据,性能低下(以 hoodieKey 为匹配键)
- HBASE 索引
需要引入额外的 Hbase 服务,业务方基本不会允许
- GLOBAL_SIMPLE 索引
与 SIMPLE 索引相比,GLOBAL_SIMPLE 索引读取的旧数据是全量数据,以 recordkey为匹配键,性能更低下
BLOOM
写入信息
org.apache.hudi.io.storage.HoodieAvroOrcWriter
org.apache.hudi.avro.HoodieBloomFilterWriteSupport#finalizeMetadata
可以看到这里会写入布隆过滤器序列化后的信息和主键的 MIN/MAX 信息。
写入到 parquet 文件的 footer 中。
读取信息
org.apache.hudi.common.util.BaseFileUtils#readBloomFilterFromMetadata
从 footer 中读取信息,构建布隆过滤器。
结论
还是写入 footer 中,跟 Iceberg 差不多,只是 bloomfilter 的算法可能不同。
GLOBAL_BLOOM
全局索引强制跨表的所有分区的键的唯一性,即保证表中对于给定的记录键恰好存在一条记录。
和 BLOOM 的区别
加载文件时加载全部分区的数据文件
org.apache.hudi.index.bloom.HoodieGlobalBloomIndex#loadColumnRangesFromFiles
org.apache.hudi.index.bloom.HoodieBloomIndex#loadColumnRangesFromFiles
只加载特定分区
结论
这么看,GLOBAL_BLOOM 并不能实现比 BLOOM 更好的性能。
BUCKET
推荐在较大数据量的场景下使用,避免布隆过滤器的假阳性问题。
MetadataTable
MetadataTable 是一张包含元数据的 mor 表,记录了数据表的文件、列统计、布隆过滤器的信息。
写入打标:
column_stat_idx | bloom_filter_idx | bucket_idx | flink_state | Simple | Hbase_idx | |
Spark | Y | Y | Y | N flink only | Y | Y |
Flink | N | N | Y | Y | N spark only | N |
MetaDataTable表索引分区构建:
file_idx | column_stat_idx | bloom_filter_idx | |
Spark | Y | Y | Y |
Flink | Y | Y | Y |
读取data skipping:
column_stat_idx | bloom_filter_idx | bucket_idx | |
Spark | Y | N | N |
Flink | Y | N | N |
MetadataTable 的使用
org.apache.hudi.HoodieFileIndex#lookupCandidateFilesInMetadataTable
结论
dataskip 的时候只使用了 column_stat_idx 信息。
其他优化
TimelineService
构建 timeline 的时候避免从 HDFS 上读取数据文件。