Skip to content

Commit 1b4bf13

Browse files
committed
Cleanup around vector in Cosmos
- remove experimental from vector APIs, - renamed vector index model builder method from ForVector to IsVectorIndex, - renamed vector property model builder method from IsVector to IsVectorProperty, - use helper methods rather than extracting annotations directly in validation, Fixes #35895 Fixes #35886 Fixes #35897
1 parent 62a94cb commit 1b4bf13

20 files changed

+205
-243
lines changed

Diff for: src/EFCore.Cosmos/EFCore.Cosmos.csproj

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
<ImplicitUsings>true</ImplicitUsings>
1212
<NoWarn>$(NoWarn);EF9101</NoWarn> <!-- Metrics is experimental -->
1313
<NoWarn>$(NoWarn);EF9102</NoWarn> <!-- Paging is experimental -->
14-
<NoWarn>$(NoWarn);EF9103</NoWarn> <!-- Vector search is experimental -->
1514
</PropertyGroup>
1615

1716
<ItemGroup>

Diff for: src/EFCore.Cosmos/Extensions/CosmosDbFunctionsExtensions.cs

+3-12
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,12 @@ public static double Rrf(this DbFunctions _, params double[] functions)
104104
/// <summary>
105105
/// Returns the distance between two vectors, using the distance function and data type defined using
106106
/// <see
107-
/// cref="CosmosPropertyBuilderExtensions.IsVector(Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder,Microsoft.Azure.Cosmos.DistanceFunction,int)" />
107+
/// cref="CosmosPropertyBuilderExtensions.IsVectorProperty(Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder,Microsoft.Azure.Cosmos.DistanceFunction,int)" />
108108
/// .
109109
/// </summary>
110110
/// <param name="_">The <see cref="DbFunctions" /> instance.</param>
111111
/// <param name="vector1">The first vector.</param>
112112
/// <param name="vector2">The second vector.</param>
113-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
114113
public static double VectorDistance(this DbFunctions _, ReadOnlyMemory<byte> vector1, ReadOnlyMemory<byte> vector2)
115114
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(VectorDistance)));
116115

