Skip to content

[Parquet] Implement num distinct values for parquet writer - #10654

Merged
etseidl merged 6 commits into
apache:mainfrom
Rich-T-kid:rich-t-kid/parquet-write-nvd
Aug 19, 2026
Merged

etseidl merged 6 commits into
apache:mainfrom
Rich-T-kid:rich-t-kid/parquet-write-nvd

Conversation

@Rich-T-kid

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change

see #8608, #10650 & apache/datafusion#24114

What changes are included in this PR?

Adds set_write_row_group_number_distinct_values to WriterProperties, which when enabled causes the ArrowWriter to track the exact number of distinct non-null values per column across the full row group and write it into the column chunk statistics footer as distinct_count. Tracking is implemented by hashing each non-null value using XxHash64 into a per-column HashSet that persists across batch writes and is finalized in close(). The flag defaults to false so there is no impact on existing writers.

Are these changes tested?

yes, see test.

Are there any user-facing changes?

yes, users will not be able to write distinct_count meta data to parquet files.

@github-actions github-actions Bot added the parquet Changes to the parquet crate label Aug 12, 2026
@Rich-T-kid
Rich-T-kid force-pushed the rich-t-kid/parquet-write-nvd branch from cda6e4a to 5111139 Compare August 12, 2026 13:09
Comment thread parquet/src/file/properties.rs Resolved
@Rich-T-kid
Rich-T-kid force-pushed the rich-t-kid/parquet-write-nvd branch from 5111139 to 5676cca Compare August 12, 2026 13:16
@etseidl etseidl changed the title [Parquet] Implement nvd for parquet writer [Parquet] Implement num distinct values for parquet writer Aug 12, 2026
@Rich-T-kid
Rich-T-kid requested a review from etseidl August 14, 2026 13:54
Comment thread parquet/src/arrow/arrow_writer/mod.rs Resolved
Comment thread parquet/src/arrow/arrow_writer/mod.rs Resolved
Comment thread parquet/src/arrow/arrow_writer/mod.rs Resolved
@Rich-T-kid
Rich-T-kid force-pushed the rich-t-kid/parquet-write-nvd branch from 48c40aa to d1fa404 Compare August 14, 2026 14:27
@Rich-T-kid

Copy link
Copy Markdown
Contributor Author

@etseidl could you please take a look at this when you get a chance

@etseidl

etseidl commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Yes, sorry @Rich-T-kid, still catching up from some time off 😅

@Rich-T-kid

Copy link
Copy Markdown
Contributor Author

Yes, sorry @Rich-T-kid, still catching up from some time off 😅

@etseidl no worries! sorry about the ping

@etseidl etseidl 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.

Thanks @Rich-T-kid, I think this looks good.

Am I right in thinking this will only work for the arrow writer (i.e. the row-based API will not populate the distinct count)? If so, we might want to note that in the docs.

@etseidl

etseidl commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

@etseidl no worries! sorry about the ping

And feel free to ping me any time, it's no bother...I'm scatterbrained 😅

@Rich-T-kid
Rich-T-kid force-pushed the rich-t-kid/parquet-write-nvd branch from d1fa404 to 4db4725 Compare August 18, 2026 22:39
@github-actions github-actions Bot added arrow Changes to the arrow crate arrow-array labels Aug 18, 2026
@Rich-T-kid
Rich-T-kid force-pushed the rich-t-kid/parquet-write-nvd branch from 4db4725 to 62d6619 Compare August 18, 2026 22:41
@github-actions github-actions Bot removed arrow Changes to the arrow crate arrow-array labels Aug 18, 2026
@Rich-T-kid

Copy link
Copy Markdown
Contributor Author

Thanks @Rich-T-kid, I think this looks good.

Am I right in thinking this will only work for the arrow writer (i.e. the row-based API will not populate the distinct count)? If so, we might want to note that in the docs.

thanks @etseidl. 62d6619 should address your comments

@etseidl

etseidl commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

I'll give this a day before merging to allow others to take a look if they wish. Thanks again!

@etseidl

etseidl commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Hearing no objections, the PR is merged. Thanks @Rich-T-kid

@etseidl
etseidl merged commit 3320517 into apache:main Aug 19, 2026
18 checks passed
Rich-T-kid added a commit to Rich-T-kid/arrow-rs that referenced this pull request Aug 26, 2026
)

# Which issue does this PR close?

- Closes apache#8608.
- Closes apache#10650

# Rationale for this change

