[Bug Fix] Resolve dotted source paths in pushed-down Calcite scripts - #5724
Conversation
…h-project#5702) When a filter is pushed down as a Calcite script that reads a field from _source, the field is addressed by its flattened name (e.g. "log.user_agent") while _source stores object subfields nested. The lookup was a flat Map#get, so any object subfield resolved to null and the predicate silently matched nothing. Use SourceLookup#extractValue, which delegates to XContentMapValues and walks the nested maps, still falling back to a literal dotted key when the document has one. This is not limited to indices with conflicting field types: a plain text object subfield already resolves through _source and hit the same path. Mixed text/keyword types merge down to text without a keyword subfield, which routes more fields through _source and is how opensearch-project#5702 surfaced. Signed-off-by: Jialiang Liang <jiallian@amazon.com>
PR Reviewer Guide 🔍(Review updated until commit 7724f14)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to 7724f14
Previous suggestionsSuggestions up to commit 366b9a8
|
…oject#5702) The same _source lookup backs the aggregation and sort scripts, not just filters, and both produced results that looked valid while being wrong: a stats grouping key collapsed every document into one null bucket, and a sort key left rows in their original order. Assert the sort case with verifyDataRowsInOrder; verifyDataRows compares without regard to order and cannot observe an ordering defect. Signed-off-by: Jialiang Liang <jiallian@amazon.com>
|
Persistent review updated to latest commit 7724f14 |
Description
When a PPL query pushes work down as a Calcite script that reads a field from
_source, the field is addressed by its flattened name (e.g.log.user_agent), while_sourcestores object subfields nested ({"log": {"user_agent": ...}}). The lookup was a flatMap#get:So any object subfield resolved to
null. No error was raised — the query simply produced a wrong answer.What was actually wrong
All five pushed-down script types — filter, aggregation, string sort, number sort, and field — funnel through this one method via
CalciteScript→ScriptDataContext. Measured againstmain:where log.user_agent = 'requests/2.32.3'where upper(log.user_agent) = '...'stats count() by log.ua[[3, null]]— every document in one null bucket[[2,"aaa"],[1,"bbb"]]eval u = upper(log.ua) | sort u, id[[1,BBB],[2,AAA],[3,AAA]]— ordering not applied[[2,AAA],[3,AAA],[1,BBB]]The aggregation case is the most dangerous of the four: a filter returning zero rows is visibly empty, but a
stats ... bythat silently collapses every document into a singlenullbucket returns a result that looks entirely plausible.Root cause note
The issue hypothesised that
DeepMergeRulehandles nested fields differently from the fix in #5358. That is not the cause — the merge is correct for nested fields:TextKeywordConflictRuledoes apply to nested subfields throughDeepMergeRule, and the engine correctly switches toSource.SOURCEas a result. The explain output confirms the retrieval mode was chosen correctly:SOURCES=1isSource.SOURCE— doc_values were correctly avoided. The defect is one level further down, in how that source value is read.Scope is wider than mixed-type indices
A cross-index type conflict is not required. A single index whose object subfield is plain
textalready resolves through_sourceand hit the same path. Mixedtext/keywordtypes merge down to text-without-keyword-subfield, which routes more fields through_source— that is how #5702 surfaced, but it is not the precondition.Behaviour comparison against baseline
Edge cases were run on
mainand on this branch to isolate the change:enabled: falseobject["a", null, "b"]["a",null,"b"]["a",null,"b"](unchanged)nested-type field filterisnull(o.v)sort log.ua(doc_values path)stats sum(log.n)on an integer subfieldNo unintended behaviour changes; two further latent cases are fixed as a side effect.
Related Issues
Resolves #5702
Follow-up to #5358 / #4659
Testing
CalciteMixedFieldTypeIT— 5 new cases covering filter, script filter, the single-index no-conflict case,stats ... byon an object subfield, and sort on one. Reverting the one-line fix fails exactly these 5 and leaves the 4 pre-existing #4659 cases green.The sort case asserts with
verifyDataRowsInOrder;verifyDataRowscompares without regard to order and cannot observe an ordering defect.integ-test/src/yamlRestTest/.../issues/5702.yml— 2 new scenarios, mirroring4659.yml.CalciteMixedFieldTypeITis already registered inCalciteNoPushdownIT, so the new cases also run with pushdown disabled.integTestCalciteNoPushdownITyamlRestTestspotlessCheckCheck List
--signoffor-s.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
🤖 Generated with Claude Code