You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by "xiangfu0 (via GitHub)" <gi...@apache.org> on 2026/08/13 08:22:30 UTC

[PR] Allow non-immutable ingestion transforms for offline tables [pinot]

xiangfu0 opened a new pull request, #19244:
URL: https://github.com/apache/pinot/pull/19244

   ## Summary
   
   Allow table-level ingestion transforms on `OFFLINE` tables to use registered scalar functions from any volatility category. New or changed `REALTIME` table ingestion transforms continue to require `IMMUTABLE` functions.
   
   The rest of transform validation remains in place, including expression parsing, destination-column validation, self-reference checks, and the Groovy policy. Schema-level transforms and `postPartialUpsertTransformConfigs` also retain their existing volatility checks.
   
   ## Motivation
   
   An offline upsert table needs a comparison value to choose the latest row for each primary key. Daily Parquet inputs can contain only a subset of the key space and may not contain a physical timestamp or row-version column. A value that is fixed for every ingestion run cannot order updates across those daily drops.
   
   This change lets an offline table declare a generated comparison column in the Pinot schema and populate it with `now()` or another explicitly selected non-immutable transform, without first rewriting the Parquet files. The policy change is scoped to finite, task-driven `OFFLINE` ingestion and is not applied to `REALTIME` ingestion.
   
   ## Usage
   
   Declare the generated comparison column in the Pinot schema even though it is absent from the source Parquet file:
   
   ```json
   {
     "schemaName": "dailyDimension",
     "dimensionFieldSpecs": [
       {
         "name": "id",
         "dataType": "STRING"
       }
     ],
     "metricFieldSpecs": [
       {
         "name": "ingestionTime",
         "dataType": "LONG"
       }
     ],
     "primaryKeyColumns": ["id"]
   }
   ```
   
   Configure full upsert and populate the comparison column during offline ingestion:
   
   ```json
   {
     "tableName": "dailyDimension",
     "tableType": "OFFLINE",
     "segmentsConfig": {
       "segmentPushType": "APPEND",
       "replication": "1"
     },
     "routing": {
       "instanceSelectorType": "strictReplicaGroup"
     },
     "tableIndexConfig": {
       "segmentPartitionConfig": {
         "columnPartitionMap": {
           "id": {
             "functionName": "Murmur",
             "numPartitions": 1
           }
         }
       }
     },
     "upsertConfig": {
       "mode": "FULL",
       "comparisonColumns": ["ingestionTime"]
     },
     "ingestionConfig": {
       "transformConfigs": [
         {
           "columnName": "ingestionTime",
           "transformFunction": "now()"
         }
       ]
     }
   }
   ```
   
   The Parquet rows must contain `id`, but they do not need to contain `ingestionTime`. Offline upsert still requires primary-key partitioning and strict-replica-group routing.
   
   ## Compatibility
   
   - `OFFLINE` table-level ingestion transforms accept `IMMUTABLE`, `STABLE`, and `VOLATILE` functions.
   - New or changed `REALTIME` table-level ingestion transforms continue to reject non-immutable functions.
   - An identical non-immutable transform already stored on a `REALTIME` table remains grandfathered so unrelated config updates are not blocked.
   - Schema-level and post-partial-upsert transforms continue to require immutable functions.
   - Unknown functions, invalid expressions, and disabled Groovy transforms remain rejected.
   
   ## Validation
   
   - `TableConfigUtilsTest`: 78 tests passed.
   - `SchemaUtilsTest`: 15 tests passed.
   - `PinotTableRestletResourceTest` and `TableConfigsRestletResourceTest`: 45 tests passed.
   - Spotless, Checkstyle, license formatting/checking, and `git diff --check` passed for all affected modules.
   
   ## Draft status and known correctness gap
   
   This PR changes validation policy only; it does not make volatile functions batch-stable. Row-based offline segment generation currently evaluates transforms once while gathering statistics and again while indexing after rewinding the input. A function such as `now()` or `rand()` can therefore produce different values between the two passes. Dictionary-encoded columns can resolve a second-pass value that was absent from the first-pass dictionary to an incorrect dictionary ID, while no-dictionary columns can store values inconsistent with first-pass min/max metadata. Either case can select the wrong offline-upsert winner.
   
   Values can also differ across records, retries, rebuilds, and backfills, and registered functions that depend on unavailable runtime context can validate but fail during batch evaluation.
   
   This should remain a draft discussion PR until segment generation either materializes and reuses transformed rows or provides a defined build-stable evaluation mode, with an end-to-end segment-generation/readback regression test.
   


-- 
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: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Allow non-immutable ingestion transforms for offline tables [pinot]

Posted by "xiangfu0 (via GitHub)" <gi...@apache.org>.
xiangfu0 commented on PR #19244:
URL: https://github.com/apache/pinot/pull/19244#issuecomment-5287082921

   Documentation follow-up: https://github.com/pinot-contrib/pinot-docs/pull/983 (merged).