see apache#8608, apache#10650 & apache/datafusion#24114

# What changes are included in this PR?
Adds `set_write_row_group_number_distinct_values` to WriterProperties,
which when enabled causes the ArrowWriter to track the exact number of
distinct non-null values per column across the full row group and write
it into the column chunk statistics footer as `distinct_count`. Tracking
is implemented by hashing each non-null value using XxHash64 into a
per-column HashSet<u64> that persists across batch writes and is
finalized in `close()`. **The flag defaults to false so there is no
impact on existing writers.**

# Are these changes tested?
yes, see test.

# Are there any user-facing changes?
yes, users will not be able to write `distinct_count` meta data to
parquet files.
Rich-T-kid added a commit to Rich-T-kid/arrow-rs that referenced this pull request Aug 28, 2026
)

# Which issue does this PR close?

- Closes apache#8608.
- Closes apache#10650

# Rationale for this change

see apache#8608, apache#10650 & apache/datafusion#24114

# What changes are included in this PR?
Adds `set_write_row_group_number_distinct_values` to WriterProperties,
which when enabled causes the ArrowWriter to track the exact number of
distinct non-null values per column across the full row group and write
it into the column chunk statistics footer as `distinct_count`. Tracking
is implemented by hashing each non-null value using XxHash64 into a
per-column HashSet<u64> that persists across batch writes and is
finalized in `close()`. **The flag defaults to false so there is no
impact on existing writers.**

# Are these changes tested?
yes, see test.

# Are there any user-facing changes?
yes, users will not be able to write `distinct_count` meta data to
parquet files.
Rich-T-kid added a commit to Rich-T-kid/arrow-rs that referenced this pull request Sep 2, 2026
)

# Which issue does this PR close?

- Closes apache#8608.
- Closes apache#10650

# Rationale for this change

see apache#8608, apache#10650 & apache/datafusion#24114

# What changes are included in this PR?
Adds `set_write_row_group_number_distinct_values` to WriterProperties,
which when enabled causes the ArrowWriter to track the exact number of
distinct non-null values per column across the full row group and write
it into the column chunk statistics footer as `distinct_count`. Tracking
is implemented by hashing each non-null value using XxHash64 into a
per-column HashSet<u64> that persists across batch writes and is
finalized in `close()`. **The flag defaults to false so there is no
impact on existing writers.**

# Are these changes tested?
yes, see test.

# Are there any user-facing changes?
yes, users will not be able to write `distinct_count` meta data to
parquet files.
Rich-T-kid added a commit to Rich-T-kid/arrow-rs that referenced this pull request Sep 18, 2026
)

# Which issue does this PR close?

- Closes apache#8608.
- Closes apache#10650

# Rationale for this change

see apache#8608, apache#10650 & apache/datafusion#24114

# What changes are included in this PR?
Adds `set_write_row_group_number_distinct_values` to WriterProperties,
which when enabled causes the ArrowWriter to track the exact number of
distinct non-null values per column across the full row group and write
it into the column chunk statistics footer as `distinct_count`. Tracking
is implemented by hashing each non-null value using XxHash64 into a
per-column HashSet<u64> that persists across batch writes and is
finalized in `close()`. **The flag defaults to false so there is no
impact on existing writers.**

# Are these changes tested?
yes, see test.

# Are there any user-facing changes?
yes, users will not be able to write `distinct_count` meta data to
parquet files.
Rich-T-kid added a commit to Rich-T-kid/arrow-rs that referenced this pull request Sep 21, 2026
)

# Which issue does this PR close?

- Closes apache#8608.
- Closes apache#10650

# Rationale for this change

see apache#8608, apache#10650 & apache/datafusion#24114

# What changes are included in this PR?
Adds `set_write_row_group_number_distinct_values` to WriterProperties,
which when enabled causes the ArrowWriter to track the exact number of
distinct non-null values per column across the full row group and write
it into the column chunk statistics footer as `distinct_count`. Tracking
is implemented by hashing each non-null value using XxHash64 into a
per-column HashSet<u64> that persists across batch writes and is
finalized in `close()`. **The flag defaults to false so there is no
impact on existing writers.**

# Are these changes tested?
yes, see test.

# Are there any user-facing changes?
yes, users will not be able to write `distinct_count` meta data to
parquet files.
etseidl pushed a commit that referenced this pull request Sep 22, 2026
# Which issue does this PR close?

- Closes #10804..

# Rationale for this change

