Skip to content

Fix #2601 parse single-leg findAndRerank sorts - #2647

Open
erichare wants to merge 3 commits into
fix/rerank-candidate-paginationfrom
feat/rerank-single-leg-sort-parsing
Open

erichare wants to merge 3 commits into
fix/rerank-candidate-paginationfrom
feat/rerank-single-leg-sort-parsing

Conversation

@erichare

Copy link
Copy Markdown
Contributor

What this PR does:

Parse the single-leg findAndRerank sorts. The sort clause now accepts exactly one top-level key: $hybrid, $vectorize, $vector or $lexical. The $hybrid forms parse as before.

  • {"$vectorize": "text"} is LegMode.VECTORIZE
  • {"$vector": [...]} and {"$vector": {"$binary": "..."}} are LegMode.VECTOR
  • {"$lexical": "text"} is LegMode.LEXICAL

Null and blank values are recorded as no value, the same as inside $hybrid. Two top-level keys fail when the sort is parsed. The record rejects a single-leg mode that carries a value for another mode.

The value parsing for $vectorize, $lexical and $vector was moved into two private functions in the deserializer, so the $hybrid object and the top-level keys use the same code. No duplicated parsing.

NOTE: this PR itself does not run single-leg sorts. The planner has no legs for these modes yet, so they still fail with UNSUPPORTED_FIND_AND_RERANK_SORT. Building the legs is #2602, and rerankCandidateLimit and field sorts are not in this PR.

NOTE: this PR is stacked on #2607, which is stacked on #2637. Merge those first.

Tests: 217 tests pass on Java 21, and fmt:check passes.

  • FindAndRerankSortClauseDeserializerTest: new cases for the three single-leg sorts, null and blank values, $binary vectors, two top-level keys, and wrong value types
  • FindAndRerankPlannerTest: single-leg modes still fail with UNSUPPORTED_FIND_AND_RERANK_SORT
  • FindAndRerankOperationBuilderBehaviorTest: the 75 request shapes for $hybrid are unchanged

Which issue(s) this PR fixes:

Refs #2601
Refs #2602

NOTE: this PR does not close #2601 or #2602. It is the parsing slice only.

Checklist

  • Changes manually tested
  • Automated Tests added/updated
  • Documentation added/updated
  • CLA Signed: DataStax CLA

@erichare
erichare requested a review from a team as a code owner October 15, 2026 17:22
Comment on lines +97 to +102
if (sortMatch.matched().size() != 1) {
throw new JsonMappingException(
jsonParser,
"sort clause must have exactly one of $hybrid, $vectorize, $vector, $lexical",
jsonParser.currentLocation());
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a user-visible error? If so, use specific API error

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 787722f: now throws SORT_CLAUSE_INVALID.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a user-visible error? What makes you believe this is the right exception? Why you decided to use JsonMappingException previously? Why did you decide to throw this error or do the validation inside the deserializer?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially treated conflicting keys as a JSON shape error, but SORT_CLAUSE_INVALID gives users a more specific error. The check belongs in the deserializer because it needs one top-level key to select the sort mode. Do you agree with keeping that check in the deserializer?

// top level has exactly one of $hybrid, $vectorize, $vector or $lexical
// { "sort" : { "$hybrid" : "i like cheese" } }
// { "sort" : { "$hybrid" : { "$vectorize" : "i like cheese", "$lexical" : "cows"} } }
// { "sort" : { "$hybrid" : { "$vector" : [1, 2, 3], "$lexical" : "cows"} } }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why delete this example in the comment?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restored in 787722f.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why delete this example in the comment? Does it become invalid?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example is still valid, and there was no behavior change that justified removing it. I have restored it.

CommandFeature feature)
throws JsonMappingException {
return switch (node) {
case null -> null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does {"sort": {"$lexical": null}} mean at the top level? Inside $hybrid a null skips that leg, but here it is the only leg. Where is that rejected, and is there a test for it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Records LEXICAL with no value; planner rejects it (UNSUPPORTED_FIND_AND_RERANK_SORT, #2602). Test added: failSingleLegModeWithNoValue.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you explain this? I don't really understand this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parser records a lexical sort with no text, and the test only covers its rejection because single-leg execution is not implemented yet. Are you OK with adding the null and blank checks in #2602 alongside that execution?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants