diff --git a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/Readme.md b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/Readme.md index a82df272e875b..b96d9a200a2c5 100644 --- a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/Readme.md +++ b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/Readme.md @@ -1,20 +1,41 @@ # Introduction -Introduction to Time Series Insights. +Azure Time Series Insights provides data exploration and telemetry tools to help you improve operational analysis. It's a fully managed analytics, storage, and visualization service where you can explore and analyze billions of Internet of Things (IoT) events simultaneously. -# Time Series Insights Samples +Azure Time Series Insights gives you a global view of your data, so you can quickly validate your IoT solution and avoid costly downtime to mission-critical devices. It can help you discover hidden trends, spot anomalies, and conduct root-cause analysis in near real time. + +If you are new to Azure Time Series Insights and would like to learn more about the platform, please make sure you check out the Azure Time Series Insights official [documentation page][tsi_product_documentation]. + +# Time Series Insights client library for .NET +The Time Series Insights client library for .NET provides the following functionality: +- Retrieving and being able to make changes to the Time Series Insights environment model settings, such as changing the model name or default type ID. +- Retrieving and being able to add, update and remove Time Series instances. +- Retrieving and being able to make changes to the Time Series Insights environment types, such as creating, updating and deleting Time Series types. +- Retrieving and being able to make changes to the Time Series Insights hierarchies, such as creating, updating and deleting Time Series hierarchies. +- Querying raw events, computed series and aggregate series + +[Source Code][tsi_client_src] | [Package (NuGet)][tsi_nuget_package] | [Product documentation][tsi_product_documentation] | [Samples][tsi_samples] + +# Key concepts -You can explore the time series insights APIs (using the client library) using the samples project. +## TimeSeriesInsightsClient -## Creating the time series insights client +A `TimeSeriesInsightsClient` is the primary interface for developers using the Time Series Insights client library. It provides both synchronous and asynchronous operations to perform operations on a Time Series Insights environment. The `TimeSeriesInsightsClient` exposes several properties that a developer will use to perform specific operations on a Time Series Insights environment. For example, `ModelSettings` is the property that a developer can use to perform operations on the model settings of the TSI environment. `Instances` can be used to perform operations on TSI instances. Other properties include `Types`, `Hierarchies` and `Query`. + +## Creating TimeSeriesInsightsClient + +To create a new Time Series Insights client, you need the endpoint to an Azure Time Series Insights environment and supply credentials. +To use the [DefaultAzureCredential][DefaultAzureCredential] provider shown below, +or other credential providers provided with the Azure SDK, please install the Azure.Identity package: + +```PowerShell +Install-Package Azure.Identity +``` -To create a new time series insights client, you need the endpoint to an Azure Time Series Insights instance and supply credentials. -In the sample below, you can set `TsiEndpoint`, `TenantId`, `ClientId`, and `ClientSecret` as command-line arguments. -The client requires an instance of [TokenCredential](https://docs.microsoft.com/dotnet/api/azure.core.tokencredential?view=azure-dotnet). -In this samples, we illustrate how to use one derived class: ClientSecretCredential. +Set the values of the client ID, tenant ID, and client secret of the AAD application as environment variables: AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET. ```C# Snippet:TimeSeriesInsightsSampleCreateServiceClientWithClientSecret -// DefaultAzureCredential supports different authentication mechanisms and determines the appropriate credential type based of the environment it is executing in. +// DefaultAzureCredential supports different authentication mechanisms and determines the appropriate credential type based on the environment it is executing in. // It attempts to use multiple credential types in an order until it finds a working credential. var tokenCredential = new DefaultAzureCredential(); @@ -23,3 +44,616 @@ var client = new TimeSeriesInsightsClient( tokenCredential); ``` +# Time Series Insights Samples + +The following section provides several code snippets using the `client` created above, and covers the main functions of Time Series Insights. You can explore and learn more about the Time Series Insights client library APIs through using the samples project. + +- [Time Series Insights ID](#time-series-insights-id) +- [Time Series Insights Model Settings](#time-series-insights-model-settings) +- [Time Series Insights Instances](#time-series-insights-instances) +- [Time Series Insights Types](#time-series-insights-types) +- [Time Series Insights Hierarchies](#time-series-insights-hierarchies) +- [Time Series Insights Query](#time-series-insights-query) + +## Time Series Insights ID +A single Time Series ID value is composed of up to 3 string values that uniquely identify a Time Series instance. The keys that make up the Time Series ID are chosen when creating a Time Series Insights Gen2 environment through the Azure portal. The position of values must match Time Series ID properties specified on the environment and returned by Get Model Setting API. For example, if your Time Series Insights environment is setup with ID properties `Building`, `Floor` and `Room`, then this code snippet illustrates creating a Time Series instance ID using `TimeSeriesId` class for building 'Millennium', 'Floor2' and room '2A01'. Visit [this page][tsi_id_learn_more] to check out the best practices for choosing a Time Series ID. + +```csharp +var instanceId = new TimeSeriesId("Millennium", "Floor2", "2A01"); +``` + +## Time Series Insights Model Settings + +Use `ModelSettings` in [TimeSeriesInsightsClient](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsClient.cs) to learn more about the environment model settings, such as name, default type ID, and the properties that define the Time Series ID during environment creation. + +```C# Snippet:TimeSeriesInsightsSampleGetModelSettings +Response getModelSettingsResponse = await client.ModelSettings.GetAsync(); +Console.WriteLine($"Retrieved Time Series Insights model settings:\n{JsonSerializer.Serialize(getModelSettingsResponse.Value)}"); +``` + +Here's what a retrieved model settings object looks like. +```json +{ + "Name": "sampleModel", + "TimeSeriesIdProperties": [ + { + "Name": "Building", + "Type": { + "HasValue": true, + "Value": { + + } + } + }, + { + "Name": "Floor", + "Type": { + "HasValue": true, + "Value": { + + } + } + }, + { + "Name": "Room", + "Type": { + "HasValue": true, + "Value": { + + } + } + } + ], + "DefaultTypeId": "86fc3da5-a7cb-443a-b7c3-00a7d9ebb72d" +} +``` + +You can also use `ModelSettings` object to make changes to the model settings name and/or default type ID. + +```C# Snippet:TimeSeriesInsightsSampleUpdateModelSettingsName +Response updateModelSettingsNameResponse = await client.ModelSettings.UpdateNameAsync("NewModelSettingsName"); +Console.WriteLine($"Updated Time Series Insights model settings name:\n" + + $"{JsonSerializer.Serialize(updateModelSettingsNameResponse.Value)}"); +``` + +```C# Snippet:TimeSeriesInsightsSampleUpdateModelSettingsDefaultType +Response updateDefaultTypeIdResponse = await client.ModelSettings.UpdateDefaultTypeIdAsync(tsiTypeId); +Console.WriteLine($"Updated Time Series Insights model settings default type Id:\n" + + $"{JsonSerializer.Serialize(updateDefaultTypeIdResponse.Value)}"); +``` + +## Time Series Insights Instances + +Time Series Model instances are virtual representations of the time series themselves. To learn more about Time Series Model instances, make sure you visit [this page][tsi_instances_learn_more]. + +Use `Instances` in [TimeSeriesInsightsClient](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsClient.cs) to perform a variety of operations on the environment's instances. + +This code snippet demonstrates retrieving all created instances in your TSI environment. +```C# Snippet:TimeSeriesInsightsGetAllInstances +// Get all instances for the Time Series Insigths environment +AsyncPageable tsiInstances = client.Instances.GetAsync(); +await foreach (TimeSeriesInstance tsiInstance in tsiInstances) +{ + Console.WriteLine($"Retrieved Time Series Insights instance with Id '{tsiInstance.TimeSeriesId}' and name '{tsiInstance.Name}'."); +} +``` + +This code snippet demonstrates creating a list of Time Series instances in your environment. +```C# Snippet:TimeSeriesInsightsSampleCreateInstance +// Create a Time Series Instance object with the default Time Series Insights type Id. +// The default type Id can be obtained programmatically by using the ModelSettings client. +var instance = new TimeSeriesInstance(tsId, defaultTypeId) +{ + Name = "instance1", +}; + +var tsiInstancesToCreate = new List +{ + instance, +}; + +Response createInstanceErrors = await client + .Instances + .CreateOrReplaceAsync(tsiInstancesToCreate) + .ConfigureAwait(false); + +// The response of calling the API contains a list of error objects corresponding by position to the input parameter +// array in the request. If the error object is set to null, this means the operation was a success. +for (int i = 0; i < createInstanceErrors.Value.Length; i++) +{ + TimeSeriesId tsiId = tsiInstancesToCreate[i].TimeSeriesId; + + if (createInstanceErrors.Value[i] == null) + { + Console.WriteLine($"Created Time Series Insights instance with Id '{tsiId}'."); + } + else + { + Console.WriteLine($"Failed to create a Time Series Insights instance with Id '{tsiId}'."); + } +} +``` + +You can also retrieve specific instances by their unique identifier, or by the Time Series instance names. + +```C# Snippet:TimeSeriesInsightsGetnstancesById +// Get Time Series Insights instances by Id +var timeSeriesIds = new List +{ + tsId, +}; + +Response getByIdsResult = await client.Instances.GetAsync(timeSeriesIds).ConfigureAwait(false); + +/// The response of calling the API contains a list of instance or error objects corresponding by position to the array in the request. +/// Instance object is set when operation is successful and error object is set when operation is unsuccessful. +for (int i = 0; i < getByIdsResult.Value.Length; i++) +{ + InstancesOperationResult currentOperationResult = getByIdsResult.Value[i]; + + if (currentOperationResult.Instance != null) + { + Console.WriteLine($"Retrieved Time Series Insights instance with Id '{currentOperationResult.Instance.TimeSeriesId}' and name '{currentOperationResult.Instance.Name}'."); + } + else if (currentOperationResult.Error != null) + { + Console.WriteLine($"Failed to retrieve a Time Series Insights instance with Id '{timeSeriesIds[i]}'. Error message: '{currentOperationResult.Error.Message}'."); + } +} +``` + +Similarly, you can delete specific instances by their unique identifier, or by the Time Series instances names. + +```C# Snippet:TimeSeriesInsightsSampleDeleteInstanceById +var instancesToDelete = new List +{ + tsId, +}; + +Response deleteInstanceErrors = await client + .Instances + .DeleteAsync(instancesToDelete) + .ConfigureAwait(false); + +// The response of calling the API contains a list of error objects corresponding by position to the input parameter +// array in the request. If the error object is set to null, this means the operation was a success. +for (int i = 0; i < deleteInstanceErrors.Value.Length; i++) +{ + TimeSeriesId tsiId = instancesToDelete[i]; + + if (deleteInstanceErrors.Value[i] == null) + { + Console.WriteLine($"Deleted Time Series Insights instance with Id '{tsiId}'."); + } + else + { + Console.WriteLine($"Failed to delete a Time Series Insights instance with Id '{tsiId}'. Error Message: '{deleteInstanceErrors.Value[i].Message}'"); + } +} +``` + +This code snippet demonstrates replacing an existing Time Series instance. +```C# Snippet:TimeSeriesInsightsReplaceInstance +// Get Time Series Insights instances by Id +var instanceIdsToGet = new List +{ + tsId, +}; + +Response getInstancesByIdResult = await client.Instances.GetAsync(instanceIdsToGet).ConfigureAwait(false); + +TimeSeriesInstance instanceResult = getInstancesByIdResult.Value[0].Instance; +Console.WriteLine($"Retrieved Time Series Insights instance with Id '{instanceResult.TimeSeriesId}' and name '{instanceResult.Name}'."); + +// Now let's replace the instance with an updated name +instanceResult.Name = "newInstanceName"; + +var instancesToReplace = new List +{ + instanceResult, +}; + +Response replaceInstancesResult = await client.Instances.ReplaceAsync(instancesToReplace).ConfigureAwait(false); + +// The response of calling the API contains a list of error objects corresponding by position to the input parameter +// array in the request. If the error object is set to null, this means the operation was a success. +for (int i = 0; i < replaceInstancesResult.Value.Length; i++) +{ + TimeSeriesId tsiId = instancesToReplace[i].TimeSeriesId; + + TimeSeriesOperationError currentError = replaceInstancesResult.Value[i].Error; + + if (currentError != null) + { + Console.WriteLine($"Failed to replace Time Series Insights instance with Id '{tsiId}'. Error Message: '{currentError.Message}'."); + } + else + { + Console.WriteLine($"Replaced Time Series Insights instance with Id '{tsiId}'."); + } +} +``` + +## Time Series Insights Types +Use `Types` in [TimeSeriesInsightsClient](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsClient.cs) to create, retrieve, replace and delete Time Series types in your environment. + +This snippet demonstrates creating a Time Series type in your environment. + +```C# Snippet:TimeSeriesInsightsSampleCreateType +// Create a type with an aggregate variable +var timeSeriesTypes = new List(); + +var countExpression = new TimeSeriesExpression("count()"); +var aggregateVariable = new AggregateVariable(countExpression); +var variables = new Dictionary(); +variables.Add("aggregateVariable", aggregateVariable); + +timeSeriesTypes.Add(new TimeSeriesType("Type1", variables) { Id = "Type1Id" }); +timeSeriesTypes.Add(new TimeSeriesType("Type2", variables) { Id = "Type2Id" }); + +Response createTypesResult = await client + .Types + .CreateOrReplaceAsync(timeSeriesTypes) + .ConfigureAwait(false); + +// The response of calling the API contains a list of error objects corresponding by position to the input parameter array in the request. +// If the error object is set to null, this means the operation was a success. +for (int i = 0; i < createTypesResult.Value.Length; i++) +{ + if (createTypesResult.Value[i].Error == null) + { + Console.WriteLine($"Created Time Series type successfully."); + } + else + { + Console.WriteLine($"Failed to create a Time Series Insights type: {createTypesResult.Value[i].Error.Message}."); + } +} +``` + +This snippet demonstrates retrieving all created types in your environment in pages. You can enumerate an AsyncPageable object using the `async foreach` loop. + +```C# Snippet:TimeSeriesInsightsSampleGetAllTypes +// Get all Time Series types in the environment +AsyncPageable getAllTypesResponse = client.Types.GetTypesAsync(); + +await foreach (TimeSeriesType tsiType in getAllTypesResponse) +{ + Console.WriteLine($"Retrieved Time Series Insights type with Id: '{tsiType?.Id}' and Name: '{tsiType?.Name}'"); +} +``` + +This snippet highlights how you can retrieve a list of specific Time Series types by their unique identifiers or names. + +```C# Snippet:TimeSeriesInsightsSampleGetTypeById +// Code snippet below shows getting a default Type using Id +// The default type Id can be obtained programmatically by using the ModelSettings client. + +TimeSeriesModelSettings modelSettings = await client.ModelSettings.GetAsync().ConfigureAwait(false); +Response getTypeByIdResults = await client + .Types + .GetByIdAsync(new string[] { modelSettings.DefaultTypeId }) + .ConfigureAwait(false); + +// The response of calling the API contains a list of type or error objects corresponding by position to the input parameter array in the request. +// If the error object is set to null, this means the operation was a success. +for (int i = 0; i < getTypeByIdResults.Value.Length; i++) +{ + if (getTypeByIdResults.Value[i].Error == null) + { + Console.WriteLine($"Retrieved Time Series type with Id: '{getTypeByIdResults.Value[i].TimeSeriesType.Id}'."); + } + else + { + Console.WriteLine($"Failed to retrieve a Time Series type due to '{getTypeByIdResults.Value[i].Error.Message}'."); + } +} +``` + +Similarly, you can delete Time Series types by providing a list of Time Series type Ids or names. + +```C# Snippet:TimeSeriesInsightsSampleDeleteTypeById +// Delete Time Series types with Ids + +var typesIdsToDelete = new List { "Type1Id", " Type2Id" }; +Response deleteTypesResponse = await client + .Types + .DeleteByIdAsync(typesIdsToDelete) + .ConfigureAwait(false); + +// The response of calling the API contains a list of error objects corresponding by position to the input parameter +// array in the request. If the error object is set to null, this means the operation was a success. +foreach (var result in deleteTypesResponse.Value) +{ + if (result != null) + { + Console.WriteLine($"Failed to delete a Time Series Insights type: {result.Message}."); + } + else + { + Console.WriteLine($"Deleted a Time Series Insights type successfully."); + } +} +``` + +This code snippet demonstrates replacing an existing Time Series type. + +```C# Snippet:TimeSeriesInsightsSampleReplaceType +// Update variables with adding a new variable +foreach (TimeSeriesType type in timeSeriesTypes) +{ + type.Description = "Description"; +} + +Response updateTypesResult = await client + .Types + .CreateOrReplaceAsync(timeSeriesTypes) + .ConfigureAwait(false); + +// The response of calling the API contains a list of error objects corresponding by position to the input parameter array in the request. +// If the error object is set to null, this means the operation was a success. +for (int i = 0; i < updateTypesResult.Value.Length; i++) +{ + if (updateTypesResult.Value[i].Error == null) + { + Console.WriteLine($"Updated Time Series type successfully."); + } + else + { + Console.WriteLine($"Failed to update a Time Series Insights type due to: {updateTypesResult.Value[i].Error.Message}."); + } +} +``` + +## Time Series Insights Hierarchies + +Time Series Model hierarchies organize instances by specifying property names and their relationships. You can configure multiple hierarchies in a given Azure Time Series Insights Gen2 environment. A Time Series Model instance can map to a single hierarchy or multiple hierarchies (many-to-many relationship). To learn more about Time Series Model hierarchies, make sure you visit [this page][tsi_hierarchies_learn_more]. + +Use `Hierarchies` in [TimeSeriesInsightsClient](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsClient.cs) to perform a variety of operations on the environment's hierarchies. + +This code snippet demonstrates creating hierarchies in your Time Series Insights environment. + +```C# Snippet:TimeSeriesInsightsSampleCreateHierarchies +var hierarchySource = new TimeSeriesHierarchySource(); +hierarchySource.InstanceFieldNames.Add("hierarchyLevel1"); + +var tsiHierarchy = new TimeSeriesHierarchy("sampleHierarchy", hierarchySource) +{ + Id = "sampleHierarchyId" +}; + +var timeSeriesHierarchies = new List +{ + tsiHierarchy +}; + +// Create Time Series hierarchies +Response createHierarchiesResult = await client + .Hierarchies + .CreateOrReplaceAsync(timeSeriesHierarchies) + .ConfigureAwait(false); + +// The response of calling the API contains a list of error objects corresponding by position to the input parameter array in the request. +// If the error object is set to null, this means the operation was a success. +for (int i = 0; i < createHierarchiesResult.Value.Length; i++) +{ + if (createHierarchiesResult.Value[i].Error == null) + { + Console.WriteLine($"Created Time Series hierarchy successfully."); + } + else + { + Console.WriteLine($"Failed to create a Time Series hierarchy: {createHierarchiesResult.Value[i].Error.Message}."); + } +} +``` + +This code snippet demonstrates retrieving all hierarchies in your environment in pages. You can enumerate an AsyncPageable object using the `async foreach` loop. + +```C# Snippet:TimeSeriesInsightsSampleGetAllHierarchies +// Get all Time Series hierarchies in the environment +AsyncPageable getAllHierarchies = client.Hierarchies.GetAsync(); +await foreach (TimeSeriesHierarchy hierarchy in getAllHierarchies) +{ + Console.WriteLine($"Retrieved Time Series Insights hierarchy with Id: '{hierarchy.Id}' and Name: '{hierarchy.Name}'."); +} +``` + +You can use a list of hierarchy IDs or names to get specific hierarchies, as demonstrated in this code snippet. + +```C# Snippet:TimeSeriesInsightsSampleGetHierarchiesById +var tsiHierarchyIds = new List +{ + "sampleHierarchyId" +}; + +Response getHierarchiesByIdsResult = await client + .Hierarchies + .GetByIdAsync(tsiHierarchyIds) + .ConfigureAwait(false); + +// The response of calling the API contains a list of hieararchy or error objects corresponding by position to the input parameter array in the request. +// If the error object is set to null, this means the operation was a success. +for (int i = 0; i < getHierarchiesByIdsResult.Value.Length; i++) +{ + if (getHierarchiesByIdsResult.Value[i].Error == null) + { + Console.WriteLine($"Retrieved Time Series hieararchy with Id: '{getHierarchiesByIdsResult.Value[i].Hierarchy.Id}'."); + } + else + { + Console.WriteLine($"Failed to retrieve a Time Series hieararchy due to '{getHierarchiesByIdsResult.Value[i].Error.Message}'."); + } +} +``` + +Similarly, you can use a list of hierarchies Ids or names to be able to delete hierarchies, as demonstrated in this code snippet. +```C# Snippet:TimeSeriesInsightsSampleDeleteHierarchiesById +// Delete Time Series hierarchies with Ids +var tsiHierarchyIdsToDelete = new List +{ + "sampleHiearchyId" +}; + +Response deleteHierarchiesResponse = await client + .Hierarchies + .DeleteByIdAsync(tsiHierarchyIdsToDelete) + .ConfigureAwait(false); + +// The response of calling the API contains a list of error objects corresponding by position to the input parameter +// array in the request. If the error object is set to null, this means the operation was a success. +foreach (TimeSeriesOperationError result in deleteHierarchiesResponse.Value) +{ + if (result != null) + { + Console.WriteLine($"Failed to delete a Time Series Insights hierarchy: {result.Message}."); + } + else + { + Console.WriteLine($"Deleted a Time Series Insights hierarchy successfully."); + } +} +``` + +This code snippet demonstrates replacing a Time Series hierarchy. + +```C# Snippet:TimeSeriesInsightsSampleReplaceHierarchies +// Update hierarchies with adding a new instance field +foreach (TimeSeriesHierarchy hierarchy in timeSeriesHierarchies) +{ + hierarchy.Source.InstanceFieldNames.Add("hierarchyLevel2"); +} + +Response updateHierarchiesResult = await client + .Hierarchies + .CreateOrReplaceAsync(timeSeriesHierarchies) + .ConfigureAwait(false); + +// The response of calling the API contains a list of error objects corresponding by position to the input parameter array in the request. +// If the error object is set to null, this means the operation was a success. +for (int i = 0; i < updateHierarchiesResult.Value.Length; i++) +{ + if (updateHierarchiesResult.Value[i].Error == null) + { + Console.WriteLine($"Updated Time Series hierarchy successfully."); + } + else + { + Console.WriteLine($"Failed to update a Time Series Insights hierarchy due to: {updateHierarchiesResult.Value[i].Error.Message}."); + } +} +``` + +## Time Series Insights Query + +Use `Query` in [TimeSeriesInsightsClient](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsClient.cs) to query for: +- Raw events for a given Time Series ID and search span. +- Computed values and the associated event timestamps by applying calculations defined by variables on raw events. These variables can be defined in either the Time Series Model or provided inline in the query. +- Aggregated values and the associated interval timestamps by applying calculations defined by variables on raw events. These variables can be defined in either the Time Series Model or provided inline in the query. + +Response for the `Query` APIs are of type `QueryAnalyzer`. The QueryAnalyzer allows a developer to query for pages of results, while being able to perform operations on the result set as a whole. For example, to get a list of `TimeSeriesPoint` in pages, call the `GetResultsAsync` method on the `QueryAnalyzer` object. You can enumerate an AsyncPageable object using the `async foreach` loop. + +This code snippets demonstrates retrieving raw events from Time Series Insights environment using a start and end time. + +```C# Snippet:TimeSeriesInsightsSampleQueryEvents +Console.WriteLine("\n\nQuery for raw temperature events over the past 10 minutes.\n"); + +// Get events from last 10 minute +DateTimeOffset endTime = DateTime.UtcNow; +DateTimeOffset startTime = endTime.AddMinutes(-10); + +QueryAnalyzer temperatureEventsQueryAnalyzer = client.Query.CreateEventsQueryAnalyzer(tsId, startTime, endTime); +await foreach (TimeSeriesPoint point in temperatureEventsQueryAnalyzer.GetResultsAsync()) +{ + double? temperatureValue = (double?)point.GetValue("Temperature"); + Console.WriteLine($"{point.Timestamp} - Temperature: {temperatureValue}"); +} +``` + +The client library also provides a way to query for raw events with using a time span interval. +```C# Snippet:TimeSeriesInsightsSampleQueryEventsUsingTimeSpan +Console.WriteLine("\n\nQuery for raw humidity events over the past 30 seconds.\n"); + +QueryAnalyzer humidityEventsQueryAnalyzer = client.Query.CreateEventsQueryAnalyzer(tsId, TimeSpan.FromSeconds(30)); +await foreach (TimeSeriesPoint point in humidityEventsQueryAnalyzer.GetResultsAsync()) +{ + double? humidityValue = (double?)point.GetValue("Humidity"); + Console.WriteLine($"{point.Timestamp} - Humidity: {humidityValue}"); +} +``` + +This code snippet demonstrates querying for series events. In this snippet, we query for the temperature both in Celsius and fahrenheit. Hence, we create two [numeric variables][tsi_numeric_variables], one for the Celsius and the other for Fahrenheit. These variables are then added as inline variables to the request options. + +```C# Snippet:TimeSeriesInsightsSampleQuerySeries +Console.WriteLine("\n\nQuery for temperature series in Celsius and Fahrenheit over the past 10 minutes.\n"); + +DateTimeOffset endTime = DateTime.UtcNow; +DateTimeOffset startTime = endTime.AddMinutes(-10); + +var celsiusVariable = new NumericVariable( + new TimeSeriesExpression("$event.Temperature"), + new TimeSeriesExpression("avg($value)")); +var fahrenheitVariable = new NumericVariable( + new TimeSeriesExpression("$event.Temperature * 1.8 + 32"), + new TimeSeriesExpression("avg($value)")); + +var querySeriesRequestOptions = new QuerySeriesRequestOptions(); +querySeriesRequestOptions.InlineVariables["TemperatureInCelsius"] = celsiusVariable; +querySeriesRequestOptions.InlineVariables["TemperatureInFahrenheit"] = fahrenheitVariable; + +QueryAnalyzer seriesQueryAnalyzer = client.Query.CreateSeriesQueryAnalyzer( + tsId, + startTime, + endTime, + querySeriesRequestOptions); + +await foreach (TimeSeriesPoint point in seriesQueryAnalyzer.GetResultsAsync()) +{ + double? tempInCelsius = (double?)point.GetValue("TemperatureInCelsius"); + double? tempInFahrenheit = (double?)point.GetValue("TemperatureInFahrenheit"); + + Console.WriteLine($"{point.Timestamp} - Average temperature in Celsius: {tempInCelsius}. Average temperature in Fahrenheit: {tempInFahrenheit}."); +} +``` + +This code snippet demonstrates querying for aggregated values. More specifically, the number of temperature events that the TSI environment has ingested over the past 3 minutes, in 1-minute time slots. In order to achieve this, a `count` [AggregateVariable][tsi_aggregate_variables] is added as an inline variable to the request options. + +```C# Snippet:TimeSeriesInsightsSampleQueryAggregateSeriesWithAggregateVariable +Console.WriteLine("\n\nCount the number of temperature events over the past 3 minutes, in 1-minute time slots.\n"); + +// Get the count of events in 60-second time slots over the past 3 minutes +DateTimeOffset endTime = DateTime.UtcNow; +DateTimeOffset startTime = endTime.AddMinutes(-3); + +var aggregateVariable = new AggregateVariable( + new TimeSeriesExpression("count()")); + +var aggregateSeriesRequestOptions = new QueryAggregateSeriesRequestOptions(); +aggregateSeriesRequestOptions.InlineVariables["Count"] = aggregateVariable; +aggregateSeriesRequestOptions.ProjectedVariables.Add("Count"); + +QueryAnalyzer aggregateSeriesQueryAnalyzer = client.Query.CreateAggregateSeriesQueryAnalyzer( + tsId, + startTime, + endTime, + TimeSpan.FromSeconds(60), + aggregateSeriesRequestOptions); + +await foreach (TimeSeriesPoint point in aggregateSeriesQueryAnalyzer.GetResultsAsync()) +{ + long? temperatureCount = (long?)point.GetValue("Count"); + Console.WriteLine($"{point.Timestamp} - Temperature count: {temperatureCount}"); +} +``` + + +[tsi_client_src]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src +[tsi_nuget_package]: https://www.bing.com +[tsi_product_documentation]: https://docs.microsoft.com/azure/time-series-insights/ +[tsi_samples]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/Readme.md +[DefaultAzureCredential]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/identity/Azure.Identity/README.md +[tsi_instances_learn_more]: https://docs.microsoft.com/azure/time-series-insights/concepts-model-overview#time-series-model-instances +[tsi_id_learn_more]: https://docs.microsoft.com/azure/time-series-insights/how-to-select-tsid +[tsi_hierarchies_learn_more]: https://docs.microsoft.com/azure/time-series-insights/concepts-model-overview#time-series-model-hierarchies +[tsi_numeric_variables]: https://docs.microsoft.com/azure/time-series-insights/concepts-variables#numeric-variables +[tsi_aggregate_variables]: https://docs.microsoft.com/azure/time-series-insights/concepts-variables#aggregate-variables \ No newline at end of file diff --git a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/HierarchiesSamples.cs b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/HierarchiesSamples.cs index 2a9802a7f0190..3750446f14034 100644 --- a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/HierarchiesSamples.cs +++ b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/HierarchiesSamples.cs @@ -21,13 +21,13 @@ public async Task RunSamplesAsync(TimeSeriesInsightsClient client) PrintHeader("TIME SERIES INSIGHTS HIERARCHIES SAMPLE"); #region Snippet:TimeSeriesInsightsSampleCreateHierarchies - var tsiHierarchyName = "sampleHierarchy"; - var tsiInstanceField1 = "hierarchyLevel1"; var hierarchySource = new TimeSeriesHierarchySource(); - hierarchySource.InstanceFieldNames.Add(tsiInstanceField1); + hierarchySource.InstanceFieldNames.Add("hierarchyLevel1"); - var tsiHierarchy = new TimeSeriesHierarchy(tsiHierarchyName, hierarchySource); - tsiHierarchy.Id = "sampleHierarchyId"; + var tsiHierarchy = new TimeSeriesHierarchy("sampleHierarchy", hierarchySource) + { + Id = "sampleHierarchyId" + }; var timeSeriesHierarchies = new List { @@ -66,10 +66,9 @@ public async Task RunSamplesAsync(TimeSeriesInsightsClient client) #region Snippet:TimeSeriesInsightsSampleReplaceHierarchies // Update hierarchies with adding a new instance field - var tsiInstanceField2 = "hierarchyLevel2"; foreach (TimeSeriesHierarchy hierarchy in timeSeriesHierarchies) { - hierarchy.Source.InstanceFieldNames.Add(tsiInstanceField2); + hierarchy.Source.InstanceFieldNames.Add("hierarchyLevel2"); } Response updateHierarchiesResult = await client diff --git a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/Program.cs b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/Program.cs index b895a2d98b623..21af7d3fb3eb5 100644 --- a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/Program.cs +++ b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/Program.cs @@ -74,7 +74,7 @@ private static TimeSeriesInsightsClient GetTimeSeriesInsightsClient(string tenan #region Snippet:TimeSeriesInsightsSampleCreateServiceClientWithClientSecret - // DefaultAzureCredential supports different authentication mechanisms and determines the appropriate credential type based of the environment it is executing in. + // DefaultAzureCredential supports different authentication mechanisms and determines the appropriate credential type based on the environment it is executing in. // It attempts to use multiple credential types in an order until it finds a working credential. var tokenCredential = new DefaultAzureCredential(); diff --git a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/QuerySamples.cs b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/QuerySamples.cs index f8490fe1ae4f2..6b07342015596 100644 --- a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/QuerySamples.cs +++ b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/QuerySamples.cs @@ -78,7 +78,7 @@ private async Task RunQuerySeriesSample(TimeSeriesInsightsClient client, TimeSer { // Query for two series, one with the temperature values in Celsius and another in Fahrenheit #region Snippet:TimeSeriesInsightsSampleQuerySeries - Console.WriteLine("\n\nQuery for temperature series in celsius and fahrenheit over the past 10 minutes.\n"); + Console.WriteLine("\n\nQuery for temperature series in Celsius and Fahrenheit over the past 10 minutes.\n"); DateTimeOffset endTime = DateTime.UtcNow; DateTimeOffset startTime = endTime.AddMinutes(-10); @@ -141,7 +141,7 @@ private async Task RunQueryAggregateSeriesSample(TimeSeriesInsightsClient client #endregion Snippet:TimeSeriesInsightsSampleQueryAggregateSeriesWithNumericVariable #region Snippet:TimeSeriesInsightsSampleQueryAggregateSeriesWithAggregateVariable - Console.WriteLine("\n\nCount the number of temperature vents over the past 3 minutes, in 1-minute time slots.\n"); + Console.WriteLine("\n\nCount the number of temperature events over the past 3 minutes, in 1-minute time slots.\n"); // Get the count of events in 60-second time slots over the past 3 minutes DateTimeOffset endTime = DateTime.UtcNow; diff --git a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/TypesSamples.cs b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/TypesSamples.cs index 5608c1cc449e9..baa097e571bbc 100644 --- a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/TypesSamples.cs +++ b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/samples/TimeSeriesInsightsClientSample/TypesSamples.cs @@ -21,29 +21,16 @@ public async Task RunSamplesAsync(TimeSeriesInsightsClient client) PrintHeader("TIME SERIES INSIGHTS TYPES SAMPLE"); #region Snippet:TimeSeriesInsightsSampleCreateType - // Create an aggregate type + // Create a type with an aggregate variable var timeSeriesTypes = new List(); var countExpression = new TimeSeriesExpression("count()"); var aggregateVariable = new AggregateVariable(countExpression); var variables = new Dictionary(); - var variableName = "aggregateVariable"; - variables.Add(variableName, aggregateVariable); + variables.Add("aggregateVariable", aggregateVariable); - var timeSeriesTypesProperties = new Dictionary - { - { "Type1", "Type1Id"}, - { "Type2", "Type2Id"} - }; - - foreach (KeyValuePair property in timeSeriesTypesProperties) - { - var type = new TimeSeriesType(property.Key, variables) - { - Id = property.Value - }; - timeSeriesTypes.Add(type); - } + timeSeriesTypes.Add(new TimeSeriesType("Type1", variables) { Id = "Type1Id" }); + timeSeriesTypes.Add(new TimeSeriesType("Type2", variables) { Id = "Type2Id" }); Response createTypesResult = await client .Types diff --git a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsClient.cs b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsClient.cs index bb86ff123ae5e..0d032aa62ac74 100644 --- a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsClient.cs +++ b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsClient.cs @@ -65,7 +65,7 @@ public class TimeSeriesInsightsClient /// /// /// - /// // DefaultAzureCredential supports different authentication mechanisms and determines the appropriate credential type based of the environment it is executing in. + /// // DefaultAzureCredential supports different authentication mechanisms and determines the appropriate credential type based on the environment it is executing in. /// // It attempts to use multiple credential types in an order until it finds a working credential. /// var tokenCredential = new DefaultAzureCredential(); /// diff --git a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsHierarchies.cs b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsHierarchies.cs index 5bd9fd82a9ad1..ccf09d86bb49b 100644 --- a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsHierarchies.cs +++ b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsHierarchies.cs @@ -416,13 +416,13 @@ public virtual Response GetById( /// /// /// - /// var tsiHierarchyName = "sampleHierarchy"; - /// var tsiInstanceField1 = "hierarchyLevel1"; /// var hierarchySource = new TimeSeriesHierarchySource(); - /// hierarchySource.InstanceFieldNames.Add(tsiInstanceField1); + /// hierarchySource.InstanceFieldNames.Add("hierarchyLevel1"); /// - /// var tsiHierarchy = new TimeSeriesHierarchy(tsiHierarchyName, hierarchySource); - /// tsiHierarchy.Id = "sampleHierarchyId"; + /// var tsiHierarchy = new TimeSeriesHierarchy("sampleHierarchy", hierarchySource) + /// { + /// Id = "sampleHierarchyId" + /// }; /// /// var timeSeriesHierarchies = new List<TimeSeriesHierarchy> /// { diff --git a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsQuery.cs b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsQuery.cs index a0876c15be969..8e9904ce08372 100644 --- a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsQuery.cs +++ b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsQuery.cs @@ -149,7 +149,7 @@ public virtual QueryAnalyzer CreateEventsQueryAnalyzer( /// The object that can be used to retrieve the pageable list . /// /// - /// Console.WriteLine("\n\nQuery for temperature series in celsius and fahrenheit over the past 10 minutes.\n"); + /// Console.WriteLine("\n\nQuery for temperature series in Celsius and Fahrenheit over the past 10 minutes.\n"); /// /// DateTimeOffset endTime = DateTime.UtcNow; /// DateTimeOffset startTime = endTime.AddMinutes(-10); @@ -261,7 +261,7 @@ public virtual QueryAnalyzer CreateSeriesQueryAnalyzer( /// The object that can be used to retrieve the pageable list . /// /// - /// Console.WriteLine("\n\nCount the number of temperature vents over the past 3 minutes, in 1-minute time slots.\n"); + /// Console.WriteLine("\n\nCount the number of temperature events over the past 3 minutes, in 1-minute time slots.\n"); /// /// // Get the count of events in 60-second time slots over the past 3 minutes /// DateTimeOffset endTime = DateTime.UtcNow; diff --git a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsTypes.cs b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsTypes.cs index 720528bdc517e..ad74c9a863fbf 100644 --- a/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsTypes.cs +++ b/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/src/TimeSeriesInsightsTypes.cs @@ -416,29 +416,16 @@ public virtual Response GetById( /// /// /// - /// // Create an aggregate type + /// // Create a type with an aggregate variable /// var timeSeriesTypes = new List<TimeSeriesType>(); /// /// var countExpression = new TimeSeriesExpression("count()"); /// var aggregateVariable = new AggregateVariable(countExpression); /// var variables = new Dictionary<string, TimeSeriesVariable>(); - /// var variableName = "aggregateVariable"; - /// variables.Add(variableName, aggregateVariable); + /// variables.Add("aggregateVariable", aggregateVariable); /// - /// var timeSeriesTypesProperties = new Dictionary<string, string> - /// { - /// { "Type1", "Type1Id"}, - /// { "Type2", "Type2Id"} - /// }; - /// - /// foreach (KeyValuePair<string, string> property in timeSeriesTypesProperties) - /// { - /// var type = new TimeSeriesType(property.Key, variables) - /// { - /// Id = property.Value - /// }; - /// timeSeriesTypes.Add(type); - /// } + /// timeSeriesTypes.Add(new TimeSeriesType("Type1", variables) { Id = "Type1Id" }); + /// timeSeriesTypes.Add(new TimeSeriesType("Type2", variables) { Id = "Type2Id" }); /// /// Response<TimeSeriesTypeOperationResult[]> createTypesResult = await client /// .Types