set_write_row_group_number_distinct_values was added in #10654 with no
benchmarks. This PR adds them so the cost of NDV tracking is visible and
regressions are catchable going forward.

# What changes are included in this PR?

Adds a `bench_ndv` benchmark group to `parquet/benches/arrow_writer.rs`
covering the data types that NDV tracking supports: Int32 (primitive),
Boolean, Utf8, LargeBinary, and FixedSizeBinary(16).

Each group writes 10 batches of 65,536 rows through a single ArrowWriter
with `set_write_row_group_number_distinct_values(true)`. Two cardinality
shapes are exercised per type: low (100 distinct values, cycling) and
high (all unique, random), since hash-set behaviour differs meaningfully
between the two.

# Are these changes tested?
n/a

# Are there any user-facing changes?
n/a
cargo bench --bench arrow_writer --features arrow/test_utils -- "ndv/"
Rich-T-kid added a commit to Rich-T-kid/arrow-rs that referenced this pull request Sep 25, 2026
)

# Which issue does this PR close?

- Closes apache#8608.
- Closes apache#10650

# Rationale for this change

see apache#8608, apache#10650 & apache/datafusion#24114

# What changes are included in this PR?
Adds `set_write_row_group_number_distinct_values` to WriterProperties,
which when enabled causes the ArrowWriter to track the exact number of
distinct non-null values per column across the full row group and write
it into the column chunk statistics footer as `distinct_count`. Tracking
is implemented by hashing each non-null value using XxHash64 into a
per-column HashSet<u64> that persists across batch writes and is
finalized in `close()`. **The flag defaults to false so there is no
impact on existing writers.**

# Are these changes tested?
yes, see test.