@@ -125,7 +124,6 @@ public static double VectorDistance(this DbFunctions _, ReadOnlyMemory<byte> vec
125124
/// expression. If <see langword="true" />, then brute force is used, otherwise any index defined on the vector
126125
/// property is leveraged.
127126
/// </param>
128-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
129127
public static double VectorDistance(
130128
this DbFunctions _,
131129
ReadOnlyMemory<byte> vector1,
@@ -145,7 +143,6 @@ public static double VectorDistance(
145143
/// expression. If <see langword="true" />, then brute force is used, otherwise any index defined on the vector
146144
/// property is leveraged.
147145
/// </param>
148-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
149146
public static double VectorDistance(
150147
this DbFunctions _,
151148
ReadOnlyMemory<byte> vector1,
@@ -157,13 +154,12 @@ public static double VectorDistance(
157154
/// <summary>
158155
/// Returns the distance between two vectors, using the distance function and data type defined using
159156
/// <see
160-
/// cref="CosmosPropertyBuilderExtensions.IsVector(Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder,Microsoft.Azure.Cosmos.DistanceFunction,int)" />
157+
/// cref="CosmosPropertyBuilderExtensions.IsVectorProperty(Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder,Microsoft.Azure.Cosmos.DistanceFunction,int)" />
161158
/// .
162159
/// </summary>
163160
/// <param name="_">The <see cref="DbFunctions" /> instance.</param>
164161
/// <param name="vector1">The first vector.</param>
165162
/// <param name="vector2">The second vector.</param>
166-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
167163
public static double VectorDistance(this DbFunctions _, ReadOnlyMemory<sbyte> vector1, ReadOnlyMemory<sbyte> vector2)
168164
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(VectorDistance)));
169165

@@ -178,7 +174,6 @@ public static double VectorDistance(this DbFunctions _, ReadOnlyMemory<sbyte> ve
178174
/// expression. If <see langword="true" />, then brute force is used, otherwise any index defined on the vector
179175
/// property is leveraged.
180176
/// </param>
181-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
182177
public static double VectorDistance(
183178
this DbFunctions _,
184179
ReadOnlyMemory<sbyte> vector1,
@@ -198,7 +193,6 @@ public static double VectorDistance(
198193
/// expression. If <see langword="true" />, then brute force is used, otherwise any index defined on the vector
199194
/// property is leveraged.
200195
/// </param>
201-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
202196
public static double VectorDistance(
203197
this DbFunctions _,
204198
ReadOnlyMemory<sbyte> vector1,
@@ -210,13 +204,12 @@ public static double VectorDistance(
210204
/// <summary>
211205
/// Returns the distance between two vectors, using the distance function and data type defined using
212206
/// <see
213-
/// cref="CosmosPropertyBuilderExtensions.IsVector(Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder,Microsoft.Azure.Cosmos.DistanceFunction,int)" />
207+
/// cref="CosmosPropertyBuilderExtensions.IsVectorProperty(Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder,Microsoft.Azure.Cosmos.DistanceFunction,int)" />
214208
/// .
215209
/// </summary>
216210
/// <param name="_">The <see cref="DbFunctions" /> instance.</param>
217211
/// <param name="vector1">The first vector.</param>
218212
/// <param name="vector2">The second vector.</param>
219-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
220213
public static double VectorDistance(this DbFunctions _, ReadOnlyMemory<float> vector1, ReadOnlyMemory<float> vector2)
221214
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(VectorDistance)));
222215

@@ -231,7 +224,6 @@ public static double VectorDistance(this DbFunctions _, ReadOnlyMemory<float> ve
231224
/// expression. If <see langword="true" />, then brute force is used, otherwise any index defined on the vector
232225
/// property is leveraged.
233226
/// </param>
234-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
235227
public static double VectorDistance(
236228
this DbFunctions _,
237229
ReadOnlyMemory<float> vector1,
@@ -251,7 +243,6 @@ public static double VectorDistance(
251243
/// expression. If <see langword="true" />, then brute force is used, otherwise any index defined on the vector
252244
/// property is leveraged.
253245
/// </param>
254-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
255246
public static double VectorDistance(
256247
this DbFunctions _,
257248
ReadOnlyMemory<float> vector1,

Diff for: src/EFCore.Cosmos/Extensions/CosmosIndexBuilderExtensions.cs

+4-8
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ public static class CosmosIndexBuilderExtensions
2727
/// <param name="indexBuilder">The builder for the index being configured.</param>
2828
/// <param name="indexType">The type of vector index to create.</param>
2929
/// <returns>A builder to further configure the index.</returns>
30-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
31-
public static IndexBuilder ForVectors(this IndexBuilder indexBuilder, VectorIndexType? indexType)
30+
public static IndexBuilder IsVectorIndex(this IndexBuilder indexBuilder, VectorIndexType? indexType)
3231
{
3332
indexBuilder.Metadata.SetVectorIndexType(indexType);
3433

@@ -46,11 +45,10 @@ public static IndexBuilder ForVectors(this IndexBuilder indexBuilder, VectorInde
4645
/// <param name="indexBuilder">The builder for the index being configured.</param>
4746
/// <param name="indexType">The type of vector index to create.</param>
4847
/// <returns>A builder to further configure the index.</returns>
49-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
50-
public static IndexBuilder<TEntity> ForVectors<TEntity>(
48+
public static IndexBuilder<TEntity> IsVectorIndex<TEntity>(
5149
this IndexBuilder<TEntity> indexBuilder,
5250
VectorIndexType? indexType)
53-
=> (IndexBuilder<TEntity>)ForVectors((IndexBuilder)indexBuilder, indexType);
51+
=> (IndexBuilder<TEntity>)IsVectorIndex((IndexBuilder)indexBuilder, indexType);
5452

5553
/// <summary>
5654
/// Configures whether the index as a vector index with the given vector index type, such as "flat", "diskANN", or "quantizedFlat".
@@ -67,8 +65,7 @@ public static IndexBuilder<TEntity> ForVectors<TEntity>(
6765
/// The same builder instance if the configuration was applied,
6866
/// <see langword="null" /> otherwise.
6967
/// </returns>
70-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
71-
public static IConventionIndexBuilder? ForVectors(
68+
public static IConventionIndexBuilder? IsVectorIndex(
7269
this IConventionIndexBuilder indexBuilder,
7370
VectorIndexType? indexType,
7471
bool fromDataAnnotation = false)
@@ -93,7 +90,6 @@ public static IndexBuilder<TEntity> ForVectors<TEntity>(
9390
/// <param name="indexType">The index type to use.</param>
9491
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
9592
/// <returns><see langword="true" /> if the index can be configured for vectors.</returns>
96-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
9793
public static bool CanSetVectorIndexType(
9894
this IConventionIndexBuilder indexBuilder,
9995
VectorIndexType? indexType,

Diff for: src/EFCore.Cosmos/Extensions/CosmosIndexExtensions.cs

-4
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ public static class CosmosIndexExtensions
2222
/// </summary>
2323
/// <param name="index">The index.</param>
2424
/// <returns>The index type to use, or <see langword="null" /> if none is set.</returns>
25-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
2625
public static VectorIndexType? GetVectorIndexType(this IReadOnlyIndex index)
2726
=> (index is RuntimeIndex)
2827
? throw new InvalidOperationException(CoreStrings.RuntimeModelMissingData)
@@ -34,7 +33,6 @@ public static class CosmosIndexExtensions
3433
/// </summary>
3534
/// <param name="index">The index.</param>
3635
/// <param name="indexType">The index type to use.</param>
37-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
3836
public static void SetVectorIndexType(this IMutableIndex index, VectorIndexType? indexType)
3937
=> index.SetAnnotation(CosmosAnnotationNames.VectorIndexType, indexType);
4038

@@ -46,7 +44,6 @@ public static void SetVectorIndexType(this IMutableIndex index, VectorIndexType?
4644
/// <param name="index">The index.</param>
4745
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
4846
/// <returns>The configured value.</returns>
49-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
5047
public static string? SetVectorIndexType(
5148
this IConventionIndex index,
5249
VectorIndexType? indexType,
@@ -61,7 +58,6 @@ public static void SetVectorIndexType(this IMutableIndex index, VectorIndexType?
6158
/// </summary>
6259
/// <param name="property">The property.</param>
6360
/// <returns>The <see cref="ConfigurationSource" /> for whether the index is clustered.</returns>
64-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
6561
public static ConfigurationSource? GetVectorIndexTypeConfigurationSource(this IConventionIndex property)
6662
=> property.FindAnnotation(CosmosAnnotationNames.VectorIndexType)?.GetConfigurationSource();
6763

Diff for: src/EFCore.Cosmos/Extensions/CosmosPropertyBuilderExtensions.cs

+6-11
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,7 @@ public static bool CanSetJsonProperty(
116116
/// <param name="distanceFunction">The distance function for a vector comparisons.</param>
117117
/// <param name="dimensions">The number of dimensions in the vector.</param>
118118
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
119-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
120-
public static PropertyBuilder IsVector(
119+
public static PropertyBuilder IsVectorProperty(
121120
this PropertyBuilder propertyBuilder,
122121
DistanceFunction distanceFunction,
123122
int dimensions)
@@ -142,12 +141,11 @@ public static PropertyBuilder IsVector(
142141
/// <param name="distanceFunction">The distance function for a vector comparisons.</param>
143142
/// <param name="dimensions">The number of dimensions in the vector.</param>
144143
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
145-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
146-
public static PropertyBuilder<TProperty> IsVector<TProperty>(
144+
public static PropertyBuilder<TProperty> IsVectorProperty<TProperty>(
147145
this PropertyBuilder<TProperty> propertyBuilder,
148146
DistanceFunction distanceFunction,
149147
int dimensions)
150-
=> (PropertyBuilder<TProperty>)IsVector((PropertyBuilder)propertyBuilder, distanceFunction, dimensions);
148+
=> (PropertyBuilder<TProperty>)IsVectorProperty((PropertyBuilder)propertyBuilder, distanceFunction, dimensions);
151149

152150
/// <summary>
153151
/// Configures the property as a vector for Azure Cosmos DB.
@@ -164,14 +162,13 @@ public static PropertyBuilder<TProperty> IsVector<TProperty>(
164162
/// The same builder instance if the configuration was applied,
165163
/// <see langword="null" /> otherwise.
166164
/// </returns>
167-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
168-
public static IConventionPropertyBuilder? IsVector(
165+
public static IConventionPropertyBuilder? IsVectorProperty(
169166
this IConventionPropertyBuilder propertyBuilder,
170167
DistanceFunction distanceFunction,
171168
int dimensions,
172169
bool fromDataAnnotation = false)
173170
{
174-
if (!propertyBuilder.CanSetIsVector(distanceFunction, dimensions, fromDataAnnotation))
171+
if (!propertyBuilder.CanSetIsVectorProperty(distanceFunction, dimensions, fromDataAnnotation))
175172
{
176173
return null;
177174
}
@@ -193,8 +190,7 @@ public static PropertyBuilder<TProperty> IsVector<TProperty>(
193190
/// <param name="dimensions">The number of dimensions in the vector.</param>
194191
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
195192
/// <returns><see langword="true" /> if the vector type can be set.</returns>
196-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
197-
public static bool CanSetIsVector(
193+
public static bool CanSetIsVectorProperty(
198194
this IConventionPropertyBuilder propertyBuilder,
199195
DistanceFunction distanceFunction,
200196
int dimensions,
@@ -237,7 +233,6 @@ public static PropertyBuilder<TProperty> IsETagConcurrency<TProperty>(
237233
this PropertyBuilder<TProperty> propertyBuilder)
238234
=> (PropertyBuilder<TProperty>)IsETagConcurrency((PropertyBuilder)propertyBuilder);
239235

240-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
241236
private static CosmosVectorType CreateVectorType(DistanceFunction distanceFunction, int dimensions)
242237
=> Enum.IsDefined(distanceFunction)
243238
? new CosmosVectorType(distanceFunction, dimensions)

Diff for: src/EFCore.Cosmos/Extensions/CosmosPropertyExtensions.cs

-4
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ public static void SetJsonPropertyName(this IMutableProperty property, string? n
8888
/// </summary>
8989
/// <param name="property">The property.</param>
9090
/// <returns>Returns the definition of the vector stored in this property.</returns>
91-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
9291
public static CosmosVectorType? GetVectorType(this IReadOnlyProperty property)
9392
=> (CosmosVectorType?)property[CosmosAnnotationNames.VectorType];
9493

@@ -97,7 +96,6 @@ public static void SetJsonPropertyName(this IMutableProperty property, string? n
9796
/// </summary>
9897
/// <param name="property">The property.</param>
9998
/// <param name="vectorType">The type of vector stored in the property.</param>
100-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
10199
public static void SetVectorType(this IMutableProperty property, CosmosVectorType? vectorType)
102100
=> property.SetOrRemoveAnnotation(CosmosAnnotationNames.VectorType, vectorType);
103101

@@ -108,7 +106,6 @@ public static void SetVectorType(this IMutableProperty property, CosmosVectorTyp
108106
/// <param name="vectorType">The type of vector stored in the property.</param>
109107
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
110108
/// <returns>The configured value.</returns>
111-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
112109
public static CosmosVectorType? SetVectorType(
113110
this IConventionProperty property,
114111
CosmosVectorType? vectorType,
@@ -125,7 +122,6 @@ public static void SetVectorType(this IMutableProperty property, CosmosVectorTyp
125122
/// <returns>
126123
/// The <see cref="ConfigurationSource" /> for the definition of the vector stored in this property.
127124
/// </returns>
128-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
129125
public static ConfigurationSource? GetVectorTypeConfigurationSource(this IConventionProperty property)
130126
=> property.FindAnnotation(CosmosAnnotationNames.VectorType)?.GetConfigurationSource();
131127

Diff for: src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs

+20-4
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ protected virtual void ValidateIndexes(
574574
{
575575
foreach (var index in entityType.GetDeclaredIndexes())
576576
{
577-
if (index.FindAnnotation(CosmosAnnotationNames.VectorIndexType) != null)
577+
if (index.GetVectorIndexType() != null)
578578
{
579579
if (index.Properties.Count > 1)
580580
{
@@ -584,7 +584,7 @@ protected virtual void ValidateIndexes(
584584
string.Join(",", index.Properties.Select(e => e.Name))));
585585
}
586586

587-
if (index.Properties[0].FindAnnotation(CosmosAnnotationNames.VectorType) == null)
587+
if (index.Properties[0].GetVectorType() == null)
588588
{
589589
throw new InvalidOperationException(
590590
CosmosStrings.VectorIndexOnNonVector(
@@ -594,7 +594,14 @@ protected virtual void ValidateIndexes(
594594
}
595595
else if (index.IsFullTextIndex() == true)
596596
{
597-
// composite vector validation is done during container creation
597+
if (index.Properties.Count > 1)
598+
{
599+
throw new InvalidOperationException(
600+
CosmosStrings.CompositeFullTextIndex(
601+
index.DeclaringEntityType.DisplayName(),
602+
string.Join(",", index.Properties.Select(e => e.Name))));
603+
}
604+
598605
if (index.Properties[0].GetIsFullTextSearchEnabled() != true)
599606
{
600607
throw new InvalidOperationException(
@@ -621,7 +628,6 @@ protected virtual void ValidateIndexes(
621628
/// any release. You should only use it directly in your code with extreme caution and knowing that
622629
/// doing so can result in application failures when updating to a new Entity Framework Core release.
623630
/// </summary>
624-
[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
625631
protected override void ValidatePropertyMapping(
626632
IModel model,
627633
IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
@@ -638,6 +644,16 @@ protected override void ValidatePropertyMapping(
638644
// Will throw if the data type is not set and cannot be inferred.
639645
CosmosVectorType.CreateDefaultVectorDataType(property.ClrType);
640646
}
647+
648+
if (property.GetIsFullTextSearchEnabled() == true
649+
&& property.ClrType != typeof(string))
650+
{
651+
throw new InvalidOperationException(
652+
CosmosStrings.FullTextSearchConfiguredForUnsupportedPropertyType(
653+
property.DeclaringType.DisplayName(),
654+
property.Name,
655+
property.ClrType.Name));
656+
}
641657
}
642658
}
643659
}

0 commit comments

Comments
 (0)