Skip to content

Commit f812815

Browse files
authored
[Search] Vector Search Updates For August Preview (Azure#37948)
Vector Search updates
1 parent d7a8030 commit f812815

20 files changed

+359
-65
lines changed

sdk/search/Azure.Search.Documents/CHANGELOG.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
# Release History
22

3-
## 11.5.0-beta.4 (Unreleased)
3+
## 11.5.0-beta.4 (2023-08-07)
44

55
### Features Added
6-
7-
### Breaking Changes
8-
9-
### Bugs Fixed
10-
11-
### Other Changes
6+
- Added the ability to perform multiple vectors query searches.
7+
- Added support for vector queries over multiple fields.
128

139
## 11.5.0-beta.3 (2023-07-11)
1410

sdk/search/Azure.Search.Documents/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ foreach (SearchResult<SearchDocument> result in response.GetResults())
352352
SearchDocument doc = result.Document;
353353
string id = (string)doc["HotelId"];
354354
string name = (string)doc["HotelName"];
355-
Console.WriteLine("{id}: {name}");
355+
Console.WriteLine($"{id}: {name}");
356356
}
357357
```
358358

sdk/search/Azure.Search.Documents/api/Azure.Search.Documents.netstandard2.0.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ public SearchOptions() { }
173173
public string SessionId { get { throw null; } set { } }
174174
public int? Size { get { throw null; } set { } }
175175
public int? Skip { get { throw null; } set { } }
176-
public Azure.Search.Documents.Models.SearchQueryVector Vector { get { throw null; } set { } }
176+
public System.Collections.Generic.IList<Azure.Search.Documents.Models.SearchQueryVector> Vectors { get { throw null; } }
177177
}
178178
public partial class SuggestOptions
179179
{
@@ -210,6 +210,8 @@ public SearchableFieldAttribute() { }
210210
public string IndexAnalyzerName { get { throw null; } set { } }
211211
public string SearchAnalyzerName { get { throw null; } set { } }
212212
public string[] SynonymMapNames { get { throw null; } set { } }
213+
public string VectorSearchConfiguration { get { throw null; } set { } }
214+
public string VectorSearchDimensions { get { throw null; } set { } }
213215
}
214216
public partial class SearchIndexClient
215217
{
@@ -3282,7 +3284,6 @@ public static partial class SearchModelFactory
32823284
public static Azure.Search.Documents.Indexes.Models.SearchIndexerWarning SearchIndexerWarning(string key, string message, string name, string details, string documentationLink) { throw null; }
32833285
public static Azure.Search.Documents.Indexes.Models.SearchIndexStatistics SearchIndexStatistics(long documentCount, long storageSize) { throw null; }
32843286
public static Azure.Search.Documents.Indexes.Models.SearchIndexStatistics SearchIndexStatistics(long documentCount = (long)0, long storageSize = (long)0, long? vectorIndexSize = default(long?)) { throw null; }
3285-
public static Azure.Search.Documents.Models.SearchQueryVector SearchQueryVector(System.Collections.Generic.IEnumerable<float> value = null, int? kNearestNeighborsCount = default(int?), string fields = null) { throw null; }
32863287
public static Azure.Search.Documents.Indexes.Models.SearchResourceCounter SearchResourceCounter(long usage, long? quota) { throw null; }
32873288
public static Azure.Search.Documents.Models.SearchResultsPage<T> SearchResultsPage<T>(Azure.Search.Documents.Models.SearchResults<T> results) { throw null; }
32883289
public static Azure.Search.Documents.Models.SearchResults<T> SearchResults<T>(System.Collections.Generic.IEnumerable<Azure.Search.Documents.Models.SearchResult<T>> values, long? totalCount, System.Collections.Generic.IDictionary<string, System.Collections.Generic.IList<Azure.Search.Documents.Models.FacetResult>> facets, double? coverage, Azure.Response rawResponse) { throw null; }
@@ -3311,7 +3312,7 @@ public enum SearchQueryType
33113312
public partial class SearchQueryVector
33123313
{
33133314
public SearchQueryVector() { }
3314-
public string Fields { get { throw null; } set { } }
3315+
public System.Collections.Generic.IList<string> Fields { get { throw null; } }
33153316
public int? KNearestNeighborsCount { get { throw null; } set { } }
33163317
public System.Collections.Generic.IReadOnlyList<float> Value { get { throw null; } set { } }
33173318
}

sdk/search/Azure.Search.Documents/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "net",
44
"TagPrefix": "net/search/Azure.Search.Documents",
5-
"Tag": "net/search/Azure.Search.Documents_a3427a4c81"
5+
"Tag": "net/search/Azure.Search.Documents_38f84358e8"
66
}

sdk/search/Azure.Search.Documents/samples/Sample07_VectorSearch.md

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ This sample will show you how to index a vector field and perform vector search
1010

1111
## Create a Vector Index
1212

13-
Let's consider the example of a `Hotel`. First, we need to create an index for storing hotel information. In this index, we will define a field called `DescriptionVector` as a vector field. To configure the vector field, you need to provide the model dimensions, which indicate the size of the embeddings generated for this field, and the name of the vector search algorithm configuration that specifies the algorithm and any optional parameters for searching the vector field. You can find detailed instructions on how to create a vector index in the [documentation](https://learn.microsoft.com/azure/search/vector-search-how-to-create-index).
13+
Let's consider the example of a `Hotel`. First, we need to create an index for storing hotel information. In this index, we will define vector fields called `DescriptionVector` and `CategoryVector`. To configure the vector field, you need to provide the model dimensions, which indicate the size of the embeddings generated for this field, and the name of the vector search algorithm configuration that specifies the algorithm and any optional parameters for searching the vector field. You can find detailed instructions on how to create a vector index in the [documentation](https://learn.microsoft.com/azure/search/vector-search-how-to-create-index).
1414

1515
We will create an instace of `SearchIndex` and define `Hotel` fields.
1616

@@ -32,7 +32,13 @@ SearchIndex searchIndex = new(indexName)
3232
VectorSearchDimensions = modelDimensions,
3333
VectorSearchConfiguration = vectorSearchConfigName
3434
},
35-
new SearchableField("Category") { IsFilterable = true, IsSortable = true, IsFacetable = true }
35+
new SearchableField("Category") { IsFilterable = true, IsSortable = true, IsFacetable = true },
36+
new SearchField("CategoryVector", SearchFieldDataType.Collection(SearchFieldDataType.Single))
37+
{
38+
IsSearchable = true,
39+
VectorSearchDimensions = modelDimensions,
40+
VectorSearchConfiguration = vectorSearchConfigName
41+
},
3642
},
3743
VectorSearch = new()
3844
{
@@ -67,6 +73,7 @@ public class Hotel
6773
public string Description { get; set; }
6874
public IReadOnlyList<float> DescriptionVector { get; set; }
6975
public string Category { get; set; }
76+
public IReadOnlyList<float> CategoryVector { get; set; }
7077
}
7178
```
7279

