Skip to content

Commit 6eeb183

Browse files
committed
Merge branch 'master' into users/aavasthy/fixlocationcache
2 parents 61bd618 + e4ec354 commit 6eeb183

3 files changed

Lines changed: 142 additions & 51 deletions

File tree

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ public static HybridSearchQueryResult Create(CosmosElement document)
5454
throw new ArgumentException($"{FieldNames.Payload} must exist.");
5555
}
5656

57-
if (!outerPayload.TryGetValue(FieldNames.Payload, out CosmosObject innerPayload))
57+
if (!outerPayload.TryGetValue(FieldNames.Payload, out CosmosElement innerPayload))
5858
{
59-
throw new ArgumentException($"{FieldNames.Payload} must exist nested within the outer payload field.");
59+
innerPayload = CosmosUndefined.Create();
6060
}
6161

6262
if (!outerPayload.TryGetValue(FieldNames.ComponentScores, out CosmosArray componentScores))

Microsoft.Azure.Cosmos/src/ThinClientTransportSerializer.cs

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,13 @@ public static async Task<Stream> SerializeProxyRequestAsync(
5959
dictionaryCollection.Set(header.Key, string.Join(",", header.Value));
6060
}
6161

62-
using DocumentServiceRequest request = new (operationType, resourceType, requestMessage.RequestUri.PathAndQuery,
63-
requestStream, AuthorizationTokenType.PrimaryMasterKey,
64-
dictionaryCollection);
62+
using DocumentServiceRequest request = new (
63+
operationType,
64+
resourceType,
65+
requestMessage.RequestUri.PathAndQuery,
66+
requestStream,
67+
AuthorizationTokenType.PrimaryMasterKey,
68+
dictionaryCollection);
6569

