Skip to content

docs(performance): document Parquet bloom filters and separate them from the bloom index - #19590

Merged
voonhous merged 1 commit into
apache:asf-sitefrom
rangareddy:docs-16063-parquet-bloom-filters
Aug 30, 2026
Merged

docs(performance): document Parquet bloom filters and separate them from the bloom index#19590
voonhous merged 1 commit into
apache:asf-sitefrom
rangareddy:docs-16063-parquet-bloom-filters

Conversation

@rangareddy

@rangareddy rangareddy commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Describe the issue this Pull Request addresses

Closes #16063 (HUDI-6456), "Add parquet blooms documentation".

Hudi forwards Parquet's per-column bloom filter settings through to the Parquet writer, but the only trace of
bloom filters in the docs was one auto-generated row in configurations.md — and that row is for a different
feature
with a near-identical name. So nothing told a user that these keys exist, that they are per column,
or that they are read from the Hadoop configuration:

parquet.bloom.filter.enabled#<column>
parquet.bloom.filter.expected.ndv#<column>

Summary and Changelog

Adds a Parquet Bloom Filters subsection to performance.md, under Read Path next to Data Skipping,
because that is precisely the gap it fills: column stats prune on ranges and so help least for an equality
predicate on a high-cardinality column whose min-max spans nearly every file — which is what a bloom filter
covers.

The section states the two keys, that they are per column, how to set them from Spark (spark.hadoop. prefix),
how to size expected.ndv, that it is a write-time decision so an existing table only picks them up as it is
rewritten, and — added after review — what the read side needs: nothing, on Spark 3.x, beyond an equality
predicate that can be pushed down.

Two caveats are called out, because both are easy to get wrong and neither was written down anywhere:

  1. hoodie.parquet.bloom.filter.enabled is not this feature. It controls whether Hudi writes a bloom
    filter of record keys into the footer for the bloom index during
    upserts. It defaults to true, applies only when meta fields are populated, and is implied anyway when
    hoodie.index.type names a BLOOM index. Setting it does not enable per-column Parquet filters. Given
    the names differ by one prefix, a user reading configurations.md could reasonably conclude the opposite.
  2. The settings are applied reflectively and failure is swallowed. On a Parquet without
    withBloomFilterEnabled / withBloomFilterNDV, the keys are silently ignored rather than rejected.

Verification

Docs change, so no test to add — said plainly rather than implied. Every claim was read off master
(3ba31dd37fff):

claim source
keys are read from the Hadoop config, per column HoodieBaseParquetWriter.handleParquetBloomFilters, :98-119 — iterates the Configuration and splits the column off each key
exact key spelling HoodieBaseParquetWriter:52-53, and TestHoodieParquetBloom.scala:36-37 sets parquet.bloom.filter.enabled#bloom_col / expected.ndv#bloom_col on jsc.hadoopConfiguration
forwarded via withBloomFilterEnabled / withBloomFilterNDV :105 and :114, invoked by reflection
silently ignored on an older Parquet :107-109 and :116-118NoSuchMethodException is caught and skipped
hoodie.parquet.bloom.filter.enabled is about record-key blooms for the bloom index HoodieStorageConfig:252-258 (default true, since 0.15.0) and HoodieFileWriterFactory.enableBloomFilter:141-146 (populateMetaFields && (thisConfig ‖ index.type contains BLOOM))
Flink sets them the same way TestHoodieRowDataParquetConfigInjector:100-101
the read path actually consults them TestHoodieParquetBloomFilter (hudi-spark): sets the write keys, disables parquet.filter.columnindex.enabled and parquet.filter.stats.enabled so only a bloom can skip, then asserts 0 row groups scanned for an absent value vs 1 for a present one, reading via spark.read.format("hudi"), over BULK_INSERT / INSERT / UPSERT / INSERT_OVERWRITE on COW
parquet.filter.bloom.enabled left at its default that same test disables stats and columnindex but never the bloom switch, and grep finds Hudi setting it nowhere

Version coverage. The feature ships in every currently-supported release, so the section is added to the
current docs and to all five supported versioned copies:

tree why
website/docs/ current / next
versioned_docs/version-1.2.0, 1.1.1, 1.0.2, 1.0.1, 1.0.0 all ≥ 0.14.0, so all have the feature

