Add Rust UDFs for json, json_object, json_array - #22130
Conversation
PR Reviewer Guide 🔍(Review updated until commit 9765d6f)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to 9765d6f Explore these optional code suggestions:
Previous suggestionsSuggestions up to commit 4abefbe
Suggestions up to commit a0b559c
|
|
❌ Gradle check result for a0b559c: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
Wires PPL json_valid through the analytics-engine route (PPL -> Calcite -> Substrait -> DataFusion): ScalarFunction.JSON_VALID enum, JsonValidAdapter (rewrites Calcite IS_JSON_VALUE -> local json_valid op), project + filter op registration, substrait FunctionMapping, yaml signature, and the Rust UDF. json_valid is registered as a FILTER op (not just PROJECT) so it works as a WHERE predicate (e.g. `where json_valid(col)` / `where not json_valid(col)`), same shape as cidrmatch. Semantics match the legacy SQL-plugin JsonUtils.isValidJson (Jackson readTree): malformed -> false, NULL -> NULL, and empty/whitespace -> true (Jackson returns MissingNode without throwing; serde rejects empty input, so is_valid_json special-cases it to preserve parity with the JsonFunctionsIT fixture). Complements opensearch-project#22130 (json/json_object/json_array); json_valid is independent. Rust unit tests 10/10, Java adapter tests 9/9. Signed-off-by: Eric Wei <mengwei.eric@gmail.com>
Wires PPL json_valid through the analytics-engine route (PPL -> Calcite -> Substrait -> DataFusion): ScalarFunction.JSON_VALID enum, JsonValidAdapter (rewrites Calcite IS_JSON_VALUE -> local json_valid op), project + filter op registration, substrait FunctionMapping, yaml signature, and the Rust UDF. json_valid is registered as a FILTER op (not just PROJECT) so it works as a WHERE predicate (e.g. `where json_valid(col)` / `where not json_valid(col)`), same shape as cidrmatch. Semantics match the legacy SQL-plugin JsonUtils.isValidJson (Jackson readTree): malformed -> false, NULL -> NULL, and empty/whitespace -> true (Jackson returns MissingNode without throwing; serde rejects empty input, so is_valid_json special-cases it to preserve parity with the JsonFunctionsIT fixture). Complements opensearch-project#22130 (json/json_object/json_array); json_valid is independent. Rust unit tests 10/10, Java adapter tests 9/9. Signed-off-by: Eric Wei <mengwei.eric@gmail.com>
…22139) Wires PPL json_valid through the analytics-engine route (PPL -> Calcite -> Substrait -> DataFusion): ScalarFunction.JSON_VALID enum, JsonValidAdapter (rewrites Calcite IS_JSON_VALUE -> local json_valid op), project + filter op registration, substrait FunctionMapping, yaml signature, and the Rust UDF. json_valid is registered as a FILTER op (not just PROJECT) so it works as a WHERE predicate (e.g. `where json_valid(col)` / `where not json_valid(col)`), same shape as cidrmatch. Semantics match the legacy SQL-plugin JsonUtils.isValidJson (Jackson readTree): malformed -> false, NULL -> NULL, and empty/whitespace -> true (Jackson returns MissingNode without throwing; serde rejects empty input, so is_valid_json special-cases it to preserve parity with the JsonFunctionsIT fixture). Complements #22130 (json/json_object/json_array); json_valid is independent. Rust unit tests 10/10, Java adapter tests 9/9. Signed-off-by: Eric Wei <mengwei.eric@gmail.com>
DataFusion's stdlib has no JSON constructors, so PPL queries calling json(), json_object(), or json_array() failed with "No backend supports scalar function [JSON_OBJECT] among [datafusion]" on parquet-backed indices. Add three Rust UDFs and wire them through the ScalarFunction enum, JsonFunctionAdapters, the backend project-ops registry, ADDITIONAL_SCALAR_SIGS, and opensearch_scalar_functions.yaml. The json_object / json_array adapters strip Calcite's leading SqlJsonConstructorNullClause flag and prepend a per-value type-tag (n / b / j / s) so the Rust UDF can preserve the original Calcite type when emitting JSON — numerics unquoted, booleans unquoted, nested-JSON results quoted-and-escaped, plain strings quoted. Tests: 15 new Rust unit tests (5 per UDF) covering happy path, NULL propagation, arity, type-tag dispatch; 3 new Java adapter tests in JsonFunctionAdaptersTests; new sandbox QA IT JsonBuiltinsIT covering the json / json_object / json_array query shapes against the calcs dataset. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
a0b559c to
4abefbe
Compare
|
Persistent review updated to latest commit 4abefbe |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #22130 +/- ##
============================================
+ Coverage 73.33% 73.45% +0.11%
- Complexity 75798 75939 +141
============================================
Files 6070 6070
Lines 344610 344610
Branches 49576 49576
============================================
+ Hits 252734 253117 +383
+ Misses 71769 71329 -440
- Partials 20107 20164 +57 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
PR Code Analyzer ❗AI-powered 'Code-Diff-Analyzer' found issues on commit 9765d6f.
The table above displays the top 10 most important findings. Pull Requests Author(s): Please update your Pull Request according to the report above. Repository Maintainer(s): You can Thanks. |
|
Persistent review updated to latest commit 9765d6f |
…pensearch-project#22139) Wires PPL json_valid through the analytics-engine route (PPL -> Calcite -> Substrait -> DataFusion): ScalarFunction.JSON_VALID enum, JsonValidAdapter (rewrites Calcite IS_JSON_VALUE -> local json_valid op), project + filter op registration, substrait FunctionMapping, yaml signature, and the Rust UDF. json_valid is registered as a FILTER op (not just PROJECT) so it works as a WHERE predicate (e.g. `where json_valid(col)` / `where not json_valid(col)`), same shape as cidrmatch. Semantics match the legacy SQL-plugin JsonUtils.isValidJson (Jackson readTree): malformed -> false, NULL -> NULL, and empty/whitespace -> true (Jackson returns MissingNode without throwing; serde rejects empty input, so is_valid_json special-cases it to preserve parity with the JsonFunctionsIT fixture). Complements opensearch-project#22130 (json/json_object/json_array); json_valid is independent. Rust unit tests 10/10, Java adapter tests 9/9. Signed-off-by: Eric Wei <mengwei.eric@gmail.com>
Description
DataFusion's stdlib has no JSON constructors, so PPL queries calling
json(),json_object(), orjson_array()on parquet-backed indices failed with:This PR adds three custom Rust UDFs (
json/json_object/json_array) and wires them through the full chain —ScalarFunctionenum,JsonFunctionAdapters, the backend project-ops registry,ADDITIONAL_SCALAR_SIGS, and the substrait extension yaml.Semantics
json(s)— round-trips parse a JSON string and returns the canonical re-serialisation. NULL on malformed input or NULL operand (matches PPL legacyJsonFunctionImpl.eval).json_object(k1, v1, k2, v2, ...)— variadic key/value pairs → JSON-object literal. Values keep their original Calcite type when emitted: numerics unquoted, booleans unquoted, nested JSON-builtin results quoted-and-escaped, plain strings JSON-quoted.json_array(v1, v2, ...)— variadic scalars → JSON-array literal. Same per-value type fidelity asjson_object.The
json_object/json_arrayadapters strip Calcite's leadingSqlJsonConstructorNullClauseflag and prepend a per-value type-tag (n/b/j/s) so the Rust UDF can recover the original type when emitting JSON.Query shapes now supported
Tests
udf/json.rs,udf/json_object.rs,udf/json_array.rs— happy path, NULL propagation, arity guards, per-tag dispatch.JsonFunctionAdaptersTests— flag stripping, type-tag insertion for numeric/string values, operator-identity preservation.JsonBuiltinsITover the sharedcalcsdataset covers the five primary query shapes (valid + invalidjson, single-pair / nestedjson_object, heterogeneous-numeric / stringjson_array) end-to-end against a parquet-backed index.PPL Calcite tests in the SQL plugin unblocked
CalcitePPLJsonBuiltinFunctionIT.testJsonCalcitePPLJsonBuiltinFunctionIT.testJsonAppendCalcitePPLJsonBuiltinFunctionIT.testJsonExtend(
testJsonObjectandtestJsonArrayin the same class were also failing for the same root cause and now pass.)Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.