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

   ## Summary
   
   Follow-up to #18972 and @Jackie-Jiang's request to extend the transform 
function.
   
   This adds query-time and ingestion-transform equivalents of the new 
streaming JsonPath scalar functions:
   
   ```text
   jsonExtractScalarFast(jsonField, jsonPath, resultsType[, defaultValue])
   jsonExtractScalarFirstMatch(jsonField, jsonPath, resultsType[, defaultValue])
   ```
   
   - `jsonExtractScalarFast` streams simple paths and scans the full root value.
   - `jsonExtractScalarFirstMatch` stops as soon as the addressed value is 
found.
   - Complex paths, unsupported roots, and fast-extractor failures fall back to 
the existing Jayway implementation.
   - The existing `jsonExtractScalar` execution path remains Jayway-based for 
compatibility.
   - Both `STRING` and raw JSON `BYTES` inputs are supported.
   - Planner registration, operand validation, return-type inference, 
function-registry snapshots, and both query engines are covered.
   - Adds the missing multi-path `byte[]` extractor overload needed by the 
transform path.
   
   ## User guide
   
   ### Choosing a function
   
   | Function | Use when | Duplicate keys | Malformed content after the match |
   | --- | --- | --- | --- |
   | `jsonExtractScalar` | Existing behavior is required | Last value wins | 
Rejected |
   | `jsonExtractScalarFast` | You want streaming extraction with 
Jayway-compatible ordinary-input behavior | Last value wins | Rejected |
   | `jsonExtractScalarFirstMatch` | Input is known to be well-formed and 
duplicate-free, and early exit is useful | First non-null value wins | Not 
validated |
   
   The fast path supports simple linear paths: `$` followed by `.key`, 
`['key']`, or `[index]`. Wildcards, recursive descent, filters, unions, slices, 
negative indices, and other complex paths automatically use Jayway.
   
   As documented for the extractor introduced in #18972, `Fast` may avoid 
Jayway materialization failures in an unaddressed subtree, such as an 
over-limit string or pathological `BigDecimal` exponent. It does not return a 
different addressed value.
   
   ### Arguments and result types
   
   - `jsonField` must be a single-value `STRING` or `BYTES` column or transform 
expression.
   - `jsonPath` and `resultsType` must be string literals.
   - `defaultValue`, when supplied, may be any literal.
   - Without a default, an unresolved scalar row throws; an unresolved array 
becomes an empty array. Null elements inside a resolved array still require a 
default.
   
   Supported scalar result types:
   
   ```text
   INT, LONG, FLOAT, DOUBLE, BIG_DECIMAL, BOOLEAN, TIMESTAMP,
   STRING, JSON, BYTES
   ```
   
   Supported array result types:
   
   ```text
   INT_ARRAY, LONG_ARRAY, FLOAT_ARRAY, DOUBLE_ARRAY,
   BIG_DECIMAL_ARRAY, BOOLEAN_ARRAY, TIMESTAMP_ARRAY, STRING_ARRAY
   ```
   
   Additional conversion notes:
   
   - `BOOLEAN` accepts booleans, non-zero numbers, and Pinot boolean strings.
   - `TIMESTAMP` accepts epoch milliseconds or strings supported by Pinot 
timestamp conversion.
   - `STRING` preserves strings and serializes other JSON values.
   - `JSON` is exposed to SQL as serialized `VARCHAR`.
   - `BYTES` decodes a Base64-encoded JSON string.
   - `BIG_DECIMAL` extraction preserves decimal precision.
   
   Multi-stage queries support every listed type except `BIG_DECIMAL_ARRAY`; 
the planner currently lowers decimal arrays to `DOUBLE_ARRAY`. Use the 
single-stage engine when decimal-array precision matters.
   
   ## Sample queries
   
   ```sql
   SELECT
     jsonExtractScalarFast(payload, '$.user.id', 'LONG', -1) AS user_id,
     jsonExtractScalarFirstMatch(
       payload,
       '$.service.name',
       'STRING',
       'unknown'
     ) AS service_name,
     jsonExtractScalarFast(payload, '$.tags', 'STRING_ARRAY') AS tags
   FROM events
   LIMIT 10;
   ```
   
   A `BYTES` column containing the raw JSON document works the same way:
   
   ```sql
   SELECT
     jsonExtractScalarFast(payloadBytes, '$.amount', 'BIG_DECIMAL', 0) AS amount
   FROM events
   LIMIT 10;
   ```
   
   The functions can also be used in ingestion transforms:
   
   ```json
   {
     "ingestionConfig": {
       "transformConfigs": [
         {
           "columnName": "userId",
           "transformFunction": "jsonExtractScalarFast(payload, '$.user.id', 
'LONG', -1)"
         },
         {
           "columnName": "serviceName",
           "transformFunction": "jsonExtractScalarFirstMatch(payload, 
'$.service.name', 'STRING', 'unknown')"
         }
       ]
     }
   }
   ```
   
   ## Testing
   
   Passed on the rebased commit:
   
   - `FastJsonPathExtractorTest` — 488 tests, including the new multi-path 
`byte[]` overload.
   - `JsonExtractScalarTransformFunctionTest` — 199 tests across all three 
modes, scalar/array types, coercion, defaults, complex-path fallback, 
`STRING`/`BYTES` input, Base64 `BYTES` output, duplicate keys, and malformed 
tails.
   - `FunctionRegistryTest` — 4 tests.
   - `QueryCompilationTest` — 221 tests, including planner typing and invalid 
non-literal operands.
   - `JsonPathTest` — 48 integration tests on both query engines with `STRING` 
and `BYTES` JSON columns.
   - Affected-module `test-compile` with `-Xlint:all`.
   - `spotless:apply`, `checkstyle:check`, `license:format`, and 
`license:check` for all affected modules.
   
   The `UdfTest#failWhenAllFunctionsYamlNotUpdated` snapshot comparison is 
currently blocked on upstream `master` before reaching its assertion: `NotUdf` 
reflects `LogicalFunctions.not(boolean)`, while the current method signature is 
`not(Boolean)`. The expected snapshot is updated here with the two transform 
registrations and the six scalar registrations merged in #18972.
   


-- 
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