6670
ContainerProperties collection = await clientCollectionCache.ResolveCollectionAsync(
6771
request,
@@ -71,7 +75,7 @@ public static async Task<Stream> SerializeProxyRequestAsync(
7175
if (operationType.IsPointOperation())
7276
{
7377
string partitionKey = request.Headers.Get(HttpConstants.HttpHeaders.PartitionKey);
74-
78+
7579
if (string.IsNullOrEmpty(partitionKey))
7680
{
7781
throw new InternalServerErrorException();
@@ -90,7 +94,7 @@ public static async Task<Stream> SerializeProxyRequestAsync(
9094
request.Properties = new Dictionary<string, object>
9195
{
9296
{ WFConstants.BackendHeaders.StartEpkHash, HexStringUtility.HexStringToBytes(request.Headers[ThinClientConstants.ProxyStartEpk]) },
93-
{ WFConstants.BackendHeaders.EndEpkHash, HexStringUtility.HexStringToBytes(request.Headers[ThinClientConstants.ProxyEndEpk]) }
97+
{ WFConstants.BackendHeaders.EndEpkHash, HexStringUtility.HexStringToBytes(request.Headers[ThinClientConstants.ProxyEndEpk]) }
9498
};
9599

96100
request.Headers.Add(HttpConstants.HttpHeaders.ReadFeedKeyType, RntbdConstants.RntdbReadFeedKeyType.EffectivePartitionKeyRange.ToString());
@@ -103,19 +107,29 @@ public static async Task<Stream> SerializeProxyRequestAsync(
103107
await request.EnsureBufferedBodyAsync();
104108

105109
using Documents.Rntbd.TransportSerialization.SerializedRequest serializedRequest =
106-
Documents.Rntbd.TransportSerialization.BuildRequestForProxy(request,
107-
new ResourceOperation(operationType, resourceType),
108-
activityId,
109-
bufferProvider.Provider,
110-
accountName,
111-
out _,
112-
out _);
113-
114-
// TODO: consider using the SerializedRequest directly.
115-
MemoryStream memoryStream = new MemoryStream(serializedRequest.RequestSize);
116-
await serializedRequest.CopyToStreamAsync(memoryStream);
117-
memoryStream.Position = 0;
118-
return memoryStream;
110+
Documents.Rntbd.TransportSerialization.BuildRequestForProxy(
111+
request,
112+
new ResourceOperation(operationType, resourceType),
113+
activityId,
114+
bufferProvider.Provider,
115+
accountName,
116+
out _,
117+
out _);
118+
119+
int length = serializedRequest.RequestSize;
120+
byte[] buffer = ArrayPool<byte>.Shared.Rent(length);
121+
try
122+
{
123+
await serializedRequest.CopyToStreamAsync(new MemoryStream(buffer, 0, length, true, true));
124+
125+
MemoryStream stream = new MemoryStream(buffer, 0, length, writable: false, publiclyVisible: false);
126+
return stream;
127+
}
128+
catch
129+
{
130+
ArrayPool<byte>.Shared.Return(buffer);
131+
throw;
132+
}
119133
}
120134

121135
public static string GetEffectivePartitionKeyHash(string partitionJson, PartitionKeyDefinition partitionKeyDefinition)
@@ -198,14 +212,11 @@ public static async Task<HttpResponseMessage> ConvertProxyResponseAsync(HttpResp
198212
int headerRead = 0;
199213
while (headerRead < headerLength)
200214
{
201-
int read = 0;
202-
read = await stream.ReadAsync(header, headerRead, headerLength - headerRead);
203-
215+
int read = await stream.ReadAsync(header, headerRead, headerLength - headerRead);
204216
if (read == 0)
205217
{
206218
throw new DocumentClientException("Unexpected read empty bytes", HttpStatusCode.Gone, SubStatusCodes.Unknown);
207219
}
208-
209220
headerRead += read;
210221
}
211222

@@ -222,9 +233,7 @@ public static async Task<HttpResponseMessage> ConvertProxyResponseAsync(HttpResp
222233
int responseMetadataRead = 0;
223234
while (responseMetadataRead < metadataLength)
224235
{
225-
int read = 0;
226-
read = await stream.ReadAsync(metadata, responseMetadataRead, metadataLength - responseMetadataRead);
227-
236+
int read = await stream.ReadAsync(metadata, responseMetadataRead, metadataLength - responseMetadataRead);
228237
if (read == 0)
229238
{
230239
throw new DocumentClientException("Unexpected read empty bytes", HttpStatusCode.Gone, SubStatusCodes.Unknown);
@@ -250,9 +259,7 @@ private static async Task<int> ReadBodyLengthAsync(Stream stream)
250259
int headerRead = 0;
251260
while (headerRead < headerLength)
252261
{
253-
int read = 0;
254-
read = await stream.ReadAsync(header, headerRead, headerLength - headerRead);
255-
262+
int read = await stream.ReadAsync(header, headerRead, headerLength - headerRead);
256263
if (read == 0)
257264
{
258265
throw new DocumentClientException("Unexpected read empty bytes", HttpStatusCode.Gone, SubStatusCodes.Unknown);
@@ -267,7 +274,6 @@ private static async Task<int> ReadBodyLengthAsync(Stream stream)
267274
{
268275
ArrayPool<byte>.Shared.Return(header);
269276
}
270-
271277
}
272278
}
273279
}

Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Query/CosmosUndefinedQueryTests.cs

Lines changed: 105 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ public sealed class CosmosUndefinedQueryTests : QueryTestsBase
2323

2424
private const int IntegerValue = 42;
2525

26-
private const string StringValue = "string";
27-
28-
private const string ArrayValue = "[10, 20]";
29-
26+
private const string StringValue = "string";
27+
28+
private const string ArrayValue = "[10, 20]";
29+
3030
private const string ObjectValue = "{\"type\":\"object\"}";
3131

3232
private static readonly int[] PageSizes = new[] { 5, 10, -1 };
@@ -51,14 +51,76 @@ await this.CreateIngestQueryDeleteAsync(
5151
indexingPolicy: CompositeIndexPolicy);
5252
}
5353

54+
[TestMethod]
55+
public async Task HybridSearchTests()
56+
{
57+
// Removing the await causes the test framework to not run this test
58+
await this.CreateIngestQueryDeleteAsync(
59+
connectionModes: ConnectionModes.Direct | ConnectionModes.Gateway,
60+
collectionTypes: CollectionTypes.MultiPartition | CollectionTypes.SinglePartition,
61+
documents: Documents,
62+
query: HybridSearchTests,
63+
indexingPolicy: CompositeIndexPolicy);
64+
}
65+
5466
private static async Task RunTests(Container container, IReadOnlyList<CosmosObject> _)
5567
{
5668
await OrderByTests(container);
5769
await GroupByTests(container);
5870
await UntypedTests(container);
5971
}
6072

61-
private static async Task UntypedTests(Container container)
73+
private static async Task HybridSearchTests(Container container, IReadOnlyList<CosmosObject> _)
74+
{
75+
UndefinedProjectionTestCase[] testCases = new[]
76+
{
77+
MakeUndefinedProjectionTest(
78+
query: "SELECT c.AlwaysUndefinedField " +
79+
"FROM c " +
80+
"ORDER BY RANK FullTextScore(c.AlwaysUndefinedField, ['needle'])",
81+
expectedCount: DocumentCount),
82+
MakeUndefinedProjectionTest(
83+
query: "SELECT VALUE c.AlwaysUndefinedField " +
84+
"FROM c " +
85+
"ORDER BY RANK FullTextScore(c.AlwaysUndefinedField, ['needle'])",
86+
expectedCount: 0),
87+
MakeUndefinedProjectionTest(
88+
query: "SELECT c.AlwaysUndefinedField " +
89+
"FROM c " +
90+
"ORDER BY RANK RRF(FullTextScore(c.AlwaysUndefinedField, ['needle']), FullTextScore(c.AnotherUndefinedField, ['needle']))",
91+
expectedCount: DocumentCount),
92+
MakeUndefinedProjectionTest(
93+
query: "SELECT VALUE c.AlwaysUndefinedField " +
94+
"FROM c " +
95+
"ORDER BY RANK RRF(FullTextScore(c.AlwaysUndefinedField, ['needle']), FullTextScore(c.AnotherUndefinedField, ['needle']))",
96+
expectedCount: 0),
97+
MakeUndefinedProjectionTest(
98+
query: $"SELECT c.AlwaysUndefinedField " +
99+
$"FROM c " +
100+
$"ORDER BY RANK FullTextScore(c.{nameof(MixedTypeDocument.MixedTypeField)}, ['needle'])",
101+
expectedCount: DocumentCount),
102+
MakeUndefinedProjectionTest(
103+
query: $"SELECT VALUE c.AlwaysUndefinedField " +
104+
$"FROM c " +
105+
$"ORDER BY RANK FullTextScore(c.{nameof(MixedTypeDocument.MixedTypeField)}, ['needle'])",
106+
expectedCount: 0),
107+
MakeUndefinedProjectionTest(
108+
query: $"SELECT c.AlwaysUndefinedField " +
109+
$"FROM c " +
110+
$"ORDER BY RANK RRF(FullTextScore(c.{nameof(MixedTypeDocument.MixedTypeField)}, ['needle']),FullTextScore(c.{nameof(MixedTypeDocument.Index)}, ['needle']))",
111+
expectedCount: DocumentCount),
112+
MakeUndefinedProjectionTest(
113+
query: $"SELECT VALUE c.AlwaysUndefinedField " +
114+
$"FROM c " +
115+
$"ORDER BY RANK RRF(FullTextScore(c.{nameof(MixedTypeDocument.MixedTypeField)}, ['needle']),FullTextScore(c.{nameof(MixedTypeDocument.Index)}, ['needle']))",
116+
expectedCount: 0),
117+
};
118+
119+
await RunUndefinedProjectionTests(container, testCases);
120+
await RunUntypedTestsAsync(container, testCases);
121+
}
122+
123+
private static Task UntypedTests(Container container)
62124
{
63125
UndefinedProjectionTestCase[] undefinedProjectionTestCases = new[]
64126
{
@@ -79,13 +141,18 @@ private static async Task UntypedTests(Container container)
79141
expectedCount: 0),
80142
MakeUndefinedProjectionTest(
81143
query: $"SELECT VALUE AVG(c.{nameof(MixedTypeDocument.MixedTypeField)}) FROM c",
82-
expectedCount: 0),
83-
MakeUndefinedProjectionTest(
144+
expectedCount: 0),
145+
MakeUndefinedProjectionTest(
84146
query: $"SELECT DISTINCT VALUE SUM(c.{nameof(MixedTypeDocument.MixedTypeField)}) FROM c",
85147
expectedCount: 0)
86148
};
87149

88-
foreach (UndefinedProjectionTestCase testCase in undefinedProjectionTestCases)
150+
return RunUntypedTestsAsync(container, undefinedProjectionTestCases);
151+
}
152+
153+
private static async Task RunUntypedTestsAsync(Container container, IEnumerable<UndefinedProjectionTestCase> testCases)
154+
{
155+
foreach (UndefinedProjectionTestCase testCase in testCases)
89156
{
90157
foreach (int pageSize in PageSizes)
91158
{
@@ -122,6 +189,24 @@ private static async Task UntypedTests(Container container)
122189
Assert.AreEqual(testCase.ExpectedResultCount, actualCount);
123190
}
124191
}
192+
}
193+
194+
private static async Task RunUndefinedProjectionTests(Container container, IEnumerable<UndefinedProjectionTestCase> testCases)
195+
{
196+
foreach (UndefinedProjectionTestCase testCase in testCases)
197+
{
198+
foreach (int pageSize in PageSizes)
199+
{
200+
List<UndefinedProjection> results = await RunQueryCombinationsAsync<UndefinedProjection>(
201+
container,
202+
testCase.Query,
203+
new QueryRequestOptions { MaxItemCount = pageSize },
204+
QueryDrainingMode.HoldState);
205+
206+
Assert.AreEqual(testCase.ExpectedResultCount, results.Count);
207+
Assert.IsTrue(results.All(x => x is UndefinedProjection));
208+
}
209+
}
125210
}
126211

127212
private static async Task OrderByTests(Container container)
@@ -237,10 +322,10 @@ private static async Task GroupByTests(Container container)
237322
value: DocumentsPerTypeCount),
238323
MakeGrouping(
239324
key: CosmosArray.Parse(ArrayValue),
240-
value: DocumentsPerTypeCount),
325+
value: DocumentsPerTypeCount),
241326
MakeGrouping(
242327
key: CosmosObject.Parse(ObjectValue),
243-
value: DocumentsPerTypeCount),
328+
value: DocumentsPerTypeCount),
244329
}),
245330
MakeGroupByTest(
246331
query: $"SELECT SUM(c.{nameof(MixedTypeDocument.MixedTypeField)}) as {nameof(GroupByProjection.MixedTypeField)}, " +
@@ -361,9 +446,9 @@ private static async Task GroupByTests(Container container)
361446
};
362447

363448
foreach (GroupByUndefinedTestCase testCase in mixedTypeTestCases)
364-
{
449+
{
365450
foreach (int pageSize in PageSizes)
366-
{
451+
{
367452
List<GroupByProjection> actual = await QueryWithoutContinuationTokensAsync<GroupByProjection>(
368453
container,
369454
testCase.Query,
@@ -457,14 +542,14 @@ private static List<MixedTypeDocument> CreateDocuments(int count)
457542
case 4:
458543
mixedTypeElement = CosmosString.Create(StringValue);
459544
break;
460-
461-
case 5:
462-
mixedTypeElement = CosmosArray.Parse(ArrayValue);
463-
break;
464-
465-
case 6:
466-
mixedTypeElement = CosmosObject.Parse(ObjectValue);
467-
break;
545+
546+
case 5:
547+
mixedTypeElement = CosmosArray.Parse(ArrayValue);
548+
break;
549+
550+
case 6:
551+
mixedTypeElement = CosmosObject.Parse(ObjectValue);
552+
break;
468553

469554
default:
470555
mixedTypeElement = null;

0 commit comments

Comments
 (0)