@@ -87,7 +94,7 @@ Embeddings embeddings = await openAIClient.GetEmbeddingsAsync("EmbeddingsModelNa
8794
IReadOnlyList<float> descriptionVector = embeddings.Data[0].Embedding;
8895
```
8996

90-
In the sample code below, we are using hardcoded embeddings for the `DescriptionVector` field:
97+
In the sample code below, we are using hardcoded embeddings for the vector fields named `DescriptionVector` and `CategoryVector`:
9198

9299
```C# Snippet:Azure_Search_Documents_Tests_Samples_Sample07_Vector_Search_Hotel_Document
93100
public static Hotel[] GetHotelDocuments()
@@ -104,6 +111,7 @@ public static Hotel[] GetHotelDocuments()
104111
"the tourist attractions. We highly recommend this hotel.",
105112
DescriptionVector = VectorSearchEmbeddings.Hotel1VectorizeDescription,
106113
Category = "Luxury",
114+
CategoryVector = VectorSearchEmbeddings.LuxuryVectorizeCategory
107115
},
108116
new Hotel()
109117
{
@@ -112,6 +120,7 @@ public static Hotel[] GetHotelDocuments()
112120
Description = "Cheapest hotel in town. Infact, a motel.",
113121
DescriptionVector = VectorSearchEmbeddings.Hotel2VectorizeDescription,
114122
Category = "Budget",
123+
CategoryVector = VectorSearchEmbeddings.BudgetVectorizeCategory
115124
},
116125
// Add more hotel documents here...
117126
};
@@ -142,7 +151,7 @@ IReadOnlyList<float> vectorizedResult = VectorSearchEmbeddings.SearchVectorizeDe
142151
SearchResults<Hotel> response = await searchClient.SearchAsync<Hotel>(null,
143152
new SearchOptions
144153
{
145-
Vector = new() { Value = vectorizedResult, KNearestNeighborsCount = 3, Fields = "DescriptionVector" },
154+
Vectors = { new() { Value = vectorizedResult, KNearestNeighborsCount = 3, Fields = { "DescriptionVector" } } },
146155
});
147156

148157
int count = 0;
@@ -166,7 +175,7 @@ IReadOnlyList<float> vectorizedResult = VectorSearchEmbeddings.SearchVectorizeDe
166175
SearchResults<Hotel> response = await searchClient.SearchAsync<Hotel>(null,
167176
new SearchOptions
168177
{
169-
Vector = new() { Value = vectorizedResult, KNearestNeighborsCount = 3, Fields = "DescriptionVector" },
178+
Vectors = { new() { Value = vectorizedResult, KNearestNeighborsCount = 3, Fields = { "DescriptionVector" } } },
170179
Filter = "Category eq 'Luxury'"
171180
});
172181

