diff --git a/dotnet/src/IntegrationTests/Connectors/Memory/AzureAISearch/AzureAISearchKeywordVectorizedHybridSearchTests.cs b/dotnet/src/IntegrationTests/Connectors/Memory/AzureAISearch/AzureAISearchKeywordVectorizedHybridSearchTests.cs
deleted file mode 100644
index d42561ac8ee6..000000000000
--- a/dotnet/src/IntegrationTests/Connectors/Memory/AzureAISearch/AzureAISearchKeywordVectorizedHybridSearchTests.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using Microsoft.Extensions.VectorData;
-using Microsoft.SemanticKernel.Connectors.AzureAISearch;
-using Xunit;
-
-namespace SemanticKernel.IntegrationTests.Connectors.Memory.AzureAISearch;
-
-///
-/// Inherits common integration tests that should pass for any .
-///
-/// Azure AI Search setup and teardown.
-[Collection("AzureAISearchVectorStoreCollection")]
-[AzureAISearchConfigCondition]
-public class AzureAISearchKeywordVectorizedHybridSearchTests(AzureAISearchVectorStoreFixture fixture) : BaseKeywordVectorizedHybridSearchTests
-{
- protected override string Key1 => "1";
- protected override string Key2 => "2";
- protected override string Key3 => "3";
- protected override string Key4 => "4";
- protected override int DelayAfterUploadInMilliseconds => 2000;
-
- protected override IVectorStoreRecordCollection GetTargetRecordCollection(string recordCollectionName, VectorStoreRecordDefinition? vectorStoreRecordDefinition)
- {
- return new AzureAISearchVectorStoreRecordCollection(fixture.SearchIndexClient, recordCollectionName + AzureAISearchVectorStoreFixture.TestIndexPostfix, new()
- {
- VectorStoreRecordDefinition = vectorStoreRecordDefinition
- });
- }
-}
diff --git a/dotnet/src/IntegrationTests/Connectors/Memory/AzureCosmosDBNoSQL/AzureCosmosDBNoSQLKeywordVectorizedHybridSearchTests.cs b/dotnet/src/IntegrationTests/Connectors/Memory/AzureCosmosDBNoSQL/AzureCosmosDBNoSQLKeywordVectorizedHybridSearchTests.cs
deleted file mode 100644
index 3ce18873790f..000000000000
--- a/dotnet/src/IntegrationTests/Connectors/Memory/AzureCosmosDBNoSQL/AzureCosmosDBNoSQLKeywordVectorizedHybridSearchTests.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using Microsoft.Extensions.VectorData;
-using Microsoft.SemanticKernel.Connectors.AzureCosmosDBNoSQL;
-using Xunit;
-
-namespace SemanticKernel.IntegrationTests.Connectors.Memory.AzureCosmosDBNoSQL;
-
-///
-/// Inherits common integration tests that should pass for any .
-///
-[Collection("AzureCosmosDBNoSQLVectorStoreCollection")]
-[AzureCosmosDBNoSQLConnectionStringSetCondition]
-public class AzureCosmosDBNoSQLKeywordVectorizedHybridSearchTests(AzureCosmosDBNoSQLVectorStoreFixture fixture) : BaseKeywordVectorizedHybridSearchTests
-{
- protected override string Key1 => "1";
- protected override string Key2 => "2";
- protected override string Key3 => "3";
- protected override string Key4 => "4";
- protected override int DelayAfterUploadInMilliseconds => 2000;
- protected override string? IndexKind { get; } = Microsoft.Extensions.VectorData.IndexKind.Flat;
-
- protected override IVectorStoreRecordCollection GetTargetRecordCollection(string recordCollectionName, VectorStoreRecordDefinition? vectorStoreRecordDefinition)
- {
- return new AzureCosmosDBNoSQLVectorStoreRecordCollection(fixture.Database!, recordCollectionName, new()
- {
- VectorStoreRecordDefinition = vectorStoreRecordDefinition
- });
- }
-}
diff --git a/dotnet/src/IntegrationTests/Connectors/Memory/BaseKeywordVectorizedHybridSearchTests.cs b/dotnet/src/IntegrationTests/Connectors/Memory/BaseKeywordVectorizedHybridSearchTests.cs
deleted file mode 100644
index 149159ad46c0..000000000000
--- a/dotnet/src/IntegrationTests/Connectors/Memory/BaseKeywordVectorizedHybridSearchTests.cs
+++ /dev/null
@@ -1,341 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.Extensions.VectorData;
-using SemanticKernel.IntegrationTests.Connectors.Memory.Xunit;
-using Xunit;
-
-namespace SemanticKernel.IntegrationTests.Connectors.Memory;
-
-///
-/// Base class for common integration tests that should pass for any .
-///
-/// The type of key to use with the record collection.
-public abstract class BaseKeywordVectorizedHybridSearchTests
- where TKey : notnull
-{
- protected abstract TKey Key1 { get; }
- protected abstract TKey Key2 { get; }
- protected abstract TKey Key3 { get; }
- protected abstract TKey Key4 { get; }
-
- protected virtual int DelayAfterIndexCreateInMilliseconds { get; } = 0;
-
- protected virtual int DelayAfterUploadInMilliseconds { get; } = 0;
-
- protected virtual string? IndexKind { get; } = null;
-
- protected abstract IVectorStoreRecordCollection GetTargetRecordCollection(string recordCollectionName, VectorStoreRecordDefinition? vectorStoreRecordDefinition);
-
- [VectorStoreFact]
- public async Task SearchShouldReturnExpectedResultsAsync()
- {
- // Arrange
- var sut = this.GetTargetRecordCollection>(
- "kwhybrid",
- this.KeyWithVectorAndStringRecordDefinition);
-
- var hybridSearch = sut as IKeywordHybridSearch>;
-
- try
- {
- var vector = new ReadOnlyMemory([1, 0, 0, 0]);
- await this.CreateCollectionAndAddDataAsync(sut, vector);
-
- // Act
- // All records have the same vector, but the third contains Grapes, so searching for
- // Grapes should return the third record first.
- var searchResult = await hybridSearch!.HybridSearchAsync(vector, ["Grapes"]);
-
- // Assert
- var results = await searchResult.Results.ToListAsync();
- Assert.Equal(3, results.Count);
-
- Assert.Equal(this.Key3, results[0].Record.Key);
- }
- finally
- {
- // Cleanup
- await sut.DeleteCollectionAsync();
- }
- }
-
- [VectorStoreFact]
- public async Task SearchWithFilterShouldReturnExpectedResultsAsync()
- {
- // Arrange
- var sut = this.GetTargetRecordCollection>(
- "kwfilteredhybrid",
- this.KeyWithVectorAndStringRecordDefinition);
-
- var hybridSearch = sut as IKeywordHybridSearch>;
-
- try
- {
- var vector = new ReadOnlyMemory([1, 0, 0, 0]);
- await this.CreateCollectionAndAddDataAsync(sut, vector);
-
- // Act
- // All records have the same vector, but the second contains Oranges, however
- // adding the filter should limit the results to only the first.
-#pragma warning disable CS0618 // Type or member is obsolete
- var options = new HybridSearchOptions>
- {
- OldFilter = new VectorSearchFilter().EqualTo("Code", 1)
- };
-#pragma warning restore CS0618 // Type or member is obsolete
- var searchResult = await hybridSearch!.HybridSearchAsync(vector, ["Oranges"], options);
-
- // Assert
- var results = await searchResult.Results.ToListAsync();
- Assert.Single(results);
-
- Assert.Equal(this.Key1, results[0].Record.Key);
- }
- finally
- {
- // Cleanup
- await sut.DeleteCollectionAsync();
- }
- }
-
- [VectorStoreFact]
- public async Task SearchWithTopShouldReturnExpectedResultsAsync()
- {
- // Arrange
- var sut = this.GetTargetRecordCollection>(
- "kwtophybrid",
- this.KeyWithVectorAndStringRecordDefinition);
-
- var hybridSearch = sut as IKeywordHybridSearch>;
-
- try
- {
- var vector = new ReadOnlyMemory([1, 0, 0, 0]);
- await this.CreateCollectionAndAddDataAsync(sut, vector);
-
- // Act
- // All records have the same vector, but the second contains Oranges, so the
- // second should be returned first.
- var searchResult = await hybridSearch!.HybridSearchAsync(vector, ["Oranges"], new() { Top = 1 });
-
- // Assert
- var results = await searchResult.Results.ToListAsync();
- Assert.Single(results);
-
- Assert.Equal(this.Key2, results[0].Record.Key);
- }
- finally
- {
- // Cleanup
- await sut.DeleteCollectionAsync();
- }
- }
-
- [VectorStoreFact]
- public async Task SearchWithSkipShouldReturnExpectedResultsAsync()
- {
- // Arrange
- var sut = this.GetTargetRecordCollection>(
- "kwskiphybrid",
- this.KeyWithVectorAndStringRecordDefinition);
-
- var hybridSearch = sut as IKeywordHybridSearch>;
-
- try
- {
- var vector = new ReadOnlyMemory([1, 0, 0, 0]);
- await this.CreateCollectionAndAddDataAsync(sut, vector);
-
- // Act
- // All records have the same vector, but the first and third contain healthy,
- // so when skipping the first two results, we should get the second record.
- var searchResult = await hybridSearch!.HybridSearchAsync(vector, ["healthy"], new() { Skip = 2 });
-
- // Assert
- var results = await searchResult.Results.ToListAsync();
- Assert.Single(results);
-
- Assert.Equal(this.Key2, results[0].Record.Key);
- }
- finally
- {
- // Cleanup
- await sut.DeleteCollectionAsync();
- }
- }
-
- [VectorStoreFact]
- public async Task SearchWithMultipleKeywordsShouldRankMatchedKeywordsHigherAsync()
- {
- // Arrange
- var sut = this.GetTargetRecordCollection>(
- "kwmultikeywordhybrid",
- this.KeyWithVectorAndStringRecordDefinition);
-
- var hybridSearch = sut as IKeywordHybridSearch>;
-
- try
- {
- var vector = new ReadOnlyMemory([1, 0, 0, 0]);
- await this.CreateCollectionAndAddDataAsync(sut, vector);
-
- // Act
- var searchResult = await hybridSearch!.HybridSearchAsync(vector, ["tangy", "nourishing"]);
-
- // Assert
- var results = await searchResult.Results.ToListAsync();
- Assert.Equal(3, results.Count);
-
- Assert.True(results[0].Record.Key.Equals(this.Key1) || results[0].Record.Key.Equals(this.Key2));
- Assert.True(results[1].Record.Key.Equals(this.Key1) || results[1].Record.Key.Equals(this.Key2));
- Assert.Equal(this.Key3, results[2].Record.Key);
- }
- finally
- {
- // Cleanup
- await sut.DeleteCollectionAsync();
- }
- }
-
- [VectorStoreFact]
- public async Task SearchWithMultiTextRecordSearchesRequestedFieldAsync()
- {
- // Arrange
- var sut = this.GetTargetRecordCollection>(
- "kwmultitexthybrid",
- this.MultiSearchStringRecordDefinition);
-
- var hybridSearch = sut as IKeywordHybridSearch>;
-
- try
- {
- var vector = new ReadOnlyMemory([1, 0, 0, 0]);
- await this.CreateCollectionAndAddDataAsync(sut, vector);
-
- // Act
- var searchResult1 = await hybridSearch!.HybridSearchAsync(vector, ["Apples"], new() { AdditionalProperty = r => r.Text2 });
- var searchResult2 = await hybridSearch!.HybridSearchAsync(vector, ["Oranges"], new() { AdditionalProperty = r => r.Text2 });
-
- // Assert
- var results1 = await searchResult1.Results.ToListAsync();
- Assert.Equal(2, results1.Count);
-
- Assert.Equal(this.Key2, results1[0].Record.Key);
- Assert.Equal(this.Key1, results1[1].Record.Key);
-
- var results2 = await searchResult2.Results.ToListAsync();
- Assert.Equal(2, results2.Count);
-
- Assert.Equal(this.Key1, results2[0].Record.Key);
- Assert.Equal(this.Key2, results2[1].Record.Key);
- }
- finally
- {
- // Cleanup
- await sut.DeleteCollectionAsync();
- }
- }
-
- private async Task CreateCollectionAndAddDataAsync(IVectorStoreRecordCollection> sut, ReadOnlyMemory vector)
- {
- await sut.CreateCollectionIfNotExistsAsync();
- await Task.Delay(this.DelayAfterIndexCreateInMilliseconds);
-
- var record1 = new KeyWithVectorAndStringRecord
- {
- Key = this.Key1,
- Text = "Apples are a healthy and nourishing snack",
- Vector = vector,
- Code = 1
- };
- var record2 = new KeyWithVectorAndStringRecord
- {
- Key = this.Key2,
- Text = "Oranges are tangy and contain vitamin c",
- Vector = vector,
- Code = 2
- };
- var record3 = new KeyWithVectorAndStringRecord
- {
- Key = this.Key3,
- Text = "Grapes are healthy, sweet and juicy",
- Vector = vector,
- Code = 3
- };
-
- await sut.UpsertBatchAsync([record1, record2, record3]).ToListAsync();
- await Task.Delay(this.DelayAfterUploadInMilliseconds);
- }
-
- private async Task CreateCollectionAndAddDataAsync(IVectorStoreRecordCollection> sut, ReadOnlyMemory vector)
- {
- await sut.CreateCollectionIfNotExistsAsync();
- await Task.Delay(this.DelayAfterIndexCreateInMilliseconds);
-
- var record1 = new MultiSearchStringRecord
- {
- Key = this.Key1,
- Text1 = "Apples",
- Text2 = "Oranges",
- Vector = vector
- };
- var record2 = new MultiSearchStringRecord
- {
- Key = this.Key2,
- Text1 = "Oranges",
- Text2 = "Apples",
- Vector = vector
- };
-
- await sut.UpsertBatchAsync([record1, record2]).ToListAsync();
- await Task.Delay(this.DelayAfterUploadInMilliseconds);
- }
-
- private VectorStoreRecordDefinition KeyWithVectorAndStringRecordDefinition => new()
- {
- Properties = new List()
- {
- new VectorStoreRecordKeyProperty("Key", typeof(TKey)),
- new VectorStoreRecordDataProperty("Text", typeof(string)) { IsFullTextSearchable = true },
- new VectorStoreRecordDataProperty("Code", typeof(int)) { IsFilterable = true },
- new VectorStoreRecordVectorProperty("Vector", typeof(ReadOnlyMemory)) { Dimensions = 4, IndexKind = this.IndexKind },
- }
- };
-
- private sealed class KeyWithVectorAndStringRecord
- {
- public TRecordKey Key { get; set; } = default!;
-
- public string Text { get; set; } = string.Empty;
-
- public int Code { get; set; }
-
- public ReadOnlyMemory Vector { get; set; }
- }
-
- private VectorStoreRecordDefinition MultiSearchStringRecordDefinition => new()
- {
- Properties = new List()
- {
- new VectorStoreRecordKeyProperty("Key", typeof(TKey)),
- new VectorStoreRecordDataProperty("Text1", typeof(string)) { IsFullTextSearchable = true },
- new VectorStoreRecordDataProperty("Text2", typeof(string)) { IsFullTextSearchable = true },
- new VectorStoreRecordVectorProperty("Vector", typeof(ReadOnlyMemory)) { Dimensions = 4, IndexKind = this.IndexKind },
- }
- };
-
- private sealed class MultiSearchStringRecord
- {
- public TRecordKey Key { get; set; } = default!;
-
- public string Text1 { get; set; } = string.Empty;
-
- public string Text2 { get; set; } = string.Empty;
-
- public ReadOnlyMemory Vector { get; set; }
- }
-}
diff --git a/dotnet/src/IntegrationTests/Connectors/Memory/MongoDB/MongoDBKeywordVectorizedHybridSearchTests.cs b/dotnet/src/IntegrationTests/Connectors/Memory/MongoDB/MongoDBKeywordVectorizedHybridSearchTests.cs
deleted file mode 100644
index c6e326a14f76..000000000000
--- a/dotnet/src/IntegrationTests/Connectors/Memory/MongoDB/MongoDBKeywordVectorizedHybridSearchTests.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using Microsoft.Extensions.VectorData;
-using Microsoft.SemanticKernel.Connectors.MongoDB;
-using SemanticKernel.IntegrationTests.Connectors.Memory;
-using Xunit;
-
-namespace SemanticKernel.IntegrationTests.Connectors.MongoDB;
-
-///
-/// Inherits common integration tests that should pass for any .
-///
-[Collection("MongoDBVectorStoreCollection")]
-public class MongoDBKeywordVectorizedHybridSearchTests(MongoDBVectorStoreFixture fixture) : BaseKeywordVectorizedHybridSearchTests
-{
- protected override string Key1 => "1";
- protected override string Key2 => "2";
- protected override string Key3 => "3";
- protected override string Key4 => "4";
- protected override int DelayAfterUploadInMilliseconds => 1000;
-
- protected override IVectorStoreRecordCollection GetTargetRecordCollection(string recordCollectionName, VectorStoreRecordDefinition? vectorStoreRecordDefinition)
- {
- return new MongoDBVectorStoreRecordCollection(fixture.MongoDatabase, recordCollectionName, new()
- {
- VectorStoreRecordDefinition = vectorStoreRecordDefinition
- });
- }
-}
diff --git a/dotnet/src/IntegrationTests/Connectors/Memory/Qdrant/QdrantNamedVectorsKeywordVectorizedHybridSearchTests.cs b/dotnet/src/IntegrationTests/Connectors/Memory/Qdrant/QdrantNamedVectorsKeywordVectorizedHybridSearchTests.cs
deleted file mode 100644
index 20fd1097b957..000000000000
--- a/dotnet/src/IntegrationTests/Connectors/Memory/Qdrant/QdrantNamedVectorsKeywordVectorizedHybridSearchTests.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using Microsoft.Extensions.VectorData;
-using Microsoft.SemanticKernel.Connectors.Qdrant;
-using Xunit;
-
-namespace SemanticKernel.IntegrationTests.Connectors.Memory.Qdrant;
-
-///
-/// Inherits common integration tests that should pass for any .
-///
-[Collection("QdrantVectorStoreCollection")]
-public class QdrantNamedVectorsKeywordVectorizedHybridSearchTests(QdrantVectorStoreFixture fixture) : BaseKeywordVectorizedHybridSearchTests
-{
- protected override ulong Key1 => 1;
- protected override ulong Key2 => 2;
- protected override ulong Key3 => 3;
- protected override ulong Key4 => 4;
-
- protected override IVectorStoreRecordCollection GetTargetRecordCollection(string recordCollectionName, VectorStoreRecordDefinition? vectorStoreRecordDefinition)
- {
- return new QdrantVectorStoreRecordCollection(fixture.QdrantClient, recordCollectionName, new()
- {
- HasNamedVectors = true,
- VectorStoreRecordDefinition = vectorStoreRecordDefinition
- });
- }
-}
diff --git a/dotnet/src/IntegrationTests/Connectors/Memory/Qdrant/QdrantSingleVectorKeywordVectorizedHybridSearchTests.cs b/dotnet/src/IntegrationTests/Connectors/Memory/Qdrant/QdrantSingleVectorKeywordVectorizedHybridSearchTests.cs
deleted file mode 100644
index 4579e47b56ad..000000000000
--- a/dotnet/src/IntegrationTests/Connectors/Memory/Qdrant/QdrantSingleVectorKeywordVectorizedHybridSearchTests.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using Microsoft.Extensions.VectorData;
-using Microsoft.SemanticKernel.Connectors.Qdrant;
-using Xunit;
-
-namespace SemanticKernel.IntegrationTests.Connectors.Memory.Qdrant;
-
-///
-/// Inherits common integration tests that should pass for any .
-///
-[Collection("QdrantVectorStoreCollection")]
-public class QdrantSingleVectorKeywordVectorizedHybridSearchTests(QdrantVectorStoreFixture fixture) : BaseKeywordVectorizedHybridSearchTests
-{
- protected override ulong Key1 => 1;
- protected override ulong Key2 => 2;
- protected override ulong Key3 => 3;
- protected override ulong Key4 => 4;
-
- protected override IVectorStoreRecordCollection GetTargetRecordCollection(string recordCollectionName, VectorStoreRecordDefinition? vectorStoreRecordDefinition)
- {
- return new QdrantVectorStoreRecordCollection(fixture.QdrantClient, recordCollectionName, new()
- {
- HasNamedVectors = false,
- VectorStoreRecordDefinition = vectorStoreRecordDefinition
- });
- }
-}
diff --git a/dotnet/src/IntegrationTests/Connectors/Memory/Weaviate/WeaviateKeywordVectorizedHybridSearchTests.cs b/dotnet/src/IntegrationTests/Connectors/Memory/Weaviate/WeaviateKeywordVectorizedHybridSearchTests.cs
deleted file mode 100644
index 2ec29b428053..000000000000
--- a/dotnet/src/IntegrationTests/Connectors/Memory/Weaviate/WeaviateKeywordVectorizedHybridSearchTests.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using System;
-using Microsoft.Extensions.VectorData;
-using Microsoft.SemanticKernel.Connectors.Weaviate;
-using Xunit;
-
-namespace SemanticKernel.IntegrationTests.Connectors.Memory.Weaviate;
-
-///
-/// Inherits common integration tests that should pass for any .
-///
-/// Weaviate setup and teardown.
-[Collection("WeaviateVectorStoreCollection")]
-public class WeaviateKeywordVectorizedHybridSearchTests(WeaviateVectorStoreFixture fixture) : BaseKeywordVectorizedHybridSearchTests
-{
- protected override Guid Key1 => new("11111111-1111-1111-1111-111111111111");
- protected override Guid Key2 => new("22222222-2222-2222-2222-222222222222");
- protected override Guid Key3 => new("33333333-3333-3333-3333-333333333333");
- protected override Guid Key4 => new("44444444-4444-4444-4444-444444444444");
- protected override int DelayAfterUploadInMilliseconds => 1000;
-
- protected override IVectorStoreRecordCollection GetTargetRecordCollection(string recordCollectionName, VectorStoreRecordDefinition? vectorStoreRecordDefinition)
- {
- // Weaviate collection names must start with an upper case letter.
- var recordCollectionNameChars = recordCollectionName.ToCharArray();
- recordCollectionNameChars[0] = char.ToUpperInvariant(recordCollectionNameChars[0]);
-
- return new WeaviateVectorStoreRecordCollection(fixture.HttpClient!, new string(recordCollectionNameChars), new()
- {
- VectorStoreRecordDefinition = vectorStoreRecordDefinition
- });
- }
-}
diff --git a/dotnet/src/VectorDataIntegrationTests/AzureAISearchIntegrationTests/HybridSearch/AzureAISearchKeywordVectorizedHybridSearchTests.cs b/dotnet/src/VectorDataIntegrationTests/AzureAISearchIntegrationTests/HybridSearch/AzureAISearchKeywordVectorizedHybridSearchTests.cs
new file mode 100644
index 000000000000..3860489b9471
--- /dev/null
+++ b/dotnet/src/VectorDataIntegrationTests/AzureAISearchIntegrationTests/HybridSearch/AzureAISearchKeywordVectorizedHybridSearchTests.cs
@@ -0,0 +1,41 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.Text.RegularExpressions;
+using AzureAISearchIntegrationTests.Support;
+using Microsoft.Extensions.VectorData;
+using VectorDataSpecificationTests.HybridSearch;
+using VectorDataSpecificationTests.Support;
+using Xunit;
+
+namespace AzureAISearchIntegrationTests.HybridSearch;
+
+///
+/// Inherits common integration tests that should pass for any .
+///
+public class AzureAISearchKeywordVectorizedHybridSearchTests(
+ AzureAISearchKeywordVectorizedHybridSearchTests.VectorAndStringFixture vectorAndStringFixture,
+ AzureAISearchKeywordVectorizedHybridSearchTests.MultiTextFixture multiTextFixture)
+ : KeywordVectorizedHybridSearchComplianceTests(vectorAndStringFixture, multiTextFixture),
+ IClassFixture,
+ IClassFixture
+{
+#pragma warning disable CA1308 // Normalize strings to uppercase
+ private static readonly string _testIndexPostfix = new Regex("[^a-zA-Z0-9]").Replace(Environment.MachineName.ToLowerInvariant(), "");
+#pragma warning restore CA1308 // Normalize strings to uppercase
+
+ public new class VectorAndStringFixture : KeywordVectorizedHybridSearchComplianceTests.VectorAndStringFixture
+ {
+ public override TestStore TestStore => AzureAISearchTestStore.Instance;
+
+ // Azure AI search only supports lowercase letters, digits or dashes.
+ protected override string CollectionName => "vecstring-hybrid-search-" + _testIndexPostfix;
+ }
+
+ public new class MultiTextFixture : KeywordVectorizedHybridSearchComplianceTests.MultiTextFixture
+ {
+ public override TestStore TestStore => AzureAISearchTestStore.Instance;
+
+ // Azure AI search only supports lowercase letters, digits or dashes.
+ protected override string CollectionName => "multitext-hybrid-search-" + _testIndexPostfix;
+ }
+}
diff --git a/dotnet/src/VectorDataIntegrationTests/CosmosNoSQLIntegrationTests/CosmosNoSQLIntegrationTests.csproj b/dotnet/src/VectorDataIntegrationTests/CosmosNoSQLIntegrationTests/CosmosNoSQLIntegrationTests.csproj
index 715b01505df7..7c60f6d74ebd 100644
--- a/dotnet/src/VectorDataIntegrationTests/CosmosNoSQLIntegrationTests/CosmosNoSQLIntegrationTests.csproj
+++ b/dotnet/src/VectorDataIntegrationTests/CosmosNoSQLIntegrationTests/CosmosNoSQLIntegrationTests.csproj
@@ -7,23 +7,25 @@
true
false
CosmosNoSQLIntegrationTests
+ b7762d10-e29b-4bb1-8b74-b6d69a667dd4
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
-
-
-
+
+
+
+
+
-
-
+
+
diff --git a/dotnet/src/VectorDataIntegrationTests/CosmosNoSQLIntegrationTests/HybridSearch/CosmosNoSQLKeywordVectorizedHybridSearchTests.cs b/dotnet/src/VectorDataIntegrationTests/CosmosNoSQLIntegrationTests/HybridSearch/CosmosNoSQLKeywordVectorizedHybridSearchTests.cs
new file mode 100644
index 000000000000..24935b4ffc2d
--- /dev/null
+++ b/dotnet/src/VectorDataIntegrationTests/CosmosNoSQLIntegrationTests/HybridSearch/CosmosNoSQLKeywordVectorizedHybridSearchTests.cs
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using CosmosNoSQLIntegrationTests.Support;
+using VectorDataSpecificationTests.HybridSearch;
+using VectorDataSpecificationTests.Support;
+using Xunit;
+
+namespace CosmosNoSQLIntegrationTests.HybridSearch;
+
+public class CosmosNoSQLKeywordVectorizedHybridSearchTests(
+ CosmosNoSQLKeywordVectorizedHybridSearchTests.VectorAndStringFixture vectorAndStringFixture,
+ CosmosNoSQLKeywordVectorizedHybridSearchTests.MultiTextFixture multiTextFixture)
+ : KeywordVectorizedHybridSearchComplianceTests(vectorAndStringFixture, multiTextFixture),
+ IClassFixture,
+ IClassFixture
+{
+ public new class VectorAndStringFixture : KeywordVectorizedHybridSearchComplianceTests.VectorAndStringFixture
+ {
+ public override TestStore TestStore => CosmosNoSqlTestStore.Instance;
+ }
+
+ public new class MultiTextFixture : KeywordVectorizedHybridSearchComplianceTests.MultiTextFixture
+ {
+ public override TestStore TestStore => CosmosNoSqlTestStore.Instance;
+ }
+}
diff --git a/dotnet/src/VectorDataIntegrationTests/CosmosNoSQLIntegrationTests/Support/CosmosNoSQLTestEnvironment.cs b/dotnet/src/VectorDataIntegrationTests/CosmosNoSQLIntegrationTests/Support/CosmosNoSQLTestEnvironment.cs
index bd2848a2cb8f..6f9db1179ca5 100644
--- a/dotnet/src/VectorDataIntegrationTests/CosmosNoSQLIntegrationTests/Support/CosmosNoSQLTestEnvironment.cs
+++ b/dotnet/src/VectorDataIntegrationTests/CosmosNoSQLIntegrationTests/Support/CosmosNoSQLTestEnvironment.cs
@@ -18,6 +18,7 @@ static CosmosNoSQLTestEnvironment()
.AddJsonFile(path: "testsettings.json", optional: true)
.AddJsonFile(path: "testsettings.development.json", optional: true)
.AddEnvironmentVariables()
+ .AddUserSecrets()
.Build();
ConnectionString = configuration["AzureCosmosDBNoSQL:ConnectionString"];
diff --git a/dotnet/src/VectorDataIntegrationTests/MongoDBIntegrationTests/HybridSearch/MongoDBKeywordVectorizedHybridSearchTests.cs b/dotnet/src/VectorDataIntegrationTests/MongoDBIntegrationTests/HybridSearch/MongoDBKeywordVectorizedHybridSearchTests.cs
new file mode 100644
index 000000000000..7e8259442a36
--- /dev/null
+++ b/dotnet/src/VectorDataIntegrationTests/MongoDBIntegrationTests/HybridSearch/MongoDBKeywordVectorizedHybridSearchTests.cs
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using MongoDBIntegrationTests.Support;
+using VectorDataSpecificationTests.HybridSearch;
+using VectorDataSpecificationTests.Support;
+using Xunit;
+
+namespace MongoDBIntegrationTests.HybridSearch;
+
+public class MongoDBKeywordVectorizedHybridSearchTests(
+ MongoDBKeywordVectorizedHybridSearchTests.VectorAndStringFixture vectorAndStringFixture,
+ MongoDBKeywordVectorizedHybridSearchTests.MultiTextFixture multiTextFixture)
+ : KeywordVectorizedHybridSearchComplianceTests(vectorAndStringFixture, multiTextFixture),
+ IClassFixture,
+ IClassFixture
+{
+ public new class VectorAndStringFixture : KeywordVectorizedHybridSearchComplianceTests.VectorAndStringFixture
+ {
+ public override TestStore TestStore => MongoDBTestStore.Instance;
+ }
+
+ public new class MultiTextFixture : KeywordVectorizedHybridSearchComplianceTests.MultiTextFixture
+ {
+ public override TestStore TestStore => MongoDBTestStore.Instance;
+ }
+}
diff --git a/dotnet/src/VectorDataIntegrationTests/QdrantIntegrationTests/HybridSearch/QdrantKeywordVectorizedHybridSearchTests_NamedVectors.cs b/dotnet/src/VectorDataIntegrationTests/QdrantIntegrationTests/HybridSearch/QdrantKeywordVectorizedHybridSearchTests_NamedVectors.cs
new file mode 100644
index 000000000000..86a878167626
--- /dev/null
+++ b/dotnet/src/VectorDataIntegrationTests/QdrantIntegrationTests/HybridSearch/QdrantKeywordVectorizedHybridSearchTests_NamedVectors.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using QdrantIntegrationTests.Support;
+using VectorDataSpecificationTests.HybridSearch;
+using VectorDataSpecificationTests.Support;
+using Xunit;
+
+namespace QdrantIntegrationTests.HybridSearch;
+
+public class QdrantKeywordVectorizedHybridSearchTests_NamedVectors(
+ QdrantKeywordVectorizedHybridSearchTests_NamedVectors.VectorAndStringFixture vectorAndStringFixture,
+ QdrantKeywordVectorizedHybridSearchTests_NamedVectors.MultiTextFixture multiTextFixture)
+ : KeywordVectorizedHybridSearchComplianceTests(vectorAndStringFixture, multiTextFixture),
+ IClassFixture,
+ IClassFixture
+{
+ public new class VectorAndStringFixture : KeywordVectorizedHybridSearchComplianceTests.VectorAndStringFixture
+ {
+ public override TestStore TestStore => QdrantTestStore.NamedVectorsInstance;
+
+ // Qdrant doesn't support the default Flat index kind
+ protected override string IndexKind => Microsoft.Extensions.VectorData.IndexKind.Hnsw;
+ }
+
+ public new class MultiTextFixture : KeywordVectorizedHybridSearchComplianceTests.MultiTextFixture
+ {
+ public override TestStore TestStore => QdrantTestStore.NamedVectorsInstance;
+
+ // Qdrant doesn't support the default Flat index kind
+ protected override string IndexKind => Microsoft.Extensions.VectorData.IndexKind.Hnsw;
+ }
+}
diff --git a/dotnet/src/VectorDataIntegrationTests/QdrantIntegrationTests/HybridSearch/QdrantKeywordVectorizedHybridSearchTests_UnnamedVectors.cs b/dotnet/src/VectorDataIntegrationTests/QdrantIntegrationTests/HybridSearch/QdrantKeywordVectorizedHybridSearchTests_UnnamedVectors.cs
new file mode 100644
index 000000000000..e9492cd7ef21
--- /dev/null
+++ b/dotnet/src/VectorDataIntegrationTests/QdrantIntegrationTests/HybridSearch/QdrantKeywordVectorizedHybridSearchTests_UnnamedVectors.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using QdrantIntegrationTests.Support;
+using VectorDataSpecificationTests.HybridSearch;
+using VectorDataSpecificationTests.Support;
+using Xunit;
+
+namespace QdrantIntegrationTests.HybridSearch;
+
+public class QdrantKeywordVectorizedHybridSearchTests_UnnamedVectors(
+ QdrantKeywordVectorizedHybridSearchTests_UnnamedVectors.VectorAndStringFixture vectorAndStringFixture,
+ QdrantKeywordVectorizedHybridSearchTests_UnnamedVectors.MultiTextFixture multiTextFixture)
+ : KeywordVectorizedHybridSearchComplianceTests(vectorAndStringFixture, multiTextFixture),
+ IClassFixture,
+ IClassFixture
+{
+ public new class VectorAndStringFixture : KeywordVectorizedHybridSearchComplianceTests.VectorAndStringFixture
+ {
+ public override TestStore TestStore => QdrantTestStore.UnnamedVectorInstance;
+
+ // Qdrant doesn't support the default Flat index kind
+ protected override string IndexKind => Microsoft.Extensions.VectorData.IndexKind.Hnsw;
+ }
+
+ public new class MultiTextFixture : KeywordVectorizedHybridSearchComplianceTests.MultiTextFixture
+ {
+ public override TestStore TestStore => QdrantTestStore.UnnamedVectorInstance;
+
+ // Qdrant doesn't support the default Flat index kind
+ protected override string IndexKind => Microsoft.Extensions.VectorData.IndexKind.Hnsw;
+ }
+}
diff --git a/dotnet/src/VectorDataIntegrationTests/VectorDataIntegrationTests/HybridSearch/KeywordVectorizedHybridSearchComplianceTests.cs b/dotnet/src/VectorDataIntegrationTests/VectorDataIntegrationTests/HybridSearch/KeywordVectorizedHybridSearchComplianceTests.cs
new file mode 100644
index 000000000000..c25bb065ba74
--- /dev/null
+++ b/dotnet/src/VectorDataIntegrationTests/VectorDataIntegrationTests/HybridSearch/KeywordVectorizedHybridSearchComplianceTests.cs
@@ -0,0 +1,278 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Microsoft.Extensions.VectorData;
+using VectorDataSpecificationTests.Support;
+using VectorDataSpecificationTests.Xunit;
+using Xunit;
+
+namespace VectorDataSpecificationTests.HybridSearch;
+
+///
+/// Base class for common integration tests that should pass for any .
+///
+/// The type of key to use with the record collection.
+public abstract class KeywordVectorizedHybridSearchComplianceTests(
+ KeywordVectorizedHybridSearchComplianceTests.VectorAndStringFixture vectorAndStringFixture,
+ KeywordVectorizedHybridSearchComplianceTests.MultiTextFixture multiTextFixture)
+ where TKey : notnull
+{
+ protected virtual int DelayAfterIndexCreateInMilliseconds { get; } = 0;
+
+ [ConditionalFact]
+ public async Task SearchShouldReturnExpectedResultsAsync()
+ {
+ // Arrange
+ var hybridSearch = vectorAndStringFixture.Collection as IKeywordHybridSearch>;
+
+ var vector = new ReadOnlyMemory([1, 0, 0, 0]);
+
+ // Act
+ // All records have the same vector, but the third contains Grapes, so searching for
+ // Grapes should return the third record first.
+ var searchResult = await hybridSearch!.HybridSearchAsync(vector, ["Grapes"]);
+
+ // Assert
+ var results = await searchResult.Results.ToListAsync();
+ Assert.Equal(3, results.Count);
+
+ Assert.Equal(3, results[0].Record.Code);
+ }
+
+ [ConditionalFact]
+ public async Task SearchWithFilterShouldReturnExpectedResultsAsync()
+ {
+ // Arrange
+ var hybridSearch = vectorAndStringFixture.Collection as IKeywordHybridSearch>;
+
+ var vector = new ReadOnlyMemory([1, 0, 0, 0]);
+
+ // Act
+ // All records have the same vector, but the second contains Oranges, however
+ // adding the filter should limit the results to only the first.
+#pragma warning disable CS0618 // Type or member is obsolete
+ var options = new HybridSearchOptions>
+ {
+ OldFilter = new VectorSearchFilter().EqualTo("Code", 1)
+ };
+#pragma warning restore CS0618 // Type or member is obsolete
+ var searchResult = await hybridSearch!.HybridSearchAsync(vector, ["Oranges"], options);
+
+ // Assert
+ var results = await searchResult.Results.ToListAsync();
+ Assert.Single(results);
+
+ Assert.Equal(1, results[0].Record.Code);
+ }
+
+ [ConditionalFact]
+ public async Task SearchWithTopShouldReturnExpectedResultsAsync()
+ {
+ // Arrange
+ var hybridSearch = vectorAndStringFixture.Collection as IKeywordHybridSearch>;
+
+ var vector = new ReadOnlyMemory([1, 0, 0, 0]);
+
+ // Act
+ // All records have the same vector, but the second contains Oranges, so the
+ // second should be returned first.
+ var searchResult = await hybridSearch!.HybridSearchAsync(vector, ["Oranges"], new() { Top = 1 });
+
+ // Assert
+ var results = await searchResult.Results.ToListAsync();
+ Assert.Single(results);
+
+ Assert.Equal(2, results[0].Record.Code);
+ }
+
+ [ConditionalFact]
+ public async Task SearchWithSkipShouldReturnExpectedResultsAsync()
+ {
+ // Arrange
+ var hybridSearch = vectorAndStringFixture.Collection as IKeywordHybridSearch>;
+
+ var vector = new ReadOnlyMemory([1, 0, 0, 0]);
+
+ // Act
+ // All records have the same vector, but the first and third contain healthy,
+ // so when skipping the first two results, we should get the second record.
+ var searchResult = await hybridSearch!.HybridSearchAsync(vector, ["healthy"], new() { Skip = 2 });
+
+ // Assert
+ var results = await searchResult.Results.ToListAsync();
+ Assert.Single(results);
+
+ Assert.Equal(2, results[0].Record.Code);
+ }
+
+ [ConditionalFact]
+ public async Task SearchWithMultipleKeywordsShouldRankMatchedKeywordsHigherAsync()
+ {
+ // Arrange
+ var hybridSearch = vectorAndStringFixture.Collection as IKeywordHybridSearch>;
+
+ var vector = new ReadOnlyMemory([1, 0, 0, 0]);
+
+ // Act
+ var searchResult = await hybridSearch!.HybridSearchAsync(vector, ["tangy", "nourishing"]);
+
+ // Assert
+ var results = await searchResult.Results.ToListAsync();
+ Assert.Equal(3, results.Count);
+
+ Assert.True(results[0].Record.Code.Equals(1) || results[0].Record.Code.Equals(2));
+ Assert.True(results[1].Record.Code.Equals(1) || results[1].Record.Code.Equals(2));
+ Assert.Equal(3, results[2].Record.Code);
+ }
+
+ [ConditionalFact]
+ public async Task SearchWithMultiTextRecordSearchesRequestedFieldAsync()
+ {
+ // Arrange
+ var hybridSearch = multiTextFixture.Collection as IKeywordHybridSearch>;
+
+ var vector = new ReadOnlyMemory([1, 0, 0, 0]);
+
+ // Act
+ var searchResult1 = await hybridSearch!.HybridSearchAsync(vector, ["Apples"], new() { AdditionalProperty = r => r.Text2 });
+ var searchResult2 = await hybridSearch!.HybridSearchAsync(vector, ["Oranges"], new() { AdditionalProperty = r => r.Text2 });
+
+ // Assert
+ var results1 = await searchResult1.Results.ToListAsync();
+ Assert.Equal(2, results1.Count);
+
+ Assert.Equal(2, results1[0].Record.Code);
+ Assert.Equal(1, results1[1].Record.Code);
+
+ var results2 = await searchResult2.Results.ToListAsync();
+ Assert.Equal(2, results2.Count);
+
+ Assert.Equal(1, results2[0].Record.Code);
+ Assert.Equal(2, results2[1].Record.Code);
+ }
+
+ public sealed class VectorAndStringRecord
+ {
+ public TRecordKey Key { get; set; } = default!;
+
+ public string Text { get; set; } = string.Empty;
+
+ public int Code { get; set; }
+
+ public ReadOnlyMemory Vector { get; set; }
+ }
+
+ public sealed class MultiTextStringRecord
+ {
+ public TRecordKey Key { get; set; } = default!;
+
+ public string Text1 { get; set; } = string.Empty;
+
+ public string Text2 { get; set; } = string.Empty;
+
+ public int Code { get; set; }
+
+ public ReadOnlyMemory Vector { get; set; }
+ }
+
+ public abstract class VectorAndStringFixture : VectorStoreCollectionFixture>
+ {
+ protected override string CollectionName => "KeywordHybridSearch" + this.GetUniqueCollectionName();
+
+ protected override VectorStoreRecordDefinition GetRecordDefinition()
+ => new()
+ {
+ Properties = new List()
+ {
+ new VectorStoreRecordKeyProperty("Key", typeof(TKey)),
+ new VectorStoreRecordDataProperty("Text", typeof(string)) { IsFullTextSearchable = true },
+ new VectorStoreRecordDataProperty("Code", typeof(int)) { IsFilterable = true },
+ new VectorStoreRecordVectorProperty("Vector", typeof(ReadOnlyMemory)) { Dimensions = 4, IndexKind = this.IndexKind },
+ }
+ };
+
+ protected override List> BuildTestData()
+ {
+ // All records have the same vector - this fixture is about testing the full text search portion of hybrid search
+ var vector = new ReadOnlyMemory([1, 0, 0, 0]);
+
+ return
+ [
+ new()
+ {
+ Key = this.GenerateNextKey(),
+ Text = "Apples are a healthy and nourishing snack",
+ Vector = vector,
+ Code = 1
+ },
+ new()
+ {
+ Key = this.GenerateNextKey(),
+ Text = "Oranges are tangy and contain vitamin c",
+ Vector = vector,
+ Code = 2
+ },
+ new()
+ {
+ Key = this.GenerateNextKey(),
+ Text = "Grapes are healthy, sweet and juicy",
+ Vector = vector,
+ Code = 3
+ }
+ ];
+ }
+
+ // In some databases (Azure AI Search), the data shows up but the filtering index isn't yet updated,
+ // so filtered searches show empty results. Add a filter to the seed data check below.
+ protected override Task WaitForDataAsync()
+ => this.TestStore.WaitForDataAsync(this.Collection, recordCount: this.TestData.Count, vectorSize: 4);
+ }
+
+ public abstract class MultiTextFixture : VectorStoreCollectionFixture>
+ {
+ protected override string CollectionName => "KeywordHybridSearch" + this.GetUniqueCollectionName();
+
+ protected override VectorStoreRecordDefinition GetRecordDefinition()
+ => new()
+ {
+ Properties = new List()
+ {
+ new VectorStoreRecordKeyProperty("Key", typeof(TKey)),
+ new VectorStoreRecordDataProperty("Text1", typeof(string)) { IsFullTextSearchable = true },
+ new VectorStoreRecordDataProperty("Text2", typeof(string)) { IsFullTextSearchable = true },
+ new VectorStoreRecordDataProperty("Code", typeof(int)) { IsFilterable = true },
+ new VectorStoreRecordVectorProperty("Vector", typeof(ReadOnlyMemory)) { Dimensions = 4, IndexKind = this.IndexKind },
+ }
+ };
+
+ protected override List> BuildTestData()
+ {
+ // All records have the same vector - this fixture is about testing the full text search portion of hybrid search
+ var vector = new ReadOnlyMemory([1, 0, 0, 0]);
+
+ return
+ [
+ new()
+ {
+ Key = this.GenerateNextKey(),
+ Text1 = "Apples",
+ Text2 = "Oranges",
+ Code = 1,
+ Vector = vector
+ },
+ new()
+ {
+ Key = this.GenerateNextKey(),
+ Text1 = "Oranges",
+ Text2 = "Apples",
+ Code = 2,
+ Vector = vector
+ }
+ ];
+ }
+
+ // In some databases (Azure AI Search), the data shows up but the filtering index isn't yet updated,
+ // so filtered searches show empty results. Add a filter to the seed data check below.
+ protected override Task WaitForDataAsync()
+ => this.TestStore.WaitForDataAsync(this.Collection, recordCount: this.TestData.Count, vectorSize: 4);
+ }
+}
diff --git a/dotnet/src/VectorDataIntegrationTests/VectorDataIntegrationTests/Support/TestStore.cs b/dotnet/src/VectorDataIntegrationTests/VectorDataIntegrationTests/Support/TestStore.cs
index bff2f583633e..cd92e070abf8 100644
--- a/dotnet/src/VectorDataIntegrationTests/VectorDataIntegrationTests/Support/TestStore.cs
+++ b/dotnet/src/VectorDataIntegrationTests/VectorDataIntegrationTests/Support/TestStore.cs
@@ -72,13 +72,20 @@ _ when typeof(TKey) == typeof(Guid) => (TKey)(object)new Guid($"00000000-0000-00
public virtual async Task WaitForDataAsync(
IVectorStoreRecordCollection collection,
int recordCount,
- Expression>? filter = null)
+ Expression>? filter = null,
+ int vectorSize = 3)
where TKey : notnull
{
+ var vector = new float[vectorSize];
+ for (var i = 0; i < vectorSize; i++)
+ {
+ vector[i] = 1.0f;
+ }
+
for (var i = 0; i < 20; i++)
{
var results = await collection.VectorizedSearchAsync(
- new ReadOnlyMemory([1, 2, 3]),
+ new ReadOnlyMemory(vector),
new()
{
Top = recordCount,
diff --git a/dotnet/src/VectorDataIntegrationTests/WeaviateIntegrationTests/HybridSearch/WeaviateKeywordVectorizedHybridSearchTests.cs b/dotnet/src/VectorDataIntegrationTests/WeaviateIntegrationTests/HybridSearch/WeaviateKeywordVectorizedHybridSearchTests.cs
new file mode 100644
index 000000000000..30d6bc0516f5
--- /dev/null
+++ b/dotnet/src/VectorDataIntegrationTests/WeaviateIntegrationTests/HybridSearch/WeaviateKeywordVectorizedHybridSearchTests.cs
@@ -0,0 +1,34 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using VectorDataSpecificationTests.HybridSearch;
+using VectorDataSpecificationTests.Support;
+using WeaviateIntegrationTests.Support;
+using Xunit;
+
+namespace WeaviateIntegrationTests.HybridSearch;
+
+public class WeaviateKeywordVectorizedHybridSearchTests(
+ WeaviateKeywordVectorizedHybridSearchTests.VectorAndStringFixture vectorAndStringFixture,
+ WeaviateKeywordVectorizedHybridSearchTests.MultiTextFixture multiTextFixture)
+ : KeywordVectorizedHybridSearchComplianceTests(vectorAndStringFixture, multiTextFixture),
+ IClassFixture,
+ IClassFixture
+{
+ public new class VectorAndStringFixture : KeywordVectorizedHybridSearchComplianceTests.VectorAndStringFixture
+ {
+ public override TestStore TestStore => WeaviateTestStore.Instance;
+
+ protected override string DistanceFunction => Microsoft.Extensions.VectorData.DistanceFunction.CosineDistance;
+
+ protected override string CollectionName => "VectorAndStringHybridSearch";
+ }
+
+ public new class MultiTextFixture : KeywordVectorizedHybridSearchComplianceTests.MultiTextFixture
+ {
+ public override TestStore TestStore => WeaviateTestStore.Instance;
+
+ protected override string DistanceFunction => Microsoft.Extensions.VectorData.DistanceFunction.CosineDistance;
+
+ protected override string CollectionName => "MultiTextHybridSearch";
+ }
+}