-- 
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: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Allow non-immutable ingestion transforms for offline tables [pinot]

Posted by "xiangfu0 (via GitHub)" <gi...@apache.org>.
xiangfu0 commented on code in PR #19244:
URL: https://github.com/apache/pinot/pull/19244#discussion_r3774612129


##########
pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/TableConfigUtils.java:
##########
@@ -620,7 +621,9 @@ static void validateIngestionConfig(TableConfig tableConfig, Schema schema,
                   + columnName + "'");
         }
         try {
-          validateIngestionTransformFunctionVolatility(transformConfig, existingTransformConfigs);
+          if (tableConfig.getTableType() == TableType.REALTIME) {
+            validateIngestionTransformFunctionVolatility(transformConfig, existingTransformConfigs);
+          }

Review Comment:
   Addressed in [`bd446c3539`](https://github.com/apache/pinot/pull/19244/commits/bd446c3539269d93f7dc6ab6ed9281aa0ce2364f).
   
   Row-major OFFLINE generation now detects non-immutable filter, table-transform, and legacy schema-transform functions. During statistics collection it writes each fully transformed output row to a temporary disk spool, then replays those exact rows into the index creator without invoking the transform pipeline a second time. A per-row offset sidecar bounds decoding and validates row counts/boundaries; spool failures abort the build and both temporary files are cleaned up.
   
   The end-to-end regression suite covers dictionary-encoded and raw `rand()`, `now()` on a `LONG` column, metadata/cardinality readback, and one source read for volatile pipelines versus two for immutable pipelines. The spool suite covers the physical type matrix, complex/null values, row framing, corrupt offsets, and failure cleanup. The focused JDK 25 run passed 12/12 tests, and the affected-module Spotless, Checkstyle, and license gates all pass.
   
   I also added ingestion eligibility metadata so query-context-only functions such as `reqId()` are rejected instead of validating and failing at runtime. The PR remains draft while the ordering semantics, temporary-disk cost, and rolling-upgrade requirement are reviewed.
   



-- 
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: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Allow non-immutable ingestion transforms for offline tables [pinot]

Posted by "codecov-commenter (via GitHub)" <gi...@apache.org>.
codecov-commenter commented on PR #19244:
URL: https://github.com/apache/pinot/pull/19244#issuecomment-5278177942

   ## [Codecov](https://app.codecov.io/gh/apache/pinot/pull/19244?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) Report
   :white_check_mark: All modified and coverable lines are covered by tests.
   :white_check_mark: Project coverage is 100.00%. Comparing base ([`cb89c0e`](https://app.codecov.io/gh/apache/pinot/commit/cb89c0e4c566005059d3b6b97ad306f2e159ae98?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)) to head ([`cb44bdc`](https://app.codecov.io/gh/apache/pinot/commit/cb44bdce064d40097f19c9df2ca6a55d24334423?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)).
   
   <details><summary>Additional details and impacted files</summary>
   
   
   
   ```diff
   @@              Coverage Diff               @@
   ##             master    #19244       +/-   ##
   ==============================================
   + Coverage     57.71%   100.00%   +42.28%     
   - Complexity        1         6        +5     
   ==============================================
     Files          2659         3     -2656     
     Lines        159144         6   -159138     
     Branches      26099         0    -26099     
   ==============================================
   - Hits          91855         6    -91849     
   + Misses        59489         0    -59489     
   + Partials       7800         0     -7800     
   ```
   
   | [Flag](https://app.codecov.io/gh/apache/pinot/pull/19244/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | Coverage Δ | |
   |---|---|---|
   | [integration](https://app.codecov.io/gh/apache/pinot/pull/19244/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `100.00% <ø> (+100.00%)` | :arrow_up: |
   | [integration1](https://app.codecov.io/gh/apache/pinot/pull/19244/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `100.00% <ø> (?)` | |
   | [integration2](https://app.codecov.io/gh/apache/pinot/pull/19244/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `?` | |
   | [java-25](https://app.codecov.io/gh/apache/pinot/pull/19244/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `100.00% <ø> (+42.28%)` | :arrow_up: |
   | [lane-a](https://app.codecov.io/gh/apache/pinot/pull/19244/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `100.00% <ø> (+100.00%)` | :arrow_up: |
   | [lane-b](https://app.codecov.io/gh/apache/pinot/pull/19244/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `0.00% <ø> (ø)` | |
   | [temurin](https://app.codecov.io/gh/apache/pinot/pull/19244/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `100.00% <ø> (+42.28%)` | :arrow_up: |
   | [unittests](https://app.codecov.io/gh/apache/pinot/pull/19244/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `?` | |
   | [unittests1](https://app.codecov.io/gh/apache/pinot/pull/19244/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `?` | |
   
   Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#carryforward-flags-in-the-pull-request-comment) to find out more.
   </details>
   
   [:umbrella: View full report in Codecov by Harness](https://app.codecov.io/gh/apache/pinot/pull/19244?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).   
   :loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).
   <details><summary> :rocket: New features to boost your workflow: </summary>
   
   - :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
   </details>


-- 
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: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Allow non-immutable ingestion transforms for offline tables [pinot]

Posted by "xiangfu0 (via GitHub)" <gi...@apache.org>.
xiangfu0 commented on code in PR #19244:
URL: https://github.com/apache/pinot/pull/19244#discussion_r3774648934


##########
pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/TableConfigUtils.java:
##########
@@ -620,7 +621,9 @@ static void validateIngestionConfig(TableConfig tableConfig, Schema schema,
                   + columnName + "'");
         }
         try {
-          validateIngestionTransformFunctionVolatility(transformConfig, existingTransformConfigs);
+          if (tableConfig.getTableType() == TableType.REALTIME) {
+            validateIngestionTransformFunctionVolatility(transformConfig, existingTransformConfigs);
+          }

Review Comment:
   Follow-up hardening landed in [`52a541abe5`](https://github.com/apache/pinot/pull/19244/commits/52a541abe5301ac708642bda43361a5bd55bc54a). Data and offset spool files are now deleted independently so one cleanup failure cannot leak the other, cleanup can be retried, and direct path construction is package-local so production callers always use unique temporary files. The combined JDK 25 spool and segment-generation regression run now passes 13/13 tests.



-- 
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: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Allow non-immutable ingestion transforms for offline tables [pinot]

Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #19244:
URL: https://github.com/apache/pinot/pull/19244#discussion_r3773696484


##########
pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/TableConfigUtils.java:
##########
@@ -620,7 +621,9 @@ static void validateIngestionConfig(TableConfig tableConfig, Schema schema,
                   + columnName + "'");
         }
         try {
-          validateIngestionTransformFunctionVolatility(transformConfig, existingTransformConfigs);
+          if (tableConfig.getTableType() == TableType.REALTIME) {
+            validateIngestionTransformFunctionVolatility(transformConfig, existingTransformConfigs);
+          }

Review Comment:
   Allowing non-IMMUTABLE transform functions for OFFLINE tables is risky with the current segment-generation flow because transforms are evaluated during stats collection and then evaluated again after `RecordReader.rewind()` during indexing. VOLATILE/STABLE functions (e.g., `now()`, `rand()`) can therefore yield different values between passes, leading to inconsistent dictionary/min-max metadata vs indexed values and potentially incorrect offline-upsert outcomes.
   
   Consider gating non-IMMUTABLE OFFLINE transforms behind an explicit opt-in/feature flag, or rejecting VOLATILE until segment generation can materialize/reuse transformed rows (or otherwise guarantee a build-stable evaluation mode).



-- 
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: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Allow non-immutable ingestion transforms for offline tables [pinot]

Posted by "xiangfu0 (via GitHub)" <gi...@apache.org>.
xiangfu0 commented on code in PR #19244:
URL: https://github.com/apache/pinot/pull/19244#discussion_r3773822939


##########
pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/TableConfigUtils.java:
##########
@@ -620,7 +621,9 @@ static void validateIngestionConfig(TableConfig tableConfig, Schema schema,
                   + columnName + "'");
         }
         try {
-          validateIngestionTransformFunctionVolatility(transformConfig, existingTransformConfigs);
+          if (tableConfig.getTableType() == TableType.REALTIME) {
+            validateIngestionTransformFunctionVolatility(transformConfig, existingTransformConfigs);
+          }

Review Comment:
   Agreed—this is a real merge blocker, not only a theoretical risk. I reproduced it on the current branch with a 20-row OFFLINE segment using `r = rand()`: validation and segment creation succeeded, but readback returned 20 rows with only one distinct value because second-pass values missing from the first-pass dictionary resolved to dictionary ID 0.
   
   I have converted the PR back to draft. An opt-in flag alone would still permit silently incorrect segments, so I am leaving this thread unresolved until row-based segment generation evaluates each transform once per input row per build attempt and reuses/materializes that exact row for both statistics and indexing. The fix also needs end-to-end build/readback coverage for dictionary and no-dictionary outputs, asserting stored values, cardinality, and min/max metadata.



-- 
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: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org


Re: [PR] Allow non-immutable ingestion transforms for offline tables [pinot]

Posted by "xiangfu0 (via GitHub)" <gi...@apache.org>.
xiangfu0 merged PR #19244:
URL: https://github.com/apache/pinot/pull/19244


-- 
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: commits-unsubscribe@pinot.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org