Skip to content

Commit 2ea7192

Browse files
authored
Fix to #35983 - Cosmos/FTS: update translation of FullTextScore to use multiple keywords rather than keyword array (#35984)
* Fix to #35983 - Cosmos/FTS: update translation of FullTextScore to use multiple keywords rather than keyword array Reacting to Cosmos changing the signature of FullTextScore function. Fixes #35983
1 parent 3dddb18 commit 2ea7192

File tree

5 files changed

+72
-57
lines changed

5 files changed

+72
-57
lines changed

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
<PackageVersion Include="Microsoft.DotNet.Build.Tasks.Templating" Version="$(MicrosoftDotNetBuildTasksTemplatingVersion)" />
3838

3939
<!-- Azure SDK for .NET dependencies -->
40-
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.49.0-preview.0" />
40+
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.50.0-preview.0" />
4141

4242
<!-- SQL Server dependencies -->
4343
<PackageVersion Include="Microsoft.Data.SqlClient" Version="6.0.1" />

src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.ParameterInliner.cs

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -80,48 +80,29 @@ protected override Expression VisitExtension(Expression expression)
8080
}
8181

8282
// Inlines array parameter of full-text functions, transforming FullTextContainsAll(x, @keywordsArray) to FullTextContainsAll(x, keyword1, keyword2))
83+
// we do this for FullTextContainsAll, FullTextContainsAny and FullTextScore
8384
case SqlFunctionExpression
8485
{
85-
Name: "FullTextContainsAny" or "FullTextContainsAll",
86+
Name: string name,
87+
IsScoringFunction: bool scoringFunction,
8688
Arguments: [var property, SqlParameterExpression { TypeMapping: { ElementTypeMapping: var elementTypeMapping }, Type: Type type } keywords]
8789
} fullTextContainsAllAnyFunction
88-
when type == typeof(string[]):
90+
when (name is "FullTextContainsAny" or "FullTextContainsAll" or "FullTextScore") && type == typeof(string[]):
8991
{
9092
var keywordValues = new List<SqlExpression>();
9193
foreach (var value in (IEnumerable)parametersValues[keywords.Name])
9294
{
9395
keywordValues.Add(sqlExpressionFactory.Constant(value, typeof(string), elementTypeMapping));
9496
}
9597

96-
return sqlExpressionFactory.Function(
98+
return new SqlFunctionExpression(
9799
fullTextContainsAllAnyFunction.Name,
100+
scoringFunction,
98101
[property, .. keywordValues],
99102
fullTextContainsAllAnyFunction.Type,
100103
fullTextContainsAllAnyFunction.TypeMapping);
101104
}
102105

103-
// Inlines array parameter of full-text score, transforming FullTextScore(x, @keywordsArray) to FullTextScore(x, [keyword1, keyword2]))
104-
case SqlFunctionExpression
105-
{
106-
Name: "FullTextScore",
107-
IsScoringFunction: true,
108-
Arguments: [var property, SqlParameterExpression { TypeMapping: { ElementTypeMapping: not null } typeMapping } keywords]
109-
} fullTextScoreFunction:
110-
{
111-
var keywordValues = new List<string>();
112-
foreach (var value in (IEnumerable)parametersValues[keywords.Name])
113-
{
114-
keywordValues.Add((string)value);
115-
}
116-
117-
return new SqlFunctionExpression(
118-
fullTextScoreFunction.Name,
119-
scoringFunction: true,
120-
[property, sqlExpressionFactory.Constant(keywordValues, typeMapping)],
121-
fullTextScoreFunction.Type,
122-
fullTextScoreFunction.TypeMapping);
123-
}
124-
125106
default:
126107
return expression;
127108
}

src/EFCore.Cosmos/Query/Internal/Translators/CosmosFullTextSearchTranslator.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,25 @@ public class CosmosFullTextSearchTranslator(ISqlExpressionFactory sqlExpressionF
4141
typeMappingSource.FindMapping(typeof(bool))),
4242

