Jackie-Jiang opened a new pull request, #19072:
URL: https://github.com/apache/pinot/pull/19072

   ## Summary
   
   Adds an **opt-in, per-column** reload-time backfill that reconstructs a 
column's null value vector for segments that were created before null handling 
was enabled, by treating every stored value equal to the column's default null 
value as null. This lets operators enable null handling on a table and have `IS 
NULL` / null-aware queries work on already-ingested data without re-ingesting.
   
   The reconstruction mirrors how ingestion records nulls:
   - single-value: a doc is null when its stored value equals the column's 
default null value;
   - multi-value: a doc is null when its entry is a single-element array 
holding the default null value.
   
   ### Opt-in and safety
   
   The backfill is **lossy** — a genuine value that happens to equal the 
default null value is also marked null — so it is opt-in per column, via the 
null value vector index config:
   
   ```json
   "fieldConfigList": [
     { "name": "status", "indexes": { "null": { "backfill": true } } }
   ]
   ```
   
   - A new `NullValueVectorConfig` carries the `backfill` flag; its `enabled` 
state is still derived from null handling (column-based `isNullable` or the 
table-level `nullHandlingEnabled`), and the two are merged in 
`NullValueIndexType`'s deserializer.
   - Enable it only for columns whose default null value is a non-occurring 
sentinel (e.g. a dimension's `MIN_VALUE`), not for metric/boolean columns whose 
default is a common value like `0`.
   - `MAP`/complex types are rejected at table-config validation time 
(`NullValueIndexType.validate`), since the default (empty map) is an ordinary 
value and `OPEN_STRUCT`-backed maps have no single scannable parent forward 
index. A `TODO` is left to revisit if complex-type null handling matures.
   
   ### `nonNull` column-metadata flag
   
   A new `nonNull` column-metadata property records the "null handling enabled, 
but no null values" case. A bitmap file is written only when a column actually 
has nulls (unchanged from today); the no-null case is recorded via this flag 
instead. This keeps behavior **symmetric between segment creation and 
backfill** — no empty bitmap files — and makes the backfill **idempotent** (a 
flagged column is not re-scanned on subsequent reloads) while distinguishing a 
null-handled-but-empty column from one that was never null-handled.
   
   ### Backward / mixed-version compatibility
   
   - The metadata flag defaults to `false` and is additive; older segments are 
unaffected.
   - The feature is off unless a column explicitly opts in.
   - Rolling-upgrade note: once a column opts in (writes `indexes.null` to the 
table config), a node still running the pre-change code will fail to resolve 
that table's index configs (the old null-vector deserializer treats the config 
as an exclusive alternative and every column already gets a derived config). 
Enable `backfill` only after the whole cluster is upgraded; a rollback with the 
config still set will fail on that table.
   
   ### Tests
   
   - `NullValueVectorHandlerTest` — backfill across SV/MV and dict/raw scalar 
types, selectivity (an un-opted column holding the sentinel is left untouched), 
the creation-time `nonNull` flag write, and idempotency on reload.
   - `NullValueIndexTypeTest` — config resolution (`enabled` derived from null 
handling) and `validate` rejecting `MAP` opt-in.
   - `TableConfigUtilsTest` — end-to-end validation: scalar opt-in passes, 
`MAP` opt-in is rejected.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to