Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Microsoft.Azure.Cosmos/src/Linq/CosmosLinqExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,27 @@ public static FeedIterator ToStreamIterator<T>(this IQueryable<T> query)
return linqQuery.ToStreamIterator();
}

/// <summary>
/// This extension method returns the Index Metrics for a given Response object. The index utilization metrics is to be used for debugging purposes only.
/// This result is only available if QueryRequestOptions.PopulateIndexMetrics is set to true.Returns null if the index metrics is not available in the response.
/// </summary>
/// <param name="response">The query Response.</param>
/// <returns>A string represents the Index Metrics.</returns>
/// <example>
/// This example shows a common usage of this function.
/// <code language="c#">
/// <![CDATA[
/// QueryRequestOptions queryRequestOption = new QueryRequestOptions() { PopulateIndexMetrics = true };
/// Response<int> response = await this.Container.GetLinqQueryable<T>(requestOptions: queryRequestOption).Select(item => item.Id).CountAsync(cancellationToken);
/// string indexMetrics = response.GetIndexMetrics();
/// ]]>
/// </code>
/// </example>
public static string GetIndexMetrics<T>(this Response<T> response)
{
return ResponseMessage.DecodeIndexMetrics(response.Headers, isBase64Encoded: false)?.Value;
}

/// <summary>
/// Returns the maximum value in a generic <see cref="IQueryable{TSource}" />.
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions Microsoft.Azure.Cosmos/src/Linq/CosmosLinqQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,18 @@ internal async Task<Response<T>> AggregateResultAsync(CancellationToken cancella
{
FeedResponse<T> response = await localFeedIterator.ReadNextAsync(rootTrace, cancellationToken);
headers.RequestCharge += response.RequestCharge;

// IndexMetrics only show up on first round trip
if (response.Headers.IndexUtilizationText != null)
{
headers.IndexUtilizationText = response.Headers.IndexUtilizationText;
}

if (response.Headers.ActivityId != null)
{
headers.ActivityId = response.Headers.ActivityId;
}
Comment thread
leminh98 marked this conversation as resolved.

result.AddRange(response);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class CosmosItemLinqTests : BaseCosmosClientHelper
[TestInitialize]
public async Task TestInitialize()
{
await base.TestInit();
await TestInit();
string PartitionKey = "/pk";
this.containerSettings = new ContainerProperties(id: Guid.NewGuid().ToString(), partitionKeyPath: PartitionKey);
ContainerResponse response = await this.database.CreateContainerAsync(
Expand All @@ -40,7 +40,7 @@ public async Task TestInitialize()
[TestCleanup]
public async Task Cleanup()
{
await base.TestCleanup();
await TestCleanup();
Comment thread
leminh98 marked this conversation as resolved.
Outdated
}

[DataRow(false)]
Expand All @@ -49,7 +49,7 @@ public async Task Cleanup()
public async Task ItemLinqReadFeedTest(bool useStatelessIterator)
{
IList<ToDoActivity> deleteList = await ToDoActivity.CreateRandomItems(this.Container, pkCount: 3, randomPartitionKey: true);
HashSet<string> itemIds = deleteList.Select(x => x.id).ToHashSet<string>();
HashSet<string> itemIds = deleteList.Select(x => x.id).ToHashSet();

QueryRequestOptions requestOptions = new QueryRequestOptions()
{
Expand Down Expand Up @@ -91,7 +91,7 @@ public async Task ItemLinqReadFeedTest(bool useStatelessIterator)
Assert.IsNull(lastContinuationToken);
Assert.AreEqual(itemIds.Count, 0);

itemIds = deleteList.Select(x => x.id).ToHashSet<string>();
itemIds = deleteList.Select(x => x.id).ToHashSet();
FeedIterator streamIterator = this.Container.GetItemLinqQueryable<ToDoActivity>(
requestOptions: requestOptions).ToStreamIterator();

Expand Down Expand Up @@ -198,14 +198,14 @@ public async Task ItemLINQQueryTest()
//LINQ query execution with wrong partition key.
linqQueryable = this.Container.GetItemLinqQueryable<ToDoActivity>(
allowSynchronousQueryExecution: true,
requestOptions: new QueryRequestOptions() { PartitionKey = new Cosmos.PartitionKey("test") });
requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("test") });
queriable = linqQueryable.Where(item => item.taskNum < 100);
Assert.AreEqual(0, queriable.Count());

//LINQ query execution with correct partition key.
linqQueryable = this.Container.GetItemLinqQueryable<ToDoActivity>(
allowSynchronousQueryExecution: true,
requestOptions: new QueryRequestOptions { ConsistencyLevel = Cosmos.ConsistencyLevel.Eventual, PartitionKey = new Cosmos.PartitionKey(itemList[1].pk) });
requestOptions: new QueryRequestOptions { ConsistencyLevel = ConsistencyLevel.Eventual, PartitionKey = new PartitionKey(itemList[1].pk) });
queriable = linqQueryable.Where(item => item.taskNum < 100);
Assert.AreEqual(1, queriable.Count());
Assert.AreEqual(itemList[1].id, queriable.ToList()[0].id);
Expand Down Expand Up @@ -313,7 +313,7 @@ public async Task QueryableExtentionFunctionsTest()
//Creating items for query.
IList<ToDoActivity> itemList = await ToDoActivity.CreateRandomItems(container: this.Container, pkCount: 10, perPKItemCount: 1, randomPartitionKey: true);

QueryRequestOptions queryRequestOptions = new QueryRequestOptions();
QueryRequestOptions queryRequestOptions = new QueryRequestOptions() { PopulateIndexMetrics = true };
IOrderedQueryable<ToDoActivity> linqQueryable = this.Container.GetItemLinqQueryable<ToDoActivity>(
requestOptions: queryRequestOptions);

Expand Down Expand Up @@ -396,6 +396,34 @@ public async Task QueryableExtentionFunctionsTest()
Assert.AreEqual(100, maxTaskNum);
}


[TestMethod]
public async Task GetIndexMetricsTest()
{
//Creating items for query.
IList<ToDoActivity> itemList = await ToDoActivity.CreateRandomItems(container: this.Container, pkCount: 10, perPKItemCount: 1, randomPartitionKey: true);

QueryRequestOptions queryRequestOptions = new QueryRequestOptions() { PopulateIndexMetrics = true };
IOrderedQueryable<ToDoActivity> linqQueryable = this.Container.GetItemLinqQueryable<ToDoActivity>(
requestOptions: queryRequestOptions);

// Response object with valid index metrics field
Response<int> response = await linqQueryable.Select(item => item.taskNum).SumAsync();
this.VerifyResponse(response, 420, queryRequestOptions);

string indexMetrics = response.GetIndexMetrics();
Assert.AreEqual(
@"{""UtilizedIndexes"":{""SingleIndexes"":[{""IndexSpec"":""/taskNum/?""}],""CompositeIndexes"":[]},""PotentialIndexes"":{""SingleIndexes"":[],""CompositeIndexes"":[]}}",
indexMetrics);

// Response object with null index metrics field]
Comment thread
leminh98 marked this conversation as resolved.
Outdated
response.Headers.IndexUtilizationText = null;
indexMetrics = response.GetIndexMetrics();
Assert.AreEqual(
null,
indexMetrics);
}

[DataRow(false)]
[DataRow(true)]
[TestMethod]
Expand All @@ -416,7 +444,7 @@ public async Task ItemLINQWithCamelCaseSerializerOptions(bool isGatewayMode)
Assert.IsNotNull(camelCaseCosmosClient.ClientOptions.Serializer);
Assert.IsTrue(camelCaseCosmosClient.ClientOptions.Serializer is CosmosJsonSerializerWrapper);

Cosmos.Database database = camelCaseCosmosClient.GetDatabase(this.database.Id);
Database database = camelCaseCosmosClient.GetDatabase(this.database.Id);
Container containerFromCamelCaseClient = database.GetContainer(this.Container.Id);
IList<ToDoActivity> itemList = await ToDoActivity.CreateRandomItems(container: containerFromCamelCaseClient, pkCount: 2, perPKItemCount: 1, randomPartitionKey: true);

Expand Down Expand Up @@ -444,7 +472,7 @@ static void builder(CosmosClientBuilder action)
});
}
CosmosClient camelCaseCosmosClient = TestCommon.CreateCosmosClient(builder, false);
Cosmos.Database database = camelCaseCosmosClient.GetDatabase(this.database.Id);
Database database = camelCaseCosmosClient.GetDatabase(this.database.Id);
Container containerFromCamelCaseClient = database.GetContainer(this.Container.Id);