4343
nameof(CosmosDbFunctionsExtensions.FullTextScore)
44-
when arguments is [_, var property, var keywords] => sqlExpressionFactory.ScoringFunction(
44+
when arguments is [_, SqlExpression property, SqlConstantExpression { Type: var keywordClrType, Value: string[] values } keywords]
45+
&& keywordClrType == typeof(string[]) => sqlExpressionFactory.ScoringFunction(
46+
"FullTextScore",
47+
[property, .. values.Select(x => sqlExpressionFactory.Constant(x))],
48+
typeof(double),
49+
typeMappingSource.FindMapping(typeof(double))),
50+
51+
nameof(CosmosDbFunctionsExtensions.FullTextScore)
52+
when arguments is [_, SqlExpression property, SqlParameterExpression { Type: var keywordClrType } keywords]
53+
&& keywordClrType == typeof(string[]) => sqlExpressionFactory.ScoringFunction(
54+
"FullTextScore",
55+
[property, keywords],
56+
typeof(double),
57+
typeMappingSource.FindMapping(typeof(double))),
58+
59+
nameof(CosmosDbFunctionsExtensions.FullTextScore)
60+
when arguments is [_, SqlExpression property, ArrayConstantExpression keywords] => sqlExpressionFactory.ScoringFunction(
4561
"FullTextScore",
46-
[
47-
property,
48-
keywords,
49-
],
62+
[property, .. keywords.Items],
5063
typeof(double),
5164
typeMappingSource.FindMapping(typeof(double))),
5265

test/EFCore.Cosmos.FunctionalTests/FullTextSearchCosmosTest.cs

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ public virtual async Task OrderByRank_FullTextScore_constant()
292292
"""
293293
SELECT VALUE c
294294
FROM root c
295-
ORDER BY RANK FullTextScore(c["Description"], ["otter"])
295+
ORDER BY RANK FullTextScore(c["Description"], "otter")
296296
""");
297297
}
298298

@@ -309,7 +309,7 @@ public virtual async Task OrderByRank_FullTextScore_constants()
309309
"""
310310
SELECT VALUE c
311311
FROM root c
312-
ORDER BY RANK FullTextScore(c["Description"], ["otter","beaver"])
312+
ORDER BY RANK FullTextScore(c["Description"], "otter", "beaver")
313313
""");
314314
}
315315

@@ -326,7 +326,7 @@ public virtual async Task OrderByRank_FullTextScore_constant_array()
326326
"""
327327
SELECT VALUE c
328328
FROM root c
329-
ORDER BY RANK FullTextScore(c["Description"], ["otter","beaver"])
329+
ORDER BY RANK FullTextScore(c["Description"], "otter", "beaver")
330330
""");
331331
}
332332

@@ -343,7 +343,7 @@ public virtual async Task OrderByRank_FullTextScore_constant_array_with_one_elem
343343
"""
344344
SELECT VALUE c
345345
FROM root c
346-
ORDER BY RANK FullTextScore(c["Description"], ["otter"])
346+
ORDER BY RANK FullTextScore(c["Description"], "otter")
347347
""");
348348
}
349349

@@ -361,7 +361,7 @@ public virtual async Task OrderByRank_FullTextScore_parameter_array()
361361
"""
362362
SELECT VALUE c
363363
FROM root c
364-
ORDER BY RANK FullTextScore(c["Description"], ["otter","beaver"])
364+
ORDER BY RANK FullTextScore(c["Description"], "otter", "beaver")
365365
""");
366366
}
367367

@@ -384,7 +384,7 @@ public virtual async Task OrderByRank_FullTextScore_using_parameters()
384384
385385
SELECT VALUE c
386386
FROM root c
387-
ORDER BY RANK FullTextScore(c["Description"], [@otter, @beaver])
387+
ORDER BY RANK FullTextScore(c["Description"], @otter, @beaver)
388388
""");
389389
}
390390

@@ -405,7 +405,7 @@ public virtual async Task OrderByRank_FullTextScore_using_one_parameter()
405405
406406
SELECT VALUE c
407407
FROM root c
408-
ORDER BY RANK FullTextScore(c["Description"], [@otter])
408+
ORDER BY RANK FullTextScore(c["Description"], @otter)
409409
""");
410410
}
411411

@@ -426,7 +426,28 @@ public virtual async Task OrderByRank_FullTextScore_using_parameters_constant_mi
426426
427427
SELECT VALUE c
428428
FROM root c
429-
ORDER BY RANK FullTextScore(c["Description"], ["otter", @beaver])
429+
ORDER BY RANK FullTextScore(c["Description"], "otter", @beaver)
430+
""");
431+
}
432+
433+
[ConditionalFact]
434+
public virtual async Task OrderByRank_FullTextScore_using_parameters_constant_mix_inline()
435+
{
436+
await using var context = CreateContext();
437+
438+
var beaver = "beaver";
439+
440+
var result = await context.Set<FullTextSearchAnimals>()
441+
.OrderBy(x => EF.Functions.FullTextScore(x.Description, "otter", beaver))
442+
.ToListAsync();
443+
444+
AssertSql(
445+
"""
446+
@beaver='beaver'
447+
448+
SELECT VALUE c
449+
FROM root c
450+
ORDER BY RANK FullTextScore(c["Description"], "otter", @beaver)
430451
""");
431452
}
432453

@@ -447,7 +468,7 @@ public virtual async Task OrderByRank_FullTextScore_using_parameter()
447468
448469
SELECT VALUE c
449470
FROM root c
450-
ORDER BY RANK FullTextScore(c["Description"], [@otter])
471+
ORDER BY RANK FullTextScore(c["Description"], @otter)
451472
""");
452473
}
453474

