Skip to content

Commit 4e55fdd

Browse files
authored
Merge branch 'master' into users/aditya/FTLanguageOptional
2 parents 8c8b789 + 6d57959 commit 4e55fdd

File tree

12 files changed

+566
-111
lines changed

12 files changed

+566
-111
lines changed

Microsoft.Azure.Cosmos/src/Linq/BuiltinFunctions/OtherBuiltinSystemFunctions.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public RRFVisit()
2121
true,
2222
new List<Type[]>()
2323
{
24-
new Type[]{typeof(Func<object, object>[])}
24+
new Type[]{typeof(double[])}
2525
})
2626
{
2727
}
@@ -36,7 +36,27 @@ protected override SqlScalarExpression VisitImplicit(MethodCallExpression method
3636
List<SqlScalarExpression> arguments = new List<SqlScalarExpression>();
3737
foreach (Expression argument in functionListExpression)
3838
{
39-
arguments.Add(ExpressionToSql.VisitScalarExpression(argument, context));
39+
if (!(argument is MethodCallExpression functionCallExpression))
40+
{
41+
throw new ArgumentException(
42+
string.Format(
43+
CultureInfo.CurrentCulture,
44+
"Expressions of type {0} is not supported as an argument to CosmosLinqExtensions.RRF. Supported expressions are method calls to {1}.",
45+
argument.Type,
46+
nameof(CosmosLinqExtensions.FullTextScore)));
47+
}
48+
49+
if (functionCallExpression.Method.Name != nameof(CosmosLinqExtensions.FullTextScore))
50+
{
51+
throw new ArgumentException(
52+
string.Format(
53+
CultureInfo.CurrentCulture,
54+
"Method {0} is not supported as an argument to CosmosLinqExtensions.RRF. Supported methods are {1}.",
55+
functionCallExpression.Method.Name,
56+
nameof(CosmosLinqExtensions.FullTextScore)));
57+
}
58+
59+
arguments.Add(ExpressionToSql.VisitNonSubqueryScalarExpression(argument, context));
4060
}
4161

4262
return SqlFunctionCallScalarExpression.CreateBuiltin(SqlFunctionCallScalarExpression.Names.RRF, arguments.ToImmutableArray());

Microsoft.Azure.Cosmos/src/Linq/CosmosLinqExtensions.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ public static bool FullTextContainsAny(this object obj, params string[] searches
318318
/// ]]>
319319
/// </code>
320320
/// </example>
321-
public static Func<TSource, object> FullTextScore<TSource>(this TSource obj, params string[] terms)
321+
public static double FullTextScore<TSource>(this TSource obj, params string[] terms)
322322
{
323323
throw new NotImplementedException(ClientResources.ExtensionMethodNotImplemented);
324324
}
@@ -339,7 +339,7 @@ public static Func<TSource, object> FullTextScore<TSource>(this TSource obj, par
339339
/// ]]>
340340
/// </code>
341341
/// </example>
342-
public static IOrderedQueryable<TSource> OrderByRank<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, object>> scoreFunction)
342+
public static IOrderedQueryable<TSource> OrderByRank<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> scoreFunction)
343343
{
344344
if (!(source is CosmosLinqQuery<TSource>))
345345
{
@@ -349,7 +349,7 @@ public static IOrderedQueryable<TSource> OrderByRank<TSource>(this IQueryable<TS
349349
return (IOrderedQueryable<TSource>)source.Provider.CreateQuery<TSource>(
350350
Expression.Call(
351351
null,
352-
typeof(CosmosLinqExtensions).GetMethod("OrderByRank").MakeGenericMethod(typeof(TSource)),
352+
typeof(CosmosLinqExtensions).GetMethod("OrderByRank").MakeGenericMethod(typeof(TSource), typeof(TKey)),
353353
source.Expression,
354354
Expression.Quote(scoreFunction)));
355355
}
@@ -360,7 +360,7 @@ public static IOrderedQueryable<TSource> OrderByRank<TSource>(this IQueryable<TS
360360
/// This method is to be used in LINQ expressions only and will be evaluated on server.
361361
/// There's no implementation provided in the client library.
362362
/// </summary>
363-
/// <param name="scoringFunctions">the scoring functions to combine.</param>
363+
/// <param name="scoringFunctions">the scoring functions to combine. Valid functions are FullTextScore and VectorDistance</param>
364364
/// <returns>Returns the the combined scores of the scoring functions.</returns>
365365
/// <example>
366366
/// <code>
@@ -369,7 +369,7 @@ public static IOrderedQueryable<TSource> OrderByRank<TSource>(this IQueryable<TS
369369
/// ]]>
370370
/// </code>
371371
/// </example>
372-
public static Func<TSource, object> RRF<TSource>(params Func<TSource, object>[] scoringFunctions)
372+
public static double RRF(params double[] scoringFunctions)
373373
{
374374
// The reason for not defining "this" keyword is because this causes undesirable serialization when call Expression.ToString() on this method
375375
throw new NotImplementedException(ClientResources.ExtensionMethodNotImplemented);

Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/HybridSearch/HybridSearchCrossPartitionQueryPipelineStage.cs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -404,12 +404,10 @@ private static IReadOnlyList<ComponentWeight> ExtractComponentWeights(HybridSear
404404
for (int index = 0; index < hybridSearchQueryInfo.ComponentQueryInfos.Count; ++index)
405405
{
406406
QueryInfo queryInfo = hybridSearchQueryInfo.ComponentQueryInfos[index];
407-
Debug.Assert(queryInfo.HasOrderBy, "The component query should have an order by");
408-
Debug.Assert(queryInfo.HasNonStreamingOrderBy, "The component query is a non streaming order by");
409-
Debug.Assert(queryInfo.OrderBy.Count == 1, "The component query should have exactly one order by expression");
407+
SortOrder sortOrder = queryInfo.HasOrderBy ? queryInfo.OrderBy[0] : SortOrder.Descending;
410408

411409
double componentWeight = useDefaultComponentWeight ? 1.0 : hybridSearchQueryInfo.ComponentWeights[index];
412-
result.Add(new ComponentWeight(componentWeight, queryInfo.OrderBy[0]));
410+
result.Add(new ComponentWeight(componentWeight, sortOrder));
413411
}
414412

415413
return result;
@@ -635,14 +633,19 @@ private static void ComputeRrfScores(
635633

636634
private static QueryInfo RewriteOrderByQueryInfo(QueryInfo queryInfo, GlobalFullTextSearchStatistics statistics, int componentCount)
637635
{
638-
Debug.Assert(queryInfo.HasOrderBy, "The component query should have an order by");
639-
Debug.Assert(queryInfo.HasNonStreamingOrderBy, "The component query is a non streaming order by");
636+
IReadOnlyList<string> rewrittenOrderByExpressions = queryInfo.OrderByExpressions;
640637

641-
List<string> rewrittenOrderByExpressions = new List<string>(queryInfo.OrderByExpressions.Count);
642-
foreach (string orderByExpression in queryInfo.OrderByExpressions)
638+
if (queryInfo.HasOrderBy)
643639
{
644-
string rewrittenOrderByExpression = FormatComponentQueryTextWorkaround(orderByExpression, statistics, componentCount);
645-
rewrittenOrderByExpressions.Add(rewrittenOrderByExpression);
640+
Debug.Assert(queryInfo.HasNonStreamingOrderBy, "The component query is a non streaming order by");
641+
List<string> orderByExpressions = new List<string>(queryInfo.OrderByExpressions.Count);
642+
foreach (string orderByExpression in queryInfo.OrderByExpressions)
643+
{
644+
string rewrittenOrderByExpression = FormatComponentQueryTextWorkaround(orderByExpression, statistics, componentCount);
645+
orderByExpressions.Add(rewrittenOrderByExpression);
646+
}
647+
648+
rewrittenOrderByExpressions = orderByExpressions;
646649
}
647650

648651
string rewrittenQuery = FormatComponentQueryTextWorkaround(queryInfo.RewrittenQuery, statistics, componentCount);
@@ -777,18 +780,15 @@ private static string FormatComponentQueryTextWorkaround(string format, GlobalFu
777780

778781
private class ComponentWeight
779782
{
780-
public SortOrder SortOrder { get; }
781-
782783
public double Weight { get; }
783784

784785
public Comparison<double> Comparison { get; }
785786

786787
public ComponentWeight(double weight, SortOrder sortOrder)
787788
{
788789
this.Weight = weight;
789-
this.SortOrder = sortOrder;
790790

791-
int comparisonFactor = (this.SortOrder == SortOrder.Ascending) ? 1 : -1;
791+
int comparisonFactor = (sortOrder == SortOrder.Ascending) ? 1 : -1;
792792
this.Comparison = (x, y) => comparisonFactor * x.CompareTo(y);
793793
}
794794
}

Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/HybridSearch/HybridSearchQueryResult.cs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,33 @@ public static HybridSearchQueryResult Create(CosmosElement document)
4949
throw new ArgumentException($"{FieldNames.Rid} must exist.");
5050
}
5151

52-
if (!cosmosObject.TryGetValue(FieldNames.Payload, out CosmosObject outerPayload))
53-
{
54-
throw new ArgumentException($"{FieldNames.Payload} must exist.");
55-
}
52+
bool outerPayloadExists = cosmosObject.TryGetValue(FieldNames.Payload, out CosmosObject outerPayload);
5653

57-
if (!outerPayload.TryGetValue(FieldNames.Payload, out CosmosElement innerPayload))
54+
HybridSearchQueryResult result;
55+
if (outerPayloadExists && outerPayload.TryGetValue(FieldNames.ComponentScores, out CosmosArray componentScores))
5856
{
59-
innerPayload = CosmosUndefined.Create();
60-
}
57+
// Using the older format where the payload is nested.
58+
if (!outerPayload.TryGetValue(FieldNames.Payload, out CosmosElement innerPayload))
59+
{
60+
innerPayload = CosmosUndefined.Create();
61+
}
6162

62-
if (!outerPayload.TryGetValue(FieldNames.ComponentScores, out CosmosArray componentScores))
63+
result = new HybridSearchQueryResult(rid, componentScores, innerPayload);
64+
}
65+
else
6366
{
64-
throw new ArgumentException($"{FieldNames.ComponentScores} must exist.");
67+
// Using the newer format where the payload is not nested.
68+
if (!cosmosObject.TryGetValue(FieldNames.ComponentScores, out componentScores))
69+
{
70+
throw new ArgumentException($"{FieldNames.ComponentScores} must exist.");
71+
}
72+
73+
CosmosElement payload = outerPayloadExists ? outerPayload : CosmosUndefined.Create();
74+
75+
result = new HybridSearchQueryResult(rid, componentScores, payload);
6576
}
6677

67-
return new HybridSearchQueryResult(rid, componentScores, innerPayload);
78+
return result;
6879
}
6980

7081
private static class FieldNames

Microsoft.Azure.Cosmos/src/Resource/Settings/ContainerProperties.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,12 @@ public GeospatialConfig GeospatialConfig
421421

422422
/// <summary>
423423
/// JSON path used for containers partitioning
424+
///
425+
/// For hierarchical partition keys, please use <see cref="ContainerProperties.PartitionKeyPaths"/>
424426
/// </summary>
427+
/// <remarks>
428+
/// Throws NotImplementedException for hierarchical partition keys
429+
/// </remarks>
425430
[JsonIgnore]
426431
public string PartitionKeyPath
427432
{

Microsoft.Azure.Cosmos/src/Routing/LocationCache.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -689,26 +689,26 @@ private void UpdateLocationCache(
689689
nextLocationInfo.AvailableWriteLocationByEndpoint = availableWriteLocationsByEndpoint;
690690
}
691691

692-
if (thinClientReadLocations != null)
692+
if (thinClientReadLocations != null && thinClientReadLocations.Count() > 0)
693693
{
694694
nextLocationInfo.ThinClientReadEndpointByLocation = this.GetEndpointByLocation(
695695
thinClientReadLocations,
696-
out ReadOnlyCollection<string> tcreadLocations,
697-
out ReadOnlyDictionary<Uri, string> tcReadLocByEndpoint);
696+
out ReadOnlyCollection<string> thinClientAvailableReadLocations,
697+
out ReadOnlyDictionary<Uri, string> thinClientAvailableReadLocationsByEndpoint);
698698

699-
nextLocationInfo.ThinClientReadLocations = tcreadLocations;
700-
nextLocationInfo.ThinClientReadLocationByEndpoint = tcReadLocByEndpoint;
699+
nextLocationInfo.ThinClientReadLocations = thinClientAvailableReadLocations;
700+
nextLocationInfo.ThinClientReadLocationByEndpoint = thinClientAvailableReadLocationsByEndpoint;
701701
}
702702

703-
if (thinClientWriteLocations != null)
703+
if (thinClientWriteLocations != null && thinClientWriteLocations.Count() > 0)
704704
{
705705
nextLocationInfo.ThinClientWriteEndpointByLocation = this.GetEndpointByLocation(
706706
thinClientWriteLocations,
707-
out ReadOnlyCollection<string> tcwriteLocations,
708-
out ReadOnlyDictionary<Uri, string> tcWriteLocByEndpoint);
707+
out ReadOnlyCollection<string> thinClientAvailableWriteLocations,
708+
out ReadOnlyDictionary<Uri, string> thinClientAvailableWriteLocationsByEndpoint);
709709

710-
nextLocationInfo.ThinClientWriteLocations = tcwriteLocations;
711-
nextLocationInfo.ThinClientWriteLocationByEndpoint = tcWriteLocByEndpoint;
710+
nextLocationInfo.ThinClientWriteLocations = thinClientAvailableWriteLocations;
711+
nextLocationInfo.ThinClientWriteLocationByEndpoint = thinClientAvailableWriteLocationsByEndpoint;
712712
}
713713

714714
nextLocationInfo.WriteEndpoints = this.GetPreferredAvailableEndpoints(
@@ -725,18 +725,18 @@ private void UpdateLocationCache(
725725

726726
nextLocationInfo.EffectivePreferredLocations = nextLocationInfo.PreferredLocations;
727727

728+
nextLocationInfo.ThinClientWriteEndpoints = this.GetPreferredAvailableEndpoints(
729+
endpointsByLocation: nextLocationInfo.ThinClientWriteEndpointByLocation,
730+
orderedLocations: nextLocationInfo.ThinClientWriteLocations,
731+
expectedAvailableOperation: OperationType.Write,
732+
fallbackEndpoint: this.defaultEndpoint);
733+
728734
nextLocationInfo.ThinClientReadEndpoints = this.GetPreferredAvailableEndpoints(
729735
endpointsByLocation: nextLocationInfo.ThinClientReadEndpointByLocation,
730736
orderedLocations: nextLocationInfo.ThinClientReadLocations,
731737
expectedAvailableOperation: OperationType.Read,
732-
fallbackEndpoint: this.defaultEndpoint);
738+
fallbackEndpoint: nextLocationInfo.ThinClientWriteEndpoints[0]);
733739

734-
nextLocationInfo.ThinClientWriteEndpoints = this.GetPreferredAvailableEndpoints(
735-
endpointsByLocation: nextLocationInfo.ThinClientWriteEndpointByLocation,
736-
orderedLocations: nextLocationInfo.ThinClientWriteLocations,
737-
expectedAvailableOperation: OperationType.Write,
738-
fallbackEndpoint: this.defaultEndpoint);
739-
740740
if (nextLocationInfo.PreferredLocations == null || nextLocationInfo.PreferredLocations.Count == 0)
741741
{
742742
if (!nextLocationInfo.AvailableReadLocationByEndpoint.TryGetValue(this.defaultEndpoint, out string regionForDefaultEndpoint))

Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/LinqTranslationBaselineTests.TestFullTextScoreOrderByRankFunction.xml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,52 +66,52 @@ ORDER BY RANK FullTextScore(root["StringField"], "test1", "test2", "test3")]]></
6666
<Result>
6767
<Input>
6868
<Description><![CDATA[FullTextScore in WHERE clause]]></Description>
69-
<Expression><![CDATA[query.Where(doc => (doc.StringField.FullTextScore(new [] {"test1"}) != null))]]></Expression>
69+
<Expression><![CDATA[query.Where(doc => (doc.StringField.FullTextScore(new [] {"test1"}) != 123))]]></Expression>
7070
</Input>
7171
<Output>
7272
<SqlQuery><![CDATA[
7373
SELECT VALUE root
7474
FROM root
75-
WHERE (FullTextScore(root["StringField"], "test1") != null)]]></SqlQuery>
75+
WHERE (FullTextScore(root["StringField"], "test1") != 123)]]></SqlQuery>
7676
<ErrorMessage><![CDATA[Status Code: BadRequest,{"errors":[{"severity":"Error","location":{"start":35,"end":78},"code":"SC2240","message":"The FullTextScore function is only allowed in the ORDER BY RANK clause."}]},0x800A0B00]]></ErrorMessage>
7777
</Output>
7878
</Result>
7979
<Result>
8080
<Input>
8181
<Description><![CDATA[FullTextScore in WHERE clause 2]]></Description>
82-
<Expression><![CDATA[query.Where(doc => (doc.StringField.FullTextScore(new [] {"test1", "test2", "test3"}) != null))]]></Expression>
82+
<Expression><![CDATA[query.Where(doc => (doc.StringField.FullTextScore(new [] {"test1", "test2", "test3"}) != 123))]]></Expression>
8383
</Input>
8484
<Output>
8585
<SqlQuery><![CDATA[
8686
SELECT VALUE root
8787
FROM root
88-
WHERE (FullTextScore(root["StringField"], "test1", "test2", "test3") != null)]]></SqlQuery>
88+
WHERE (FullTextScore(root["StringField"], "test1", "test2", "test3") != 123)]]></SqlQuery>
8989
<ErrorMessage><![CDATA[Status Code: BadRequest,{"errors":[{"severity":"Error","location":{"start":35,"end":96},"code":"SC2240","message":"The FullTextScore function is only allowed in the ORDER BY RANK clause."}]},0x800A0B00]]></ErrorMessage>
9090
</Output>
9191
</Result>
9292
<Result>
9393
<Input>
9494
<Description><![CDATA[FullTextScore in WHERE clause]]></Description>
95-
<Expression><![CDATA[query.Where(doc => (doc.StringField.FullTextScore(new [] {"test1"}) != null))]]></Expression>
95+
<Expression><![CDATA[query.Where(doc => (doc.StringField.FullTextScore(new [] {"test1"}) != 123))]]></Expression>
9696
</Input>
9797
<Output>
9898
<SqlQuery><![CDATA[
9999
SELECT VALUE root
100100
FROM root
101-
WHERE (FullTextScore(root["StringField"], "test1") != null)]]></SqlQuery>
101+
WHERE (FullTextScore(root["StringField"], "test1") != 123)]]></SqlQuery>
102102
<ErrorMessage><![CDATA[Status Code: BadRequest,{"errors":[{"severity":"Error","location":{"start":35,"end":78},"code":"SC2240","message":"The FullTextScore function is only allowed in the ORDER BY RANK clause."}]},0x800A0B00]]></ErrorMessage>
103103
</Output>
104104
</Result>
105105
<Result>
106106
<Input>
107107
<Description><![CDATA[FullTextScore in WHERE clause 2]]></Description>
108-
<Expression><![CDATA[query.Where(doc => (doc.StringField.FullTextScore(new [] {"test1", "test2", "test3"}) != null))]]></Expression>
108+
<Expression><![CDATA[query.Where(doc => (doc.StringField.FullTextScore(new [] {"test1", "test2", "test3"}) != 123))]]></Expression>
109109
</Input>
110110
<Output>
111111
<SqlQuery><![CDATA[
112112
SELECT VALUE root
113113
FROM root
114-
WHERE (FullTextScore(root["StringField"], "test1", "test2", "test3") != null)]]></SqlQuery>
114+
WHERE (FullTextScore(root["StringField"], "test1", "test2", "test3") != 123)]]></SqlQuery>
115115
<ErrorMessage><![CDATA[Status Code: BadRequest,{"errors":[{"severity":"Error","location":{"start":35,"end":96},"code":"SC2240","message":"The FullTextScore function is only allowed in the ORDER BY RANK clause."}]},0x800A0B00]]></ErrorMessage>
116116
</Output>
117117
</Result>

0 commit comments

Comments
 (0)