Repository navigation
Description
Current behavior
-
Whatever the request is,
build()always creates two slots: one for a vector read and one for a lexical (BM25) read ([FindAndRerankOperationBuilder.java#L89-L102]()).data-api/src/main/java/io/stargate/sgv2/jsonapi/service/resolver/FindAndRerankOperationBuilder.java
Lines 89 to 102 in 02d0423
// Step 1 - we need a reranking task and the deferrable actions to do the intermediate reads // Making the deferrables here so we can associate them with read types that will fill them var deferredVectorRead = new RerankingTask.DeferredCommandWithSource( Rank.RankSource.VECTOR, new DeferredCommandResult()); var deferredBM25Read = new RerankingTask.DeferredCommandWithSource( Rank.RankSource.BM25, new DeferredCommandResult()); var rerankTasksAndDeferrables = rerankTasks(List.of(deferredBM25Read, deferredVectorRead)); // Step 2 - we need to read the data from the collections, we are wrapping the old collections // in the new tasks so we do not change the collection code var readTasksAndDeferrables = readTasks(deferredVectorRead, deferredBM25Read); -
When the lexical read isn't needed, the slot is filled with a fake empty result ([#L344](
), [#L357](data-api/src/main/java/io/stargate/sgv2/jsonapi/service/resolver/FindAndRerankOperationBuilder.java
Line 344 in 02d0423
deferredAction.setEmptyMultiDocumentResponse(); )).data-api/src/main/java/io/stargate/sgv2/jsonapi/service/resolver/FindAndRerankOperationBuilder.java
Line 357 in 02d0423
deferredAction.setEmptyMultiDocumentResponse(); -
The vector read has no "not needed" option:
- it always runs ([#L333]());
data-api/src/main/java/io/stargate/sgv2/jsonapi/service/resolver/FindAndRerankOperationBuilder.java
Line 333 in 02d0423
var vectorReadAndDeferrables = buildVectorRead(deferredVectorReadAction); - it throws when there is no vector ([#L410]()).
data-api/src/main/java/io/stargate/sgv2/jsonapi/service/resolver/FindAndRerankOperationBuilder.java
Line 410 in 02d0423
throw new IllegalArgumentException("buildVectorRead() - no vector or vectorize");
As a result,
{"$hybrid": {"$lexical": "..."}}returns a 500 even whenrerankQueryandrerankOnare set ([stargate/data-api#2577](IllegalArgumentException / UNEXPECTED_SERVER_ERROR in FindAndRerank when omitting $vectorize in $hybrid #2577)). - it always runs ([#L333](
Why fix it
- A single lexical leg can't run, because the vector read would throw.
- The filter leg has no slot at all: it is neither a vector read nor a lexical read.
- Patching would also work: make the vector slot optional and add a third slot for the filter leg. But with 4 new modes, every rule would need
ifbranches in 5–6 places of a 495-line file, and there would be even more fake empty results. The rules in question:- which collection features are required;
- how many documents to read;
- the default rerank query and passage;
- how to build each read.
Activity
Hazel-Datastax commentedon Oct 6, 2026
After implementing this, a
$hybridkeyword must have at least one leg, either vector ($vector/$vectorize) or lexical ($lexical). If neither is present, return a request error.The use of
$hybridin the sort clause does not guarantee that multiple legs will be run when the command is executed. We can only say that a Multi Leg findAndRerank may have more than one leg, not that it must have more than one.