@@ -464,7 +485,7 @@ public virtual async Task OrderByRank_FullTextScore_using_complex_expression()
464485
.ToListAsync())).Message;
465486

466487
Assert.Contains(
467-
"The second argument of the FullTextScore function must be a non-empty array of string literals.",
488+
"The second through last arguments of the FullTextScore function must be string literals.",
468489
message);
469490
}
470491

@@ -495,7 +516,7 @@ public virtual async Task OrderByRank_FullTextScore_on_non_FTS_property()
495516
"""
496517
SELECT VALUE c
497518
FROM root c
498-
ORDER BY RANK FullTextScore(c["PartitionKey"], ["taxonomy"])
519+
ORDER BY RANK FullTextScore(c["PartitionKey"], "taxonomy")
499520
""");
500521
}
501522

@@ -514,7 +535,7 @@ public virtual async Task OrderByRank_with_RRF_using_two_FullTextScore_functions
514535
"""
515536
SELECT VALUE c
516537
FROM root c
517-
ORDER BY RANK RRF(FullTextScore(c["Description"], ["beaver"]), FullTextScore(c["Description"], ["otter","bat"]))
538+
ORDER BY RANK RRF(FullTextScore(c["Description"], "beaver"), FullTextScore(c["Description"], "otter", "bat"))
518539
""");
519540
}
520541

@@ -584,7 +605,7 @@ public virtual async Task OrderByRank_Take()
584605
"""
585606
SELECT VALUE c
586607
FROM root c
587-
ORDER BY RANK FullTextScore(c["Description"], ["beaver"])
608+
ORDER BY RANK FullTextScore(c["Description"], "beaver")
588609
OFFSET 0 LIMIT 10
589610
""");
590611
}
@@ -603,7 +624,7 @@ public virtual async Task OrderByRank_Skip_Take()
603624
"""
604625
SELECT VALUE c
605626
FROM root c
606-
ORDER BY RANK FullTextScore(c["Description"], ["beaver","dolphin"])
627+
ORDER BY RANK FullTextScore(c["Description"], "beaver", "dolphin")
607628
OFFSET 1 LIMIT 20
608629
""");
609630
}
@@ -633,7 +654,7 @@ public virtual async Task OrderBy_scoring_function_overridden_by_another()
633654
"""
634655
SELECT VALUE c
635656
FROM root c
636-
ORDER BY RANK FullTextScore(c["Description"], ["beaver","dolphin","second"])
657+
ORDER BY RANK FullTextScore(c["Description"], "beaver", "dolphin", "second")
637658
""");
638659
}
639660

@@ -667,7 +688,7 @@ public virtual async Task Regular_OrderBy_overridden_by_OrderBy_using_scoring_fu
667688
"""
668689
SELECT VALUE c
669690
FROM root c
670-
ORDER BY RANK FullTextScore(c["Description"], ["beaver","dolphin"])
691+
ORDER BY RANK FullTextScore(c["Description"], "beaver", "dolphin")
671692
""");
672693
}
673694