Checked rather than assumed: handleParquetBloomFilters is absent at release-0.13.1 and present from
release-0.14.0 onward, and the hoodie.parquet.bloom.filter.enabled config it is contrasted against reads
defaultValue(true) / sinceVersion("0.15.0") identically at release-1.0.0, 1.0.2, 1.1.1 and 1.2.0
— so every claim in the text is accurate for each version it lands in. The five-version fan-out matches how
other cross-version docs fixes have been applied (#19555, #19459). The 0.15.x and 0.14.x copies are left
alone: they have had no, or nearly no, doc commits in the last six months and are effectively frozen.

version-1.0.0/performance.md has no ## Related Resources heading — its page ends after Data Skipping —
so there the section is appended at the end of the file rather than before that anchor. Everywhere else it is
inserted before it.

Markdown checked by running markdownlint over all six files before and after and comparing rule
classes rather than counts, since these files already carry findings:

before: MD007 MD009 MD012 MD013 MD031 MD033 MD040
after : MD007 MD009 MD012 MD013 MD031 MD033 MD040   ->  no new class of finding

Also checked across all six: every <column> occurrence sits inside inline code, so nothing new is exposed
to the MDX parser; the indexes.md link target exists in every one of the five versioned trees so the
relative link resolves in each; and the inserted region is byte-identical in all six files.

Deliberately not naming TestHoodieParquetBloomFilter in the docs page itself: a user-facing reference to a
test class rots silently on a rename, which is the objection @hudi-agent raised on #19486. The evidence lives
here and in the commit message instead.

Not done: the Docusaurus build (website/node_modules absent, full install heavy). The section adds a
table, a fenced block and two admonitions, all constructs already used on this page.

Relationship to #9056

@parisni opened #9056 ("[HUDI-6456] [DOC] Add parquet blooms documentation") for this same issue in
June 2023, and it is still open. I did not see it when I opened this PR — I checked the issue timeline for
cross-referenced PRs, and because #9056 predates the JIRA-migrated issue it never linked there, even though
hudi-bot had posted a "Linked PR(s)" comment naming it. That was my error and I have said so on both threads.

The two differ in shape: #9056 adds a dedicated parquet_bloom.md page (plus a Parquet Config section in
configurations.md), where this one adds a section to performance.md next to Data Skipping. #9056 also
carries material this PR does not — how dictionary encoding makes blooms redundant below ~40k distinct
values, and NDV rationale — while this PR carries the config name collision, the silent-reflection caveat and
the five-version fan-out that #9056 does not have. I have posted those findings on #9056 as review comments
too, so they are available whichever shape a committer prefers, and I am happy to fold this content into that
PR instead if that is the preference.

Impact

Documentation only — no code, config, API or format change. Two features whose names differ by one prefix are
now distinguishable, and a write-side knob that previously required reading HoodieBaseParquetWriter to
discover is now documented.

Risk Level

none

Documentation Update

This is the documentation update. Targets asf-site; applied to docs/ plus the five supported versioned
copies (1.2.0, 1.1.1, 1.0.2, 1.0.1, 1.0.0), as justified in Verification above.

Contributor's checklist

  • Read through contributor's guide
  • Enough context is provided in the sections above
  • Adequate tests were added if applicable — n/a for docs; verification table above instead
  • CI passes on my PR — asf-site PRs do not run the master gates; markdownlint parity checked locally
    as described

@github-actions github-actions Bot added docs size:S PR with lines of changes in (10, 100] labels Aug 12, 2026

@hudi-agent hudi-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ 🤖 This review was generated by an AI agent and may contain mistakes. Please verify any suggestions before applying.

Thanks for the docs update! This adds a well-organized Parquet Bloom Filters section to performance.md, clearly stating the per-column write keys, the spark.hadoop. forwarding, sizing guidance, and two easy-to-miss caveats (the name collision with hoodie.parquet.bloom.filter.enabled and the swallowed reflection failure). My main concern is that the section is placed under "Read Path" but only documents the write-side keys — it doesn't mention what a reader needs to actually consult these filters. Please have a Hudi committer confirm the read-path behavior before merging.

Comment thread website/docs/performance.md
Comment thread website/docs/performance.md Outdated
@rangareddy
rangareddy force-pushed the docs-16063-parquet-bloom-filters branch from 234eced to 32cacba Compare August 12, 2026 07:09
…rom the bloom index

Parquet's per-column bloom filters have been passthrough-configurable in Hudi since 0.14.0, but the
only trace of them in the docs was an auto-generated row in configurations.md - and that row is for
a different feature (see below). Nothing told a user the keys exist, that they are per column, or
that they are read from the Hadoop config.

Adds a "Parquet Bloom Filters" subsection to performance.md under Read Path, next to Data Skipping,
since that is the gap it fills: column stats prune on ranges and are least useful for an equality
predicate on a high-cardinality column, which is exactly what a bloom filter covers.

  parquet.bloom.filter.enabled#<column>       write a bloom filter for that column
  parquet.bloom.filter.expected.ndv#<column>  expected distinct values, sizes the filter

HoodieBaseParquetWriter.handleParquetBloomFilters scans the Hadoop configuration for those prefixes
and forwards each to the Parquet writer builder, so from Spark they are set with the spark.hadoop.
prefix. The spelling matches TestHoodieParquetBloom, which sets exactly these keys on
jsc.hadoopConfiguration.

Two things are called out because both are easy to get wrong:

  - hoodie.parquet.bloom.filter.enabled is NOT this feature, despite the name. It controls whether
    Hudi writes a bloom filter of RECORD KEYS into the footer for the bloom index during upserts; it
    defaults to true, applies only when meta fields are populated, and is implied when
    hoodie.index.type names a BLOOM index (HoodieFileWriterFactory.enableBloomFilter). Setting it
    does not enable per-column Parquet filters.
  - the settings are applied by reflection and the NoSuchMethodException is swallowed, so on a
    Parquet without withBloomFilterEnabled / withBloomFilterNDV they are silently ignored.

Applied to the current docs and to every supported versioned copy - 1.2.0, 1.1.1, 1.0.2, 1.0.1 and
1.0.0 - because the feature ships in all of them: handleParquetBloomFilters is absent at
release-0.13.1 and present from release-0.14.0 onwards, and the hoodie.parquet.bloom.filter.enabled
config it is contrasted against reads defaultValue(true)/sinceVersion(0.15.0) identically at
release-1.0.0, 1.0.2, 1.1.1 and 1.2.0, so the text is accurate for each. That five-version fan-out
matches how other cross-version docs fixes have been applied (apache#19555, apache#19459). version-1.0.0 has no
"Related Resources" heading, so there the section is appended at the end of the page instead of
before it; the inserted text is byte-identical in all six files.

The 0.15.x and 0.14.x copies are left alone: they have had no or nearly no doc commits in the last
six months and are effectively frozen.

Review follow-up: says what the read side needs, since the section sits under Read Path while the
keys it documents are write-side. On Spark 3.x nothing extra is configured - reading back through the
Hudi datasource consults the filters given a pushed-down equality predicate, and
TestHoodieParquetBloomFilter pins that by disabling the statistics and column-index filter levels so
only a bloom can cause a skip, then asserting zero row groups scanned for an absent value against one
for a present value. parquet.filter.bloom.enabled is left at its parquet-mr default and Hudi never
sets it. Also renamed the example column from uuid, which read like a record key, and said outright
that <column> is any data column filtered by equality rather than the record key.

Closes apache#16063
@rangareddy
rangareddy force-pushed the docs-16063-parquet-bloom-filters branch from 32cacba to 41a3a0d Compare August 12, 2026 07:15
@rangareddy rangareddy assigned rangareddy and unassigned rangareddy Aug 12, 2026

@hudi-agent hudi-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ 🤖 This review was generated by an AI agent and may contain mistakes. Please verify any suggestions before applying.

Thanks for the docs update! This adds a well-sourced "Parquet Bloom Filters" section to performance.md (and the versioned copies), covering the per-column parquet.bloom.filter.* write-time keys, expected.ndv sizing, the read-side behavior on Spark 3.x, and a clear note distinguishing these from Hudi's own record-key hoodie.parquet.bloom.filter.enabled. I verified each claim against master — the write-path keys and reflection behavior in HoodieBaseParquetWriter, and the record-key config's true default / meta-fields / BLOOM-index conditions in HoodieStorageConfig and HoodieFileWriterFactory — and all are accurate; the round-1 concerns were already addressed. Please have a Hudi committer or PMC member do a final pass before merge.

cc @yihua

@github-actions github-actions Bot added size:M PR with lines of changes in (100, 300] and removed size:S PR with lines of changes in (10, 100] labels Aug 12, 2026
@uros-b

uros-b commented Aug 24, 2026

Copy link
Copy Markdown
Member

Thank you @rangareddy! +1

@voonhous
voonhous merged commit 8f3432e into apache:asf-site Aug 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs size:M PR with lines of changes in (100, 300]

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants