|
| 1 | +# Vector Search API Changelog |
| 2 | + |
| 3 | +## Version TBD - API Consolidation |
| 4 | + |
| 5 | +### Summary |
| 6 | + |
| 7 | +Consolidated vector search API from 35+ overloads to ~20 core overloads with extensive implicit conversions. |
| 8 | + |
| 9 | +### Changes |
| 10 | + |
| 11 | +#### New Types |
| 12 | + |
| 13 | +- `VectorSearchInput` - Central type for all vector search inputs with extensive implicit conversions |
| 14 | +- `VectorSearchInput.Builder` - Lambda builder for complex multi-target scenarios |
| 15 | +- `VectorSearchInput.FactoryFn` - Delegate for creating VectorSearchInput via lambda expressions with implicit conversion |
| 16 | +- `HybridVectorInput` - Discriminated union for hybrid search vector inputs (VectorSearchInput, NearTextInput, or NearVectorInput) |
| 17 | +- `HybridVectorInput.FactoryFn` - Delegate for creating HybridVectorInput via lambda builder with `.NearVector()` or `.NearText()` methods |
| 18 | +- `NearVectorInput` - Wrapper for vector input with optional thresholds (replaces `HybridNearVector`) |
| 19 | +- `NearVectorInput.FactoryFn` - Delegate for creating NearVectorInput via lambda builder with target vector configuration |
| 20 | +- `NearTextInput` - Server-side vectorization with target vectors (replaces `HybridNearText`) |
| 21 | +- `NearTextInput.FactoryFn` - Delegate for creating NearTextInput via lambda builder with target vector configuration |
| 22 | +- `TargetVectors` - Static factory methods for target vector configuration |
| 23 | +- `TargetVectorsBuilder` - Lambda builder for target vectors |
| 24 | + |
| 25 | +#### Removed Types |
| 26 | + |
| 27 | +- `IHybridVectorInput` - Marker interface removed in favor of `HybridVectorInput` |
| 28 | +- `INearVectorInput` - Marker interface removed |
| 29 | +- `HybridNearVector` - Renamed to `NearVectorInput` |
| 30 | +- `HybridNearText` - Renamed to `NearTextInput` |
| 31 | + |
| 32 | +#### Overload Reduction |
| 33 | + |
| 34 | +| Client | Method | Before | After | |
| 35 | +|--------|--------|--------|-------| |
| 36 | +| QueryClient | NearVector | 10+ | 4 | |
| 37 | +| QueryClient | NearText | 2 | 4 | |
| 38 | +| QueryClient | NearMedia | 2 | 2 | |
| 39 | +| QueryClient | Hybrid | 4+ | 9 | |
| 40 | +| GenerateClient | NearVector | 6+ | 4 | |
| 41 | +| GenerateClient | NearText | 2 | 4 | |
| 42 | +| GenerateClient | NearMedia | 2 | 2 | |
| 43 | +| GenerateClient | Hybrid | 4+ | 8 | |
| 44 | +| AggregateClient | NearVector | 6+ | 4 | |
| 45 | +| AggregateClient | NearText | 2 | 4 | |
| 46 | +| AggregateClient | NearMedia | 2 | 2 | |
| 47 | +| AggregateClient | Hybrid | 3+ | 4 | |
| 48 | +| TypedQueryClient | NearText | 2 | 4 | |
| 49 | +| TypedQueryClient | NearMedia | 2 | 2 | |
| 50 | +| TypedGenerateClient | NearText | 2 | 4 | |
| 51 | +| TypedGenerateClient | NearMedia | 2 | 2 | |
| 52 | + |
| 53 | +#### API Changes |
| 54 | + |
| 55 | +1. **HybridVectorInput discriminated union for vectors parameter** |
| 56 | + - Before: `Hybrid(string? query, IHybridVectorInput? vectors, ...)` |
| 57 | + - After: `Hybrid(string? query, HybridVectorInput? vectors, ...)` - accepts VectorSearchInput, NearTextInput, or NearVectorInput via implicit conversions |
| 58 | + |
| 59 | +2. **VectorSearchInput replaces multiple input types** |
| 60 | + - Before: Separate overloads for `float[]`, `Vector`, `Vectors`, tuple enumerables |
| 61 | + - After: Single `VectorSearchInput` with implicit conversions from all types |
| 62 | + |
| 63 | +3. **Builder replaces separate overloads** |
| 64 | + - Before: `VectorSearchInputBuilder` as standalone class |
| 65 | + - After: `VectorSearchInput.Builder` as nested class |
| 66 | + |
| 67 | +4. **FactoryFn delegate enables lambda syntax** |
| 68 | + - New: `VectorSearchInput.FactoryFn` delegate with implicit conversion to `VectorSearchInput` |
| 69 | + - Allows: `vectors: b => b.TargetVectorsSum(("title", vec1), ("desc", vec2))` syntax |
| 70 | + |
| 71 | +5. **Targets embedded in VectorSearchInput** |
| 72 | + - Before: Separate `targets` parameter on some methods |
| 73 | + - After: Targets configured via `VectorSearchInput.Builder` methods (Sum, ManualWeights, etc.) |
| 74 | + |
| 75 | +6. **TargetVectors uses static factory methods** |
| 76 | + - Before: `new SimpleTargetVectors(["title", "description"])` |
| 77 | + - After: `TargetVectors.Sum("title", "description")` or `new[] { "title", "description" }` (implicit) |
| 78 | + |
| 79 | +7. **NearTextInput includes TargetVectors** |
| 80 | + - Before: Separate `targetVector` parameter on Hybrid methods |
| 81 | + - After: `NearTextInput.TargetVectors` property is single source of truth |
| 82 | + |
| 83 | +8. **Convenience overloads for text-only Hybrid search** |
| 84 | + - New: Overloads without `vectors` parameter for all Hybrid methods |
| 85 | + - These delegate to main Hybrid method with `vectors: null` |
| 86 | + - Simplifies pure text search: `Hybrid("query")` instead of `Hybrid("query", vectors: null)` |
| 87 | + |
| 88 | +9. **Convenience overloads for NearText target vectors** |
| 89 | + - New: Overloads accepting `TargetVectors?` for all NearText methods (QueryClient, GenerateClient, AggregateClient, TypedQueryClient, TypedGenerateClient) |
| 90 | + - Allows passing string arrays directly: `targets: new[] { "vec1", "vec2" }` |
| 91 | + - Allows static factory methods: `targetVectors: TargetVectors.Sum("vec1", "vec2")` |
| 92 | + - Lambda builder syntax still available: `targetVectors: tv => tv.TargetVectorsSum("vec1", "vec2")` |
| 93 | + - Matches pattern already established by NearVector methods with VectorSearchInput |
| 94 | + |
| 95 | +10. **NearVectorInput FactoryFn constructor for consistency** |
| 96 | + - New: Constructor accepting `VectorSearchInput.FactoryFn` for lambda builder syntax |
| 97 | + - Enables: `new NearVectorInput(v => v.TargetVectorsSum(("title", vec1), ("desc", vec2)))` |
| 98 | + - Matches pattern established by NearTextInput |
| 99 | + |
| 100 | +11. **HybridVectorInput lambda builder for unified target vector syntax** |
| 101 | + - New: `HybridVectorInput.FactoryFn` delegate enables lambda builder pattern for Hybrid search |
| 102 | + - Syntax: `v => v.NearVector(certainty: 0.8).TargetVectorsManualWeights(("title", 1.2, vec1), ("desc", 0.8, vec2))` |
| 103 | + - Syntax: `v => v.NearText(["query"]).TargetVectorsManualWeights(("title", 1.2), ("desc", 0.8))` |
| 104 | + - Eliminates need to construct `NearVectorInput` or `NearTextInput` explicitly |
| 105 | + - Available across all clients: QueryClient, GenerateClient, AggregateClient, TypedQueryClient |
| 106 | + - Unifies target vector configuration directly within the Hybrid method call |
| 107 | + |
| 108 | +12. **NearMedia lambda builder pattern for unified media search** |
| 109 | + - **BREAKING CHANGE**: Old NearImage and NearMedia methods removed entirely |
| 110 | + - New: Single `NearMedia` method using lambda builder pattern with `NearMediaInput.FactoryFn` |
| 111 | + - Syntax: `m => m.Image(imageBytes).TargetVectorsSum("title", "description")` |
| 112 | + - Syntax: `m => m.Video(videoBytes, certainty: 0.8f).TargetVectorsManualWeights(("visual", 1.2), ("audio", 0.8))` |
| 113 | + - Supports all media types: Image, Video, Audio, Thermal, Depth, IMU |
| 114 | + - Optional target vectors via implicit conversion: `m => m.Image(imageBytes)` works without `.Build()` |
| 115 | + - Available across all clients: QueryClient, GenerateClient, AggregateClient, TypedQueryClient, TypedGenerateClient |
| 116 | + - Certainty and distance configured in builder (not method parameters) for consistency with NearText/NearVector patterns |
| 117 | + |
| 118 | +#### Migration from Old NearMedia API |
| 119 | + |
| 120 | +**Simple image search:** |
| 121 | + |
| 122 | +```csharp |
| 123 | +// Before (removed) |
| 124 | +await collection.Query.NearImage(imageBytes); |
| 125 | + |
| 126 | +// After (required) |
| 127 | +await collection.Query.NearMedia(m => m.Image(imageBytes)); |
| 128 | +``` |
| 129 | + |
| 130 | +**With certainty and target vectors:** |
| 131 | + |
| 132 | +```csharp |
| 133 | +// Before (removed) |
| 134 | +await collection.Query.NearImage(imageBytes, certainty: 0.8, targetVectors: t => t.TargetVectorsSum("v1", "v2")); |
| 135 | + |
| 136 | +// After (required) |
| 137 | +await collection.Query.NearMedia(m => m.Image(imageBytes, certainty: 0.8f).TargetVectorsSum("v1", "v2")); |
| 138 | +``` |
| 139 | + |
| 140 | +**Media type specification:** |
| 141 | + |
| 142 | +```csharp |
| 143 | +// Before (removed) |
| 144 | +await collection.Query.NearMedia(videoBytes, NearMediaType.Video, distance: 0.3); |
| 145 | + |
| 146 | +// After (required) |
| 147 | +await collection.Query.NearMedia(m => m.Video(videoBytes, distance: 0.3f)); |
| 148 | +``` |
| 149 | + |
| 150 | +**All media types:** |
| 151 | + |
| 152 | +```csharp |
| 153 | +// All supported via unified lambda builder pattern |
| 154 | +await collection.Query.NearMedia(m => m.Image(imageBytes)); |
| 155 | +await collection.Query.NearMedia(m => m.Video(videoBytes)); |
| 156 | +await collection.Query.NearMedia(m => m.Audio(audioBytes)); |
| 157 | +await collection.Query.NearMedia(m => m.Thermal(thermalBytes)); |
| 158 | +await collection.Query.NearMedia(m => m.Depth(depthBytes)); |
| 159 | +await collection.Query.NearMedia(m => m.IMU(imuBytes)); |
| 160 | +``` |
| 161 | + |
| 162 | +### Migration Examples |
| 163 | + |
| 164 | + |
| 165 | +**Simple hybrid search:** |
| 166 | + |
| 167 | +```csharp |
| 168 | +// Before |
| 169 | +await collection.Query.Hybrid("search query"); |
| 170 | + |
| 171 | +// After (implicit conversion from string) |
| 172 | +await collection.Query.Hybrid("search query"); |
| 173 | +``` |
| 174 | + |
| 175 | +**Hybrid with vectors:** |
| 176 | + |
| 177 | +```csharp |
| 178 | +// Before |
| 179 | +await collection.Query.Hybrid("search query", vectors: new[] { 1f, 2f, 3f }); |
| 180 | + |
| 181 | +// After (tuple implicit conversion) |
| 182 | +await collection.Query.Hybrid(("search query", new[] { 1f, 2f, 3f })); |
| 183 | +``` |
| 184 | + |
| 185 | +**Hybrid with target vectors:** |
| 186 | + |
| 187 | +```csharp |
| 188 | +// Before |
| 189 | +await collection.Query.Hybrid( |
| 190 | + "search query", |
| 191 | + vectors: new HybridNearText("banana"), |
| 192 | + targetVector: ["title", "description"] // separate parameter |
| 193 | +); |
| 194 | + |
| 195 | +// After (targets inside NearTextInput) |
| 196 | +await collection.Query.Hybrid( |
| 197 | + new NearTextInput( |
| 198 | + "banana", |
| 199 | + TargetVectors: TargetVectors.Sum("title", "description") |
| 200 | + ) |
| 201 | +); |
| 202 | + |
| 203 | +// Or with implicit string array conversion |
| 204 | +await collection.Query.Hybrid( |
| 205 | + new NearTextInput( |
| 206 | + "banana", |
| 207 | + TargetVectors: new[] { "title", "description" } |
| 208 | + ) |
| 209 | +); |
| 210 | +``` |
| 211 | + |
| 212 | +**Lambda builder for vectors:** |
| 213 | + |
| 214 | +```csharp |
| 215 | +await collection.Query.Hybrid( |
| 216 | + "search query", |
| 217 | + v => v.TargetVectorsSum( |
| 218 | + ("title", new[] { 1f, 2f }), |
| 219 | + ("description", new[] { 3f, 4f }) |
| 220 | + ) |
| 221 | +); |
| 222 | +``` |
| 223 | + |
| 224 | +**Target vectors with weights:** |
| 225 | + |
| 226 | +```csharp |
| 227 | +// Use static factory methods |
| 228 | +var targetVectors = TargetVectors.ManualWeights(("title", 1.2), ("desc", 0.8)); |
| 229 | +await collection.Query.Hybrid( |
| 230 | + new NearTextInput("banana", TargetVectors: targets) |
| 231 | +); |
| 232 | + |
| 233 | +// Or with RelativeScore |
| 234 | +var targetVectors = TargetVectors.RelativeScore(("title", 0.7), ("desc", 0.3)); |
| 235 | +``` |
| 236 | + |
| 237 | +**NearText with target vectors:** |
| 238 | + |
| 239 | +```csharp |
| 240 | +// Before: lambda builder required |
| 241 | +await collection.Query.NearText( |
| 242 | + "search query", |
| 243 | + targetVectors: tv => tv.TargetVectorsSum("title", "description") |
| 244 | +); |
| 245 | + |
| 246 | +// After: multiple options available |
| 247 | +// Option 1: String array (simplest) |
| 248 | +await collection.Query.NearText( |
| 249 | + "search query", |
| 250 | + targets: new[] { "title", "description" } |
| 251 | +); |
| 252 | + |
| 253 | +// Option 2: Static factory method |
| 254 | +await collection.Query.NearText( |
| 255 | + "search query", |
| 256 | + targetVectors: TargetVectors.Sum("title", "description") |
| 257 | +); |
| 258 | + |
| 259 | +// Option 3: Lambda builder (still works) |
| 260 | +await collection.Query.NearText( |
| 261 | + "search query", |
| 262 | + targetVectors: tv => tv.TargetVectorsSum("title", "description") |
| 263 | +); |
| 264 | +``` |
| 265 | + |
| 266 | +**Simple vector search (no changes needed):** |
| 267 | + |
| 268 | +```csharp |
| 269 | +// Works unchanged via implicit conversion |
| 270 | +await collection.Query.NearVector(new[] { 1f, 2f, 3f }); |
| 271 | +``` |
| 272 | + |
| 273 | +**NearVectorInput with lambda builder:** |
| 274 | + |
| 275 | +```csharp |
| 276 | +// Before: only accepts VectorSearchInput directly |
| 277 | +new NearVectorInput(new[] { 1f, 2f, 3f }); |
| 278 | + |
| 279 | +// After: also accepts lambda builder |
| 280 | +new NearVectorInput( |
| 281 | + v => v.TargetVectorsSum(("title", vec1), ("desc", vec2)), |
| 282 | + Certainty: 0.8f |
| 283 | +); |
| 284 | +``` |
| 285 | + |
| 286 | +**Named vector with target:** |
| 287 | + |
| 288 | +```csharp |
| 289 | +// Before |
| 290 | +await collection.Query.NearVector(new[] { 1f, 2f, 3f }, targetVector: "title"); |
| 291 | + |
| 292 | +// After |
| 293 | +await collection.Query.NearVector(v => v.Single("title", new[] { 1f, 2f, 3f })); |
| 294 | +``` |
| 295 | + |
| 296 | +**Multi-target with weights:** |
| 297 | + |
| 298 | +```csharp |
| 299 | +await collection.Query.NearVector( |
| 300 | + v => v.TargetVectorsManualWeights( |
| 301 | + ("title", 1.2, new[] { 1f, 2f }), |
| 302 | + ("desc", 0.8, new[] { 3f, 4f }) |
| 303 | + ) |
| 304 | +); |
| 305 | +``` |
| 306 | + |
| 307 | +**Hybrid with NearVector and target vectors (NEW unified syntax):** |
| 308 | + |
| 309 | +```csharp |
| 310 | +// Before: construct NearVectorInput explicitly |
| 311 | +await collection.Query.Hybrid( |
| 312 | + "test", |
| 313 | + new NearVectorInput( |
| 314 | + VectorSearchInput.Combine( |
| 315 | + TargetVectors.ManualWeights(("title", 1.2), ("desc", 0.8)), |
| 316 | + ("title", new[] { 1f, 2f }), |
| 317 | + ("desc", new[] { 3f, 4f }) |
| 318 | + ), |
| 319 | + Certainty: 0.8f |
| 320 | + ) |
| 321 | +); |
| 322 | + |
| 323 | +// After: lambda builder unifies configuration |
| 324 | +await collection.Query.Hybrid( |
| 325 | + "test", |
| 326 | + v => v.NearVector(certainty: 0.8f) |
| 327 | + .ManualWeights( |
| 328 | + ("title", 1.2, new[] { 1f, 2f }), |
| 329 | + ("desc", 0.8, new[] { 3f, 4f }) |
| 330 | + ) |
| 331 | +); |
| 332 | +``` |
| 333 | + |
| 334 | +**Hybrid with NearText and target vectors (NEW unified syntax):** |
| 335 | + |
| 336 | +```csharp |
| 337 | +// Before: construct NearTextInput explicitly |
| 338 | +await collection.Query.Hybrid( |
| 339 | + "test", |
| 340 | + new NearTextInput( |
| 341 | + ["concept1", "concept2"], |
| 342 | + TargetVectors: TargetVectors.ManualWeights(("title", 1.2), ("desc", 0.8)) |
| 343 | + ) |
| 344 | +); |
| 345 | + |
| 346 | +// After: lambda builder unifies configuration |
| 347 | +await collection.Query.Hybrid( |
| 348 | + "test", |
| 349 | + v => v.NearText(["concept1", "concept2"]) |
| 350 | + .ManualWeights(("title", 1.2), ("desc", 0.8)) |
| 351 | +); |
| 352 | +``` |
| 353 | + |
| 354 | +**Hybrid with NearText including Move parameters:** |
| 355 | + |
| 356 | +```csharp |
| 357 | +await collection.Query.Hybrid( |
| 358 | + "test", |
| 359 | + v => v.NearText( |
| 360 | + ["concept"], |
| 361 | + certainty: 0.7f, |
| 362 | + moveTo: new Move("positive", 0.5f), |
| 363 | + moveAway: new Move("negative", 0.3f) |
| 364 | + ) |
| 365 | + .Sum("title", "description") |
| 366 | +); |
| 367 | +``` |
| 368 | + |
| 369 | +### Breaking Changes |
| 370 | + |
| 371 | +- `IHybridVectorInput` and `INearVectorInput` interfaces removed |
| 372 | +- `HybridNearVector` renamed to `NearVectorInput` |
| 373 | +- `HybridNearText` renamed to `NearTextInput` |
| 374 | +- `Hybrid` method `vectors` parameter now uses `HybridVectorInput?` discriminated union type |
| 375 | +- `SimpleTargetVectors` and `WeightedTargetVectors` constructors are now internal |
| 376 | +- `VectorSearchInput.Builder` constructor is now internal (use `FactoryFn` lambda syntax instead) |
| 377 | +- `targetVector` parameter removed from Hybrid methods - use `NearTextInput.TargetVectors` instead |
| 378 | +- Removed tuple enumerable overloads (`IEnumerable<(string, Vector)>`) |
| 379 | +- `targetVector` string parameter removed from NearVector methods (use builder instead) |
| 380 | +- Overload resolution may change in edge cases with implicit conversions |
0 commit comments