Reject range index on ingestion-aggregated no-dictionary columns - #19111
Reject range index on ingestion-aggregated no-dictionary columns#19111raghavyadav01 wants to merge 2 commits into
Conversation
Ingestion-time metrics aggregation (aggregationConfigs / aggregateMetrics) forces its aggregated metric columns to be no-dictionary, and their min/max values are never tracked when the consuming segment is committed. The BitSliced range index (version 2) creator reads min/max for a single-value no-dictionary column, so this combination throws a NullPointerException for INT/LONG columns (and silently builds a degenerate index for FLOAT/DOUBLE), leaving segments unable to commit. Add validation in RangeIndexType.validate() to reject a version-2 range index on such columns upfront, and add a defense-in-depth guard in BitSlicedRangeIndexCreator so the raw-column path fails with a clear, actionable message instead of a NullPointerException on direct/programmatic creation and segment reload.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #19111 +/- ##
============================================
+ Coverage 65.50% 65.57% +0.06%
- Complexity 1421 1423 +2
============================================
Files 3430 3432 +2
Lines 218000 218392 +392
Branches 34642 34749 +107
============================================
+ Hits 142799 143208 +409
+ Misses 63641 63614 -27
- Partials 11560 11570 +10
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The ingestion-aggregation range-index check dereferenced tableConfig, but direct/programmatic index-creation paths (e.g. OpenStructColumnSplitter) call validate() with a null tableConfig, causing a NullPointerException. Skip the check when no table config is available.
Jackie-Jiang
left a comment
There was a problem hiding this comment.
This is not the correct fix. We should allow building range index, and scan the column to figure out min/max value when they are unavailable.
|
Thanks @Jackie-Jiang . I am thinking to compute min/max on demand in MutableNoDictColumnStatistics — when the mutable segment reports null (aggregated columns skip min/max tracking since the value mutates), scan the sealed forward index once (same pass isSorted() already does), before the BitSliced creator is constructed. This adds one extra O(numDocs) scan per such column at seal time. Will this be OK? |
Yes. That is the overhead we need to pay in order to add range index. We should also check how RangeIndexHandler handles null min/max value. |
Problem
Configuring a range index on an ingestion-aggregated metric column causes segments to fail to commit.
Ingestion-time metrics aggregation (
aggregationConfigs, or the legacyaggregateMetricsflag) forces its aggregated metric columns to be no-dictionary, and their min/max values are never tracked while the consuming segment is being built. The BitSliced range index (version 2) creator reads min/max for a single-value no-dictionary column:For INT/LONG columns this throws a
NullPointerExceptionat segment build time (((Number) minValue).longValue()); for FLOAT/DOUBLE it silently builds a degenerate index over a wrong value domain. Either way, the affected real-time segments can never commit.Fix
RangeIndexType.validate()— reject a version-2 range index on a single-value, no-dictionary, ingestion-aggregated column upfront, with an actionable message. Scoped toREALTIMEtables, since ingestion aggregation only materializes on consuming segments (the offline path computes min/max normally and is unaffected). Version-1 range index does not read min/max and is left allowed.BitSlicedRangeIndexCreator— defense-in-depth: the raw-column constructor now fails with a clearIllegalStateExceptionwhen min/max are absent, instead of a bareNullPointerException. This also covers direct/programmatic creation and segment reload paths that config validation does not gate.Testing
IndexCombinationValidationTest— both aggregation paths are rejected for real-time tables; version-1 range index passes; a non-aggregated no-dictionary numeric column still supports the range index; the same config on an offline table is allowed.BitSlicedIndexCreatorTest— added a test that the raw-column constructor fails loudly on absent min/max.Release Notes
Configuring a version-2 (BitSliced) range index on an ingestion-aggregated no-dictionary column is now rejected at table-config validation time. Use range index version 1, or remove the range index on such columns.