Skip to content

Parquet filtering - #2693

Merged
norberttech merged 8 commits into
1.xfrom
parquet-filtering
Oct 20, 2026
Merged

norberttech merged 8 commits into
1.xfrom
parquet-filtering

Conversation

@norberttech

@norberttech norberttech commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Resolves: #687

Change Log


Added

  • flow-php/parquet - filtered reads with row group, page index and bloom filter pruning
  • flow-php/parquet - row filtering during decode, with a limit beside the filter
  • flow-php/parquet - column index, offset index and bloom filter writing
  • flow-php/etl - DataFrame filters pushed into file sources
  • flow-php/etl-adapter-parquet - pushed filters translated into parquet reads
  • flow-php/arrow-ext - page-range reads and row filtering through arrow-rs

Fixed

  • flow-php/parquet - corrupt multi-page RLE_DICTIONARY columns written by the PHP writer
  • flow-php/parquet - UINT_64 values above PHP_INT_MAX read as numeric strings
  • flow-php/etl - string comparisons order by bytes instead of numerically
  • flow-php/arrow-ext - digit-only column option keys no longer ignored

Changed

  • flow-php/parquet - column statistics aligned with arrow-rs
  • flow-php/parquet - ParquetFile reads take a Query
  • flow-php/parquet - PAGE_MAXIMUM_ROWS_COUNT and ROW_GROUP_SIZE_BYTES enforced by both writers
  • flow-php/etl - file extractors read through FileScan
  • flow-php/etl - explain() shows pushed filters and limits under Read
  • flow-php/arrow-ext - built against arrow-rs 60

Removed

  • flow-php/parquet - unused DICTIONARY_PAGE_MIN_CARDINALITY_RATION option

Deprecated

Security

- type-aware physical ordering for statistics (unsigned, decimal, float16, IEEE 754 total order)
- column orders, statistics truncation and trusted min/max on read
- UINT_64 read and written as numeric string
- parquet.thrift and ThriftModel regenerated with nullable optional fields
- arrow-ext writes ENUM logical type and matches PHP writer statistics
- parquet-viewer shows statistics as logical values
- Filter API (parquet_column/all/any/not) and Query (parquet_query) with exact results
- row groups pruned by chunk statistics, identical on PHP and arrow engines
- reads take a ReadPlan instead of limit/offset, both extension ABIs bumped
- ParquetFileReader exposes a lazy Footer
- docs fail on a stale extension instead of writing wrong defaults
- FileScan carrier: FileExtractor::scan() replaces extract() limit/path filter
- push every deterministic AND conjunct into file sources, shown in EXPLAIN
- parquet: translate pushed predicates and skip row groups by statistics
- string comparisons in byte order through ValueOrder
- numeric_string comparable with string literals, ordered numerically
- PHP writer writes column and offset indexes (STATISTICS_LEVEL, COLUMN_INDEX_TRUNCATE_LENGTH)
- page index pruning narrows read plans below row groups
- both engines read only selected pages (arrow-ext on arrow-rs push decoder)
- fix RLE_DICTIONARY chunks spanning multiple pages
- page header statistics off by default (PAGE_HEADER_STATISTICS)
- FLOW_ARROW_ABI 2
- split block bloom filters, arrow-rs compatible sizing and folding
- COLUMNS_BLOOM_FILTERS option on the PHP and arrow writers
- equals/in prune row groups before the page index
- AND/OR truth combinators moved onto Truth
- fixture generators moved out of the repository
- both engines decode filter columns first, others only at kept rows
- arrow-ext filters with arrow-rs RowFilter, plan carries filter and limit
- limit pushed to the reader when the whole filter is bound
- PHP caches decoded filter pages and their dictionary for the output
- arrow ABI bumped to 3
…d beside it

- file extractors return only rows matching FileScan::$filter, conjunct by conjunct
- pushed conjuncts leave their Filter node, pushed leaf first, stopping at a kept conjunct
- a limit above a fully pushed filter reaches the scan
- ReplaceLeaf renamed ReplaceNode
- simplify filter binding and evaluation
- page reads through selected pages, malformed indexes ignored
- arrow writer: dictionary encodings, page row limit, size validation
- file sources filter through one shared evaluation
- explain() wording and plan node replacement reworked
- thrift generation behind bin/thrift.php parquet
@codecov