IList<ToDoActivity> itemList = await ToDoActivity.CreateRandomItems(containerFromCamelCaseClient, pkCount: 2, perPKItemCount: 1, randomPartitionKey: true);
Expand Down Expand Up @@ -513,7 +541,7 @@ static void builder(CosmosClientBuilder action)
});
}
CosmosClient nullValuesClient = TestCommon.CreateCosmosClient(builder, false);
Cosmos.Database database = nullValuesClient.GetDatabase(this.database.Id);
Database database = nullValuesClient.GetDatabase(this.database.Id);
Container containerFromNulValuesClient = database.GetContainer(this.Container.Id);

IList<ToDoActivity> itemList = await ToDoActivity.CreateRandomItems(containerFromNulValuesClient, pkCount: 2, perPKItemCount: 1, randomPartitionKey: true);
Expand Down Expand Up @@ -1010,8 +1038,11 @@ private void VerifyResponse<T>(
T expectedValue,
QueryRequestOptions queryRequestOptions)
{
Assert.AreEqual<T>(expectedValue, response.Resource);
Assert.AreEqual(expectedValue, response.Resource);
Assert.IsTrue(response.RequestCharge > 0);
Assert.IsNotNull(response.Headers.IndexUtilizationText);
Assert.IsNotNull(response.Headers.ActivityId);
Assert.IsNotNull(response.ActivityId);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6432,6 +6432,13 @@
],
"MethodInfo": "System.Linq.IOrderedQueryable`1[TSource] OrderByRank[TSource,TKey](System.Linq.IQueryable`1[TSource], System.Linq.Expressions.Expression`1[System.Func`2[TSource,TKey]]);IsAbstract:False;IsStatic:True;IsVirtual:False;IsGenericMethod:True;IsConstructor:False;IsFinal:False;"
},
"System.String GetIndexMetrics[T](Microsoft.Azure.Cosmos.Response`1[T])[System.Runtime.CompilerServices.ExtensionAttribute()]": {
"Type": "Method",
"Attributes": [
"ExtensionAttribute"
],
"MethodInfo": "System.String GetIndexMetrics[T](Microsoft.Azure.Cosmos.Response`1[T]);IsAbstract:False;IsStatic:True;IsVirtual:False;IsGenericMethod:True;IsConstructor:False;IsFinal:False;"
},
"System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.Response`1[System.Decimal]] AverageAsync(System.Linq.IQueryable`1[System.Decimal], System.Threading.CancellationToken)[System.Runtime.CompilerServices.ExtensionAttribute()]": {
"Type": "Method",
"Attributes": [
Expand Down
Loading