@@ -194,7 +203,7 @@ SearchResults<Hotel> response = await searchClient.SearchAsync<Hotel>(
194203
"Top hotels in town",
195204
new SearchOptions
196205
{
197-
Vector = new() { Value = vectorizedResult, KNearestNeighborsCount = 3, Fields = "DescriptionVector" },
206+
Vectors = { new() { Value = vectorizedResult, KNearestNeighborsCount = 3, Fields = { "DescriptionVector" } } },
198207
});
199208

200209
int count = 0;
@@ -247,7 +256,7 @@ SearchResults<Hotel> response = await searchClient.SearchAsync<Hotel>(
247256
"Is there any hotel located on the main commercial artery of the city in the heart of New York?",
248257
new SearchOptions
249258
{
250-
Vector = new SearchQueryVector { Value = vectorizedResult, KNearestNeighborsCount = 3, Fields = "descriptionVector" },
259+
Vectors = { new() { Value = vectorizedResult, KNearestNeighborsCount = 3, Fields = { "descriptionVector" } } },
251260
QueryType = SearchQueryType.Semantic,
252261
QueryLanguage = QueryLanguage.EnUs,
253262
SemanticConfigurationName = "my-semantic-config",
@@ -286,3 +295,58 @@ await foreach (SearchResult<Hotel> result in response.GetResultsAsync())
286295
}
287296
Console.WriteLine($"Total number of search results:{count}");
288297
```
298+
299+
### Multi-vector Search
300+
301+
You can search containing multiple query vectors using the `SearchOptions.Vectors` property. These queries will be executed concurrently in the search index, with each one searching for similarities in the target vector fields. The result set will be a combination of documents that matched both vector queries. One common use case for this query request is when using models like CLIP for a multi-modal vector search, where the same model can vectorize both image and non-image content.
302+
303+
```C# Snippet:Azure_Search_Documents_Tests_Samples_Sample07_Multi_Vector_Search
304+
IReadOnlyList<float> vectorizedDescriptionQuery = VectorSearchEmbeddings.SearchVectorizeDescription; // "Top hotels in town"
305+
IReadOnlyList<float> vectorizedCategoryQuery = VectorSearchEmbeddings.SearchVectorizeCategory; // "Luxury hotels in town"
306+
307+
SearchResults<Hotel> response = await searchClient.SearchAsync<Hotel>(null,
308+
new SearchOptions
309+
{
310+
Vectors = {
311+
new() { Value = vectorizedDescriptionQuery, KNearestNeighborsCount = 3, Fields = { "DescriptionVector" } },
312+
new() { Value = vectorizedCategoryQuery, KNearestNeighborsCount = 3, Fields = { "CategoryVector" } }
313+
},
314+
});
315+
316+
int count = 0;
317+
Console.WriteLine($"Multi Vector Search Results:");
318+
await foreach (SearchResult<Hotel> result in response.GetResultsAsync())
319+
{
320+
count++;
321+
Hotel doc = result.Document;
322+
Console.WriteLine($"{doc.HotelId}: {doc.HotelName}");
323+
}
324+
Console.WriteLine($"Total number of search results:{count}");
325+
```
326+
327+
### Multi-field Vector Search
328+
329+
You can set the `SearchOptions.Vectors.Fields` property to multiple vector fields. For example, we have vector fields named `DescriptionVector` and `CategoryVector`. Your vector query executes over both the `DescriptionVector` and `CategoryVector` fields, which must have the same embedding space since they share the same query vector.
330+
331+
```C# Snippet:Azure_Search_Documents_Tests_Samples_Sample07_Multi_Fields_Vector_Search
332+
IReadOnlyList<float> vectorizedResult = VectorSearchEmbeddings.SearchVectorizeDescription; // "Top hotels in town"
333+
334+
SearchResults<Hotel> response = await searchClient.SearchAsync<Hotel>(null,
335+
new SearchOptions
336+
{
337+
Vectors = { new() {
338+
Value = vectorizedResult,
339+
KNearestNeighborsCount = 3,
340+
Fields = { "DescriptionVector", "CategoryVector" } } }
341+
});
342+
343+
int count = 0;
344+
Console.WriteLine($"Multi Fields Vector Search Results:");
345+
await foreach (SearchResult<Hotel> result in response.GetResultsAsync())
346+
{
347+
count++;
348+
Hotel doc = result.Document;
349+
Console.WriteLine($"{doc.HotelId}: {doc.HotelName}");
350+
}
351+
Console.WriteLine($"Total number of search results:{count}");
352+
```

sdk/search/Azure.Search.Documents/src/Generated/Models/SearchOptions.Serialization.cs

Lines changed: 17 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)