codecov Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.66045% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.04%. Comparing base (a963743) to head (d768dc1).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@             Coverage Diff              @@
##                1.x    #2693      +/-   ##
============================================
+ Coverage     89.39%   90.04%   +0.64%     
- Complexity        0    29380   +29380     
============================================
  Files          2117     2208      +91     
  Lines         82112    85514    +3402     
============================================
+ Hits          73403    76998    +3595     
+ Misses         8709     8516     -193     
Components Coverage Δ
etl 95.89% <100.00%> (+0.13%) ⬆️
cli 87.62% <ø> (ø)
lib-array-dot 96.52% <ø> (ø)
lib-azure-sdk 64.44% <ø> (ø)
lib-doctrine-dbal-bulk 94.24% <ø> (ø)
lib-filesystem 87.62% <ø> (ø)
lib-types 94.69% <ø> (+<0.01%) ⬆️
lib-parquet 81.66% <98.24%> (+7.88%) ⬆️
lib-parquet-viewer 83.15% <100.00%> (+1.07%) ⬆️
lib-snappy 89.42% <ø> (-0.45%) ⬇️
lib-dremel 0.00% <ø> (ø)
lib-postgresql 89.38% <ø> (ø)
lib-telemetry 86.64% <ø> (ø)
bridge-filesystem-async-aws 92.76% <ø> (ø)
bridge-filesystem-azure 90.34% <ø> (ø)
bridge-filesystem-sftp 91.02% <ø> (ø)
bridge-monolog-http 96.84% <ø> (ø)
bridge-monolog-telemetry 94.79% <ø> (ø)
bridge-openapi-specification 91.45% <ø> (ø)
symfony-http-foundation 75.81% <ø> (ø)
bridge-psr18-telemetry 100.00% <ø> (ø)
bridge-psr3-telemetry 98.95% <ø> (ø)
bridge-psr7-telemetry 100.00% <ø> (ø)
bridge-telemetry-otlp 90.11% <ø> (ø)
bridge-symfony-http-foundation-telemetry 92.85% <ø> (ø)
bridge-symfony-filesystem-bundle 91.85% <ø> (ø)
bridge-symfony-filesystem-cache 98.18% <ø> (ø)
bridge-symfony-postgresql-bundle 93.62% <ø> (ø)
bridge-symfony-postgresql-cache 94.41% <ø> (ø)
bridge-symfony-postgresql-messenger 98.80% <ø> (ø)
bridge-symfony-postgresql-session 93.65% <ø> (ø)
bridge-symfony-telemetry-bundle 90.72% <ø> (ø)
adapter-chartjs 79.14% <ø> (ø)
adapter-csv 96.64% <100.00%> (ø)
adapter-doctrine 94.86% <ø> (ø)
adapter-google-sheet 99.18% <ø> (ø)
adapter-http 88.29% <ø> (ø)
adapter-json 89.90% <100.00%> (ø)
adapter-logger 44.44% <ø> (ø)
adapter-parquet 95.13% <98.76%> (+1.41%) ⬆️
adapter-text 96.94% <100.00%> (+0.02%) ⬆️
adapter-xml 94.19% <100.00%> (+0.01%) ⬆️
adapter-avro 7.14% <0.00%> (ø)
adapter-excel 97.27% <100.00%> (ø)
adapter-postgresql 97.48% <ø> (ø)
adapter-seal 90.86% <ø> (ø)
bridge-phpunit-postgresql 75.30% <ø> (ø)
bridge-phpunit-telemetry 87.36% <ø> (ø)
bridge-phpstan-types 0.00% <ø> (ø)
bridge-postgresql-valinor 100.00% <ø> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@norberttech
norberttech merged commit d4eac8a into 1.x Oct 20, 2026
52 checks passed
@norberttech
norberttech deleted the parquet-filtering branch October 20, 2026 16:16
@github-project-automation github-project-automation Bot moved this from Todo to Done in Roadmap Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Parquet Filtering

1 participant