Commit d0a9b91
Fix strict NotEqualTo/NotIn pruning with partial nulls or NaNs (#3521)
## Summary
Related to #3498
Fix strict metrics evaluation for `NotEqualTo` and `NotIn` so files are
only proven to match when a column contains only nulls or only NaNs.
Mixed null/NaN files now continue through the existing bounds checks
instead of being treated as `ROWS_MUST_MATCH`.
## Root Cause
The strict evaluator used `_can_contain_nulls` / `_can_contain_nans` for
negative predicates. That is too broad: a file with values like `[null,
5]` and bounds `5..5` cannot be proven to match `x != 5` or `x not in
{5}` because the non-null row may still fail the predicate.
## Java Parity
This matches Java's `StrictMetricsEvaluator`, which only short-circuits
negative predicates when the column contains only nulls or only NaNs:
-
[`notEq`](https://github.com/apache/iceberg/blob/0b30919372df34afb632f037df88c05cdba0b134/api/src/main/java/org/apache/iceberg/expressions/StrictMetricsEvaluator.java#L341-L375)
-
[`notIn`](https://github.com/apache/iceberg/blob/0b30919372df34afb632f037df88c05cdba0b134/api/src/main/java/org/apache/iceberg/expressions/StrictMetricsEvaluator.java#L418-L462)
## Validation
- `UV_CACHE_DIR=.cache/uv PYTHON_GIL=1 PYTHONPATH=. uv run pytest
tests/expressions/test_evaluator.py -k "mixed_nulls_and_matching_bounds
or mixed_nans_and_matching_bounds or all_nulls or all_nans or
strict_integer_not_in"`
- `UV_CACHE_DIR=.cache/uv PYTHON_GIL=1 PYTHONPATH=. uv run pytest
tests/expressions/test_evaluator.py`
- `UV_CACHE_DIR=.cache/uv PYTHON_GIL=1 PYTHONPATH=. uv run ruff check
pyiceberg/expressions/visitors.py tests/expressions/test_evaluator.py`
- `git diff --check`
---------
Co-authored-by: Kevin Liu <kevinjqliu@users.noreply.github.com>1 parent c66d8b5 commit d0a9b91
2 files changed
Lines changed: 47 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1668 | 1668 | | |
1669 | 1669 | | |
1670 | 1670 | | |
1671 | | - | |
| 1671 | + | |
| 1672 | + | |
| 1673 | + | |
| 1674 | + | |
| 1675 | + | |
1672 | 1676 | | |
1673 | 1677 | | |
1674 | 1678 | | |
| |||
1728 | 1732 | | |
1729 | 1733 | | |
1730 | 1734 | | |
1731 | | - | |
| 1735 | + | |
| 1736 | + | |
| 1737 | + | |
| 1738 | + | |
| 1739 | + | |
1732 | 1740 | | |
1733 | 1741 | | |
1734 | 1742 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1523 | 1523 | | |
1524 | 1524 | | |
1525 | 1525 | | |
1526 | | - | |
| 1526 | + | |
1527 | 1527 | | |
1528 | 1528 | | |
1529 | 1529 | | |
1530 | 1530 | | |
1531 | 1531 | | |
| 1532 | + | |
| 1533 | + | |
| 1534 | + | |
| 1535 | + | |
| 1536 | + | |
| 1537 | + | |
| 1538 | + | |
| 1539 | + | |
| 1540 | + | |
| 1541 | + | |
| 1542 | + | |
| 1543 | + | |
| 1544 | + | |
| 1545 | + | |
| 1546 | + | |
| 1547 | + | |
| 1548 | + | |
| 1549 | + | |
| 1550 | + | |
| 1551 | + | |
| 1552 | + | |
| 1553 | + | |
| 1554 | + | |
| 1555 | + | |
| 1556 | + | |
| 1557 | + | |
| 1558 | + | |
| 1559 | + | |
| 1560 | + | |
| 1561 | + | |
| 1562 | + | |
| 1563 | + | |
| 1564 | + | |
| 1565 | + | |
| 1566 | + | |
| 1567 | + | |
1532 | 1568 | | |
1533 | 1569 | | |
1534 | 1570 | | |
| |||
0 commit comments