# Are there any user-facing changes?
yes, users will not be able to write `distinct_count` meta data to
parquet files.
adriangb pushed a commit to pydantic/datafusion that referenced this pull request Oct 9, 2026
…ues to statistics (apache#25576)

## Which issue does this PR close?

<!--
We generally require a GitHub issue to be filed for all bug fixes and
enhancements and this helps us generate change logs for our releases.
You can link an issue to this PR using the GitHub syntax. For example
`Closes apache#123` indicates that this PR will close issue apache#123.
-->

- Closes apache#24114.

## Rationale for this change

DataFusion can use NDV (number of distinct values) from Parquet row
group statistics to power optimizations like COUNT(DISTINCT) aggregation
pushdown and cardinality estimation (apache#24111) . However, currently the
Parquet writers doesn't emit NDV by default, so these statistics are
absent for roundtrip queries.

Two recent arrow-rs additions make it possible to close this gap
end-to-end:
- [arrow-rs apache#10652 —
`StatisticsConverter::row_group_distinct_counts()`](apache/arrow-rs#10652)
: a typed API for reading NDV from row group metadata
- [arrow-rs apache#10654 —
`WriterPropertiesBuilder::set_write_row_group_number_distinct_values()`](apache/arrow-rs#10654):
a writer-side option to track and emit NDV during write

This PR wires both into DataFusion so that users can write parquet files
with NDV and have DataFusion read them back correctly.

<!--
Why are you proposing this change? If this is already explained clearly
in the issue then this section is not needed.
Explaining clearly why changes are proposed helps reviewers understand
your changes and offer better suggestions for fixes.

Please explain the problem you are trying to solve in terms of the
user-visible
behavior, rather than the implementation.

For example, "The code in `foo.rs` doesn't handle nulls" is a symptom of
the
implementation. "COUNT(DISTINCT) returns wrong results when the column
contains
nulls" is the user-visible problem.
-->

## What changes are included in this PR?

- summarize_distinct_counts now calls
`StatisticsConverter::row_group_distinct_counts()` instead of manually
walking column chunk statistics.
- Adds
`datafusion.execution.parquet.write_row_group_number_distinct_values`
(bool, default false) to ParquetOptions. When enabled, the ArrowWriter
hashes every non-null value per column per row group and writes the
distinct count into the Parquet statistics footer.

<!--
There is no need to duplicate the description in the issue here, but it
is sometimes worth providing a summary of the individual changes in this
PR.
-->

## What is the testing strategy for this PR?

- The NDV read change is covered by the 8 existing unit tests in
metadata.rs (test_distinct_count_*), which all continue to pass.
- The write config is tested by
sqllogictest/test_files/parquet_ndv_write.slt, which writes 4 rows with
3 distinct values and verifies:
- Without the option: Distinct is absent from DataSourceExec statistics
- With the option: Distinct=Exact(3) appears in DataSourceExec
statistics


<!--
We typically require tests for all PRs in order to:
1. Prevent the code from being accidentally broken by subsequent changes
2. Serve as another way to document the expected behavior of the code

Briefly describe how this PR is tested, and point to the specific tests
you added. For example: 'This new feature is covered by the
`sqllogictest` cases added in `foo.slt`'.

If this PR does not add tests, explain why. For example, if the change
is already covered by existing tests, please mention it.

You should also check the `codecov` bot reply on this PR to confirm the
changed code is exercised.
-->

## Are there any user-facing changes?
yes, new `write_row_group_number_distinct_values` to parquet config
options.
<!--
If there are user-facing changes then we may require documentation to be
updated before approving the PR.

If there are any breaking changes to public APIs, please add the `api
change` label.
-->
Omega359 pushed a commit to Omega359/arrow-datafusion that referenced this pull request Oct 11, 2026
…ues to statistics (apache#25576)

## Which issue does this PR close?

<!--
We generally require a GitHub issue to be filed for all bug fixes and
enhancements and this helps us generate change logs for our releases.
You can link an issue to this PR using the GitHub syntax. For example
`Closes apache#123` indicates that this PR will close issue apache#123.
-->

- Closes apache#24114.

## Rationale for this change

DataFusion can use NDV (number of distinct values) from Parquet row
group statistics to power optimizations like COUNT(DISTINCT) aggregation
pushdown and cardinality estimation (apache#24111) . However, currently the
Parquet writers doesn't emit NDV by default, so these statistics are
absent for roundtrip queries.

Two recent arrow-rs additions make it possible to close this gap
end-to-end:
- [arrow-rs apache#10652 —
`StatisticsConverter::row_group_distinct_counts()`](apache/arrow-rs#10652)
: a typed API for reading NDV from row group metadata
- [arrow-rs apache#10654 —
`WriterPropertiesBuilder::set_write_row_group_number_distinct_values()`](apache/arrow-rs#10654):
a writer-side option to track and emit NDV during write

This PR wires both into DataFusion so that users can write parquet files
with NDV and have DataFusion read them back correctly.

<!--
Why are you proposing this change? If this is already explained clearly
in the issue then this section is not needed.
Explaining clearly why changes are proposed helps reviewers understand
your changes and offer better suggestions for fixes.

Please explain the problem you are trying to solve in terms of the
user-visible
behavior, rather than the implementation.

For example, "The code in `foo.rs` doesn't handle nulls" is a symptom of
the
implementation. "COUNT(DISTINCT) returns wrong results when the column
contains
nulls" is the user-visible problem.
-->

## What changes are included in this PR?

- summarize_distinct_counts now calls
`StatisticsConverter::row_group_distinct_counts()` instead of manually
walking column chunk statistics.
- Adds
`datafusion.execution.parquet.write_row_group_number_distinct_values`
(bool, default false) to ParquetOptions. When enabled, the ArrowWriter
hashes every non-null value per column per row group and writes the
distinct count into the Parquet statistics footer.

<!--
There is no need to duplicate the description in the issue here, but it
is sometimes worth providing a summary of the individual changes in this
PR.
-->

## What is the testing strategy for this PR?

- The NDV read change is covered by the 8 existing unit tests in
metadata.rs (test_distinct_count_*), which all continue to pass.
- The write config is tested by
sqllogictest/test_files/parquet_ndv_write.slt, which writes 4 rows with
3 distinct values and verifies:
- Without the option: Distinct is absent from DataSourceExec statistics
- With the option: Distinct=Exact(3) appears in DataSourceExec
statistics


<!--
We typically require tests for all PRs in order to:
1. Prevent the code from being accidentally broken by subsequent changes
2. Serve as another way to document the expected behavior of the code

Briefly describe how this PR is tested, and point to the specific tests
you added. For example: 'This new feature is covered by the
`sqllogictest` cases added in `foo.slt`'.

If this PR does not add tests, explain why. For example, if the change
is already covered by existing tests, please mention it.

You should also check the `codecov` bot reply on this PR to confirm the
changed code is exercised.
-->

## Are there any user-facing changes?
yes, new `write_row_group_number_distinct_values` to parquet config
options.
<!--
If there are user-facing changes then we may require documentation to be
updated before approving the PR.

If there are any breaking changes to public APIs, please add the `api
change` label.
-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parquet Changes to the parquet crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Populate and read distinct_count from parquet column statistics Implement (optional) distinct count population in Parquet statistics

2 participants