Reputation: 974
I currently do have a working method which is based on the currently released example code at https://github.com/Azure-Samples/Azure-Time-Series-Insights/tree/master/csharp-tsi-preview-sample
The used types within the following method are created with AutoRest as guided in the GitHub sample: https://github.com/Azure/azure-rest-api-specs/tree/master/specification/timeseriesinsights/data-plane
My initial try is the following:
public async Task<T> GetLatestEventValue<T>(object[] timeSeriesId, string tsiPropertyName,
DateTimeRange searchSpan)
{
var client = await _tsiClientFactory.GetTimeSeriesInsightsClient();
var propertyType = GetPropertyType(typeof(T));
if (propertyType == null) throw new InvalidOperationException($"Unsupported property type (${typeof(T)})");
string continuationToken = null;
do
{
QueryResultPage queryResponse = await client.Query.ExecuteAsync(
new QueryRequest(
getEvents: new GetEvents(
timeSeriesId: timeSeriesId,
searchSpan: searchSpan,
filter: null,
projectedProperties: new List<EventProperty>()
{new EventProperty(tsiPropertyName, propertyType)})),
continuationToken: continuationToken);
var latestEventIndex = GetLatestEventPropertyIndex(queryResponse.Timestamps);
var lastValue = queryResponse.Properties
.FirstOrDefault()
?.Values[latestEventIndex];
if (lastValue != null)
{
return (T)lastValue;
}
continuationToken = queryResponse.ContinuationToken;
} while (continuationToken != null);
return default;
}
And usage of the method (timeSeriesId
is the same as in Microsoft public example):
var repository = new TsiRepository(_factory);
object[] timeSeriesId = new object[] { "2da181d7-8346-4cf2-bd94-a17742237429" };
var today = DateTime.Now;
var earlierDateTime = today.AddDays(-1);
var searchSpan = new DateTimeRange(earlierDateTime.ToUniversalTime(), today.ToUniversalTime());
var result = await repository.GetLatestEventValue<double>(timeSeriesId, "data", searchSpan);
The approach presented above kinda works but does not feel optimal. Is there a simpler way to query the latest event and its value for a given time-series instance? Maybe to take advance of the Time Series Expression (Tsx)
capabilities?
Upvotes: 1
Views: 307
Reputation: 974
After some time spent searching for the answer, my approach is to take advance of the TSX query syntax for last value and add an additional parameter which decides that the query is run only on the warm storage of TSI. This seems to speed things up nicely. The default is cold storage.
public async Task<T> RunAggregateSeriesLastValueAsync<T>(object[] timeSeriesId, DateTimeRange searchSpan)
{
var interval = searchSpan.To - searchSpan.FromProperty;
string continuationToken = null;
object lastValue;
do
{
QueryResultPage queryResponse = await _tsiClient.Query.ExecuteAsync(
new QueryRequest(
aggregateSeries: new AggregateSeries(
timeSeriesId: timeSeriesId,
searchSpan: searchSpan,
filter: null,
interval: interval,
projectedVariables: new[] { "Last_Numeric" },
inlineVariables: new Dictionary<string, Variable>()
{
["Last_Numeric"] = new NumericVariable(
value: new Tsx("$event.value"),
aggregation: new Tsx("last($value)"))
})),
storeType: "WarmStore", // Speeds things up since only warm storage is used
continuationToken: continuationToken)
lastValue = queryResponse.Properties
.FirstOrDefault()
?.Values.LastOrDefault(v => v != null)
continuationToken = queryResponse.ContinuationToken;
} while (continuationToken != null)
return (T)lastValue;
}
Upvotes: 2