public async Task <NumbersTermStatsResult> GetNumbersTermsStatsAsync(string term, IEnumerable <FieldAggregation> fields, DateTime utcStart, DateTime utcEnd, string systemFilter, string userFilter = null, TimeSpan?displayTimeOffset = null, int max = 25) { var allowedTerms = new[] { "organization_id", "project_id", "stack_id", "tags", "version" }; if (!allowedTerms.Contains(term)) { throw new ArgumentException("Must be a valid term.", nameof(term)); } if (!displayTimeOffset.HasValue) { displayTimeOffset = TimeSpan.Zero; } var filter = new ElasticQuery() .WithSystemFilter(systemFilter) .WithFilter(userFilter) .WithDateRange(utcStart, utcEnd, EventIndex.Fields.PersistentEvent.Date) .WithIndices(utcStart, utcEnd, $"'{_eventIndex.VersionedName}-'yyyyMM"); // if no start date then figure out first event date if (!filter.DateRanges.First().UseStartDate) { await UpdateFilterStartDateRangesAsync(filter, utcEnd).AnyContext(); } utcStart = filter.DateRanges.First().GetStartDate(); utcEnd = filter.DateRanges.First().GetEndDate(); var response = await _elasticClient.SearchAsync <PersistentEvent>(s => s .SearchType(SearchType.Count) .IgnoreUnavailable() .Index(filter.Indices.Count > 0 ? String.Join(",", filter.Indices) : _eventIndex.AliasName) .Query(_queryBuilder.BuildQuery <PersistentEvent>(filter)) .Aggregations(agg => BuildAggregations(agg .Terms("terms", t => BuildTermSort(t .Field(term) .Size(max) .Aggregations(agg2 => BuildAggregations(agg2 .Min("first_occurrence", o => o.Field(ev => ev.Date)) .Max("last_occurrence", o => o.Field(ev => ev.Date)), fields) ), fields) ), fields) ) ).AnyContext(); if (!response.IsValid) { _logger.Error("Retrieving stats failed: {0}", response.ServerError.Error); throw new ApplicationException("Retrieving stats failed."); } var stats = new NumbersTermStatsResult { Total = response.Total, Start = utcStart.SafeAdd(displayTimeOffset.Value), End = utcEnd.SafeAdd(displayTimeOffset.Value), Numbers = GetNumbers(response.Aggs, fields) }; var terms = response.Aggs.Terms("terms"); if (terms != null) { stats.Terms.AddRange(terms.Items.Select(i => { var item = new NumbersTermStatsItem { Total = i.DocCount, Term = i.Key, Numbers = GetNumbers(i, fields) }; var termFirstOccurrence = i.Min("first_occurrence"); if (termFirstOccurrence?.Value != null) { item.FirstOccurrence = termFirstOccurrence.Value.Value.ToDateTime().SafeAdd(displayTimeOffset.Value); } var termLastOccurrence = i.Max("last_occurrence"); if (termLastOccurrence?.Value != null) { item.LastOccurrence = termLastOccurrence.Value.Value.ToDateTime().SafeAdd(displayTimeOffset.Value); } return(item); })); } return(stats); }
public async Task <NumbersTermStatsResult> GetNumbersTermsStatsAsync(string term, IEnumerable <FieldAggregation> fields, DateTime utcStart, DateTime utcEnd, IExceptionlessSystemFilterQuery systemFilter, string userFilter = null, TimeSpan?displayTimeOffset = null, int max = 25) { var allowedTerms = new[] { "organization_id", "project_id", "stack_id", "tags", "version" }; if (!allowedTerms.Contains(term)) { throw new ArgumentException("Must be a valid term.", nameof(term)); } if (!displayTimeOffset.HasValue) { displayTimeOffset = TimeSpan.Zero; } var filter = new ElasticQuery() .WithSystemFilter(systemFilter) .WithFilter(userFilter) .WithDateRange(utcStart, utcEnd, EventIndexType.Fields.Date) .WithIndexes(utcStart, utcEnd); // if no start date then figure out first event date if (!filter.DateRanges.First().UseStartDate) { await UpdateFilterStartDateRangesAsync(filter, utcEnd).AnyContext(); } utcStart = filter.DateRanges.First().GetStartDate(); utcEnd = filter.DateRanges.First().GetEndDate(); var descriptor = new SearchDescriptor <PersistentEvent>() .SearchType(SearchType.Count) .IgnoreUnavailable() .Indices(_configuration.Events.Event.GetIndexesByQuery(filter)) .Type(_configuration.Events.Event.Name) .Aggregations(agg => BuildAggregations(agg .Terms("terms", t => BuildTermSort(t .Field(term) .Size(max) .Aggregations(agg2 => BuildAggregations(agg2 .Min("first_occurrence", o => o.Field(ev => ev.Date)) .Max("last_occurrence", o => o.Field(ev => ev.Date)), fields) ), fields) ), fields) ); _configuration.Events.Event.QueryBuilder.ConfigureSearch(filter, GetQueryOptions(), descriptor); var response = await _configuration.Client.SearchAsync <PersistentEvent>(descriptor).AnyContext(); _logger.Trace(() => response.GetRequest()); if (!response.IsValid) { string message = $"Retrieving stats failed: {response.GetErrorMessage()}"; _logger.Error().Exception(response.ConnectionStatus.OriginalException).Message(message).Property("request", response.GetRequest()).Write(); throw new ApplicationException(message, response.ConnectionStatus.OriginalException); } var stats = new NumbersTermStatsResult { Total = response.Total, Start = utcStart.SafeAdd(displayTimeOffset.Value), End = utcEnd.SafeAdd(displayTimeOffset.Value), Numbers = GetNumbers(response.Aggs, fields) }; var terms = response.Aggs.Terms("terms"); if (terms != null) { stats.Terms.AddRange(terms.Items.Select(i => { var item = new NumbersTermStatsItem { Total = i.DocCount, Term = i.Key, Numbers = GetNumbers(i, fields) }; var termFirstOccurrence = i.Min("first_occurrence"); if (termFirstOccurrence?.Value != null) { item.FirstOccurrence = termFirstOccurrence.Value.Value.ToDateTime().SafeAdd(displayTimeOffset.Value); } var termLastOccurrence = i.Max("last_occurrence"); if (termLastOccurrence?.Value != null) { item.LastOccurrence = termLastOccurrence.Value.Value.ToDateTime().SafeAdd(displayTimeOffset.Value); } return(item); })); } return(stats); }