@@ -725,7 +746,7 @@ public virtual async Task OrderByRank_Where()
725746
SELECT VALUE c
726747
FROM root c
727748
WHERE ((c["PartitionKey"] || "Foo") = "habitatFoo")
728-
ORDER BY RANK FullTextScore(c["Description"], ["beaver","dolphin"])
749+
ORDER BY RANK FullTextScore(c["Description"], "beaver", "dolphin")
729750
""");
730751
}
731752

@@ -779,7 +800,7 @@ public virtual async Task OrderByRank_with_FullTextScore_on_nested_owned_type()
779800
"""
780801
SELECT VALUE c
781802
FROM root c
782-
ORDER BY RANK FullTextScore(c["Owned"]["NestedReference"]["AnotherDescription"], ["beaver","dolphin"])
803+
ORDER BY RANK FullTextScore(c["Owned"]["NestedReference"]["AnotherDescription"], "beaver", "dolphin")
783804
""");
784805
}
785806

@@ -816,7 +837,7 @@ public virtual async Task OrderByRank_with_FullTextScore_on_nested_owned_collect
816837
"""
817838
SELECT VALUE c
818839
FROM root c
819-
ORDER BY RANK FullTextScore(c["Owned"]["NestedCollection"][0]["AnotherDescription"], ["beaver","dolphin"])
840+
ORDER BY RANK FullTextScore(c["Owned"]["NestedCollection"][0]["AnotherDescription"], "beaver", "dolphin")
820841
""");
821842
}
822843

@@ -832,7 +853,7 @@ public virtual async Task OrderBy_scoring_function_on_property_with_modified_jso
832853
"""
833854
SELECT VALUE c
834855
FROM root c
835-
ORDER BY RANK FullTextScore(c["CustomDecription"], ["beaver","dolphin"])
856+
ORDER BY RANK FullTextScore(c["CustomDecription"], "beaver", "dolphin")
836857
""");
837858
}
838859

@@ -849,7 +870,7 @@ public virtual async Task OrderByRank_with_FullTextScore_on_nested_owned_type_wi
849870
"""
850871
SELECT VALUE c
851872
FROM root c
852-
ORDER BY RANK FullTextScore(c["Owned"]["CustomNestedReference"]["AnotherDescription"], ["beaver","dolphin"])
873+
ORDER BY RANK FullTextScore(c["Owned"]["CustomNestedReference"]["AnotherDescription"], "beaver", "dolphin")
853874
""");
854875
}
855876

@@ -866,7 +887,7 @@ public virtual async Task OrderByRank_with_FullTextScore_on_property_without_ind
866887
"""
867888
SELECT VALUE c
868889
FROM root c
869-
ORDER BY RANK FullTextScore(c["DescriptionNoIndex"], ["beaver","dolphin"])
890+
ORDER BY RANK FullTextScore(c["DescriptionNoIndex"], "beaver", "dolphin")
870891
""");
871892
}
872893

test/EFCore.Cosmos.FunctionalTests/HybridSearchCosmosTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public virtual async Task Hybrid_search_vector_distance_and_FullTextScore_in_Ord
3939
4040
SELECT VALUE c
4141
FROM root c
42-
ORDER BY RANK RRF(FullTextScore(c["Description"], ["beaver","otter"]), VectorDistance(c["SBytes"], @inputVector, false, {'distanceFunction':'dotproduct', 'dataType':'int8'}))
42+
ORDER BY RANK RRF(FullTextScore(c["Description"], "beaver", "otter"), VectorDistance(c["SBytes"], @inputVector, false, {'distanceFunction':'dotproduct', 'dataType':'int8'}))
4343
""");
4444
}
4545

@@ -62,7 +62,7 @@ public virtual async Task Hybrid_search_vector_distance_and_FullTextScore_with_s
6262
6363
SELECT VALUE c
6464
FROM root c
65-
ORDER BY RANK RRF(FullTextScore(c["Description"], ["beaver"]), VectorDistance(c["SBytes"], @inputVector, false, {'distanceFunction':'dotproduct', 'dataType':'int8'}))
65+
ORDER BY RANK RRF(FullTextScore(c["Description"], "beaver"), VectorDistance(c["SBytes"], @inputVector, false, {'distanceFunction':'dotproduct', 'dataType':'int8'}))
6666
""");
6767
}
6868

@@ -84,7 +84,7 @@ public virtual async Task Hybrid_search_vector_distance_and_FullTextScore_in_Ord
8484
8585
SELECT VALUE c
8686
FROM root c
87-
ORDER BY RANK RRF(FullTextScore(c["Owned"]["AnotherDescription"], ["beaver"]), VectorDistance(c["Owned"]["Singles"], @inputVector, false, {'distanceFunction':'cosine', 'dataType':'float32'}))
87+
ORDER BY RANK RRF(FullTextScore(c["Owned"]["AnotherDescription"], "beaver"), VectorDistance(c["Owned"]["Singles"], @inputVector, false, {'distanceFunction':'cosine', 'dataType':'float32'}))
8888
""");
8989
}
9090

@@ -107,7 +107,7 @@ public virtual async Task Hybrid_search_vector_distance_and_FullTextScore_in_Ord
107107
108108
SELECT VALUE c
109109
FROM root c
110-
ORDER BY RANK RRF(VectorDistance(c["Owned"]["Singles"], @inputVector, false, {'distanceFunction':'cosine', 'dataType':'float32'}), FullTextScore(c["Owned"]["AnotherDescription"], ["beaver","otter"]))
110+
ORDER BY RANK RRF(VectorDistance(c["Owned"]["Singles"], @inputVector, false, {'distanceFunction':'cosine', 'dataType':'float32'}), FullTextScore(c["Owned"]["AnotherDescription"], "beaver", "otter"))
111111
""");
112112
}
113113

0 commit comments

Comments
 (0)