feat: add BM25Operator.AndCross for cross-property keyword AND (Weaviate 1.38.8+) - #365
Conversation
There was a problem hiding this comment.
Orca Security Scan Summary
| Status | Check | Issues by priority | |
|---|---|---|---|
| Infrastructure as Code | View in Orca | ||
| SAST | View in Orca | ||
| Secrets | View in Orca | ||
| Vulnerabilities | View in Orca |
Summary - Weaviate C# Client CoverageSummary
CoverageWeaviate.Client - 49.7%
Weaviate.Client.Analyzers - 0%
Weaviate.Client.VectorData - 50.3%
|
There was a problem hiding this comment.
Pull request overview
Adds cross-property BM25 AND support across gRPC search paths with version validation and tests.
Changes:
- Adds
BM25Operator.AndCrossand protobuf mapping. - Adds server-version guards for BM25 and hybrid requests.
- Adds unit/integration coverage and updates CI versions.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
WeaviateClient.cs |
Propagates server version to gRPC. |
PublicAPI.Unshipped.txt |
Tracks the new public record. |
Models/Search.cs |
Defines AndCross. |
gRPC/Search.Builders.cs |
Maps and validates the operator. |
gRPC/proto/v1/base_search.proto |
Adds the protobuf enum value. |
gRPC/Client.cs |
Stores server-version metadata. |
TestBM25OperatorSyntax.cs |
Tests mapping and version guards. |
Mocks/MockHelpers.cs |
Configures mocked server versions. |
TestSearchHybrid.cs |
Tests hybrid cross-property matching. |
TestQueries.cs |
Tests BM25 behavior and analyzer errors. |
.github/workflows/main.yaml |
Updates the integration-test matrix. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The operator was already accepted on query.bm25, all four hybrid surfaces and aggregate.hybrid, but not on generate.bm25 — leaving AndCross unreachable from generative keyword search. Adds the parameter to the four GenerateClient/TypedGenerateClient overloads, in the same position the query client uses. It flows into the existing BuildBM25 path, so the server-version guard applies unchanged.
| if (_serverVersion.Major == minimum.Major && _serverVersion.Minor == minimum.Minor) | ||
| { | ||
| if (_serverVersion >= minimum) | ||
| { | ||
| return; | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| if (_serverVersion >= AndCrossMinimumVersions[^1]) | ||
| { | ||
| return; | ||
| } |
There was a problem hiding this comment.
nit: This may be duplicating code
I have a strong feeling that this client already has some logic for checking "is this version lower than the minimum required version". I don't know in which file, unfortunately, but AFAIK C# client does a lot of this kind of validation.
There was a problem hiding this comment.
There is Internal/VersionGuard + [RequiresWeaviateVersion], but it can't express this one as AndCross has a backport list (≥1.37.15, ≥1.38.8, ≥1.39.0). Will keep it like this for now and implement generic checks later.
Your nit did catch a real bug though, it was throwing WeaviateFeatureNotSupportedException, which derives from WeaviateServerException. Switched to WeaviateVersionMismatchException, matching the other version gates.
… guard EnsureBM25OperatorSupported runs before the request ever leaves the client, but WeaviateFeatureNotSupportedException derives from WeaviateServerException. Switched to WeaviateVersionMismatchException (WeaviateClientException), which is what the client's other version gates throw via Internal/VersionGuard. The two previously sat under different bases, so a caller could not catch both with anything narrower than WeaviateException. That exception's only constructor takes (operation, requiredVersion, actualVersion), so the backport floors now travel in the operation argument, sourced from the existing AndCrossMinimumVersions ladder rather than a hand-written string. Tests assert the structured RequiredVersion and ActualVersion alongside the exception type. WeaviateFeatureNotSupportedException is left in place: ExceptionHelper still maps a genuine server-side gRPC Unimplemented to it, where the server base class is correct.
Brings in #359 (module endpoint/location), #365 (BM25Operator.AndCross + searchOperator on generate.bm25), #366 (diversitySelection across hybrid and the near* family), and #367 (multimodal vectorizer weights). All of the .cs overload files auto-merged: boost is inserted after `rerank` and diversitySelection after `bm25Operator`/before `autoLimit`, so the two parameter additions never collided. Verified structurally in both directions (merged-minus-boost == origin/main, merged-minus-diversitySelection/ searchOperator == the branch) rather than trusting the auto-merge. The only textual conflict was PublicAPI.Unshipped.txt, where both sides emit a *REMOVED* line plus a replacement signature for the same 102 overloads. Resolved to a deduplicated union (102 identical *REMOVED* lines collapsed), then adjudicated by the public API analyzer: 204 single-parameter signatures were stale (RS0017) and 102 combined signatures were missing (RS0016). After applying those, the RS0016/RS0017 sets are identical to both parents'. Parameter counts after the merge match each parent exactly: boost 111 declarations (as on the branch), diversitySelection 105 and searchOperator 10 (as on main).
Adds
BM25Operator.AndCross(), exposing the server's opt-inOPERATOR_AND_CROSSsearch operator (Weaviate 1.39.0, backported to 1.38.8): every query token must match, but tokens may be matched by different searched properties. Available everywhere a BM25 operator is accepted (bm25 and hybrid query/generate/aggregate paths).WeaviateFeatureNotSupportedExceptionon servers without the operator, which would otherwise silently return OR-semantics results.generate.bm25now accepts a search operator as well. It was the one BM25 surface that didn't, which would have leftAndCrossunreachable from generative keyword search.RequireVersion("1.38.8"); CI matrix minors bumped to latest patches and a 1.39.0 lane added.