public DynamicAggregationQuery <T> AndAggregateOn(Expression <Func <T, object> > path, string displayName = null) { var propertyPath = path.ToPropertyPath('_'); var rangeType = GetRangeType(path); if (rangeType != RangeType.None) { var tmp = FieldUtil.ApplyRangeSuffixIfNecessary(propertyPath, rangeType); _renames[propertyPath] = tmp; propertyPath = tmp; } if (displayName == null) { displayName = propertyPath; } if (_facets.Count > 0) { if (_facets.Any(facet => facet.DisplayName == displayName)) { throw new InvalidOperationException("Cannot use the more than one aggregation function with the same name/without name"); } } _facets.Add(new AggregationQuery <T> { Name = propertyPath, DisplayName = displayName }); return(this); }
private static void ApplyAggregation(Facet facet, FacetValue value, ArraySegment <int> docsInQuery, IndexReader indexReader, int docBase, IState state) { var name = facet.AggregationField; var rangeType = FieldUtil.GetRangeTypeFromFieldName(name); if (rangeType == RangeType.None) { name = FieldUtil.ApplyRangeSuffixIfNecessary(facet.AggregationField, RangeType.Double); rangeType = RangeType.Double; } long[] longs = null; double[] doubles = null; switch (rangeType) { case RangeType.Long: longs = FieldCache_Fields.DEFAULT.GetLongs(indexReader, name, state); break; case RangeType.Double: doubles = FieldCache_Fields.DEFAULT.GetDoubles(indexReader, name, state); break; default: throw new InvalidOperationException("Invalid range type for " + facet.Name + ", don't know how to handle " + rangeType); } for (int index = 0; index < docsInQuery.Count; index++) { var doc = docsInQuery.Array[index]; var currentVal = rangeType == RangeType.Long ? longs[doc - docBase] : doubles[doc - docBase]; if ((facet.Aggregation & FacetAggregation.Max) == FacetAggregation.Max) { value.Max = Math.Max(value.Max ?? double.MinValue, currentVal); } if ((facet.Aggregation & FacetAggregation.Min) == FacetAggregation.Min) { value.Min = Math.Min(value.Min ?? double.MaxValue, currentVal); } if ((facet.Aggregation & FacetAggregation.Sum) == FacetAggregation.Sum) { value.Sum = currentVal + (value.Sum ?? 0d); } if ((facet.Aggregation & FacetAggregation.Average) == FacetAggregation.Average) { value.Average = currentVal + (value.Average ?? 0d); } } }
public static Dictionary <string, FacetResult> Parse(IReadOnlyList <Facet> facets, out Dictionary <string, Facet> defaultFacets, out Dictionary <string, List <ParsedRange> > rangeFacets) { var results = new Dictionary <string, FacetResult>(); defaultFacets = new Dictionary <string, Facet>(); rangeFacets = new Dictionary <string, List <ParsedRange> >(); foreach (var facet in facets) { var key = string.IsNullOrWhiteSpace(facet.DisplayName) ? facet.Name : facet.DisplayName; defaultFacets[key] = facet; if (facet.Aggregation != FacetAggregation.Count && facet.Aggregation != FacetAggregation.None) { if (string.IsNullOrEmpty(facet.AggregationField)) { throw new InvalidOperationException($"Facet {facet.Name} cannot have aggregation set to {facet.Aggregation} without having a value in AggregationField"); } if (facet.AggregationField.EndsWith(Constants.Documents.Indexing.Fields.RangeFieldSuffix) == false) { var rangeType = FacetedQueryHelper.GetRangeTypeForAggregationType(facet.AggregationType); facet.AggregationField = FieldUtil.ApplyRangeSuffixIfNecessary(facet.AggregationField, rangeType); } } switch (facet.Mode) { case FacetMode.Default: results[key] = new FacetResult(); break; case FacetMode.Ranges: rangeFacets[key] = facet.Ranges .Select(range => ParseRange(facet.Name, range)) .ToList(); results[key] = new FacetResult { Values = facet.Ranges .Select(range => new FacetValue { Range = range }) .ToList() }; break; default: throw new ArgumentException(string.Format("Could not understand '{0}'", facet.Mode)); } } return(results); }
private static void ApplyAggregation(Dictionary <FacetAggregationField, FacetedQueryParser.FacetResult.Aggregation> aggregations, FacetValues values, ArraySegment <int> docsInQuery, IndexReader indexReader, int docBase, IState state) { foreach (var kvp in aggregations) { if (string.IsNullOrEmpty(kvp.Key.Name)) // Count { continue; } var value = values.Get(kvp.Key); var name = FieldUtil.ApplyRangeSuffixIfNecessary(kvp.Key.Name, RangeType.Double); var doubles = FieldCache_Fields.DEFAULT.GetDoubles(indexReader, name, state); var val = kvp.Value; double min = value.Min ?? double.MaxValue, max = value.Max ?? double.MinValue, sum = value.Sum ?? 0, avg = value.Average ?? 0; int[] array = docsInQuery.Array; for (var index = 0; index < docsInQuery.Count; index++) { var doc = array[index]; var currentVal = doubles[doc - docBase]; sum += currentVal; avg += currentVal; min = Math.Min(min, currentVal); max = Math.Max(max, currentVal); } if (val.Min) { value.Min = min; } if (val.Average) { value.Average = avg; } if (val.Max) { value.Max = max; } if (val.Sum) { value.Sum = sum; } } }
private void HandleRangeFacets(KeyValuePair <string, FacetedQueryParser.FacetResult> result, List <ReaderFacetInfo> returnedReaders, CancellationToken token) { var needToApplyAggregation = result.Value.Aggregations.Count > 0; foreach (var readerFacetInfo in returnedReaders) { var name = FieldUtil.ApplyRangeSuffixIfNecessary(result.Value.AggregateBy, result.Value.RangeType); var termsForField = IndexedTerms.GetTermsAndDocumentsFor(readerFacetInfo.Reader, readerFacetInfo.DocBase, name, _indexName, _state); var ranges = result.Value.Ranges; foreach (var kvp in termsForField) { token.ThrowIfCancellationRequested(); for (int i = 0; i < ranges.Count; i++) { var parsedRange = ranges[i]; if (parsedRange.IsMatch(kvp.Key)) { var facetValue = result.Value.Result.Values[i]; var intersectedDocuments = GetIntersectedDocuments(new ArraySegment <int>(kvp.Value), readerFacetInfo.Results, needToApplyAggregation); var intersectCount = intersectedDocuments.Count; if (intersectCount == 0) { continue; } facetValue.Count += intersectCount; if (needToApplyAggregation) { var docsInQuery = new ArraySegment <int>(intersectedDocuments.Documents, 0, intersectedDocuments.Count); ApplyAggregation(result.Value.Aggregations, facetValue, docsInQuery, readerFacetInfo.Reader, readerFacetInfo.DocBase, _state); IntArraysPool.Instance.FreeArray(intersectedDocuments.Documents); intersectedDocuments.Documents = null; } } } } } }
private static void ApplyAggregation(Dictionary <string, FacetedQueryParser.FacetResult.Aggregation> aggregations, FacetValue value, ArraySegment <int> docsInQuery, IndexReader indexReader, int docBase, IState state) { foreach (var kvp in aggregations) { if (kvp.Key == null) // Count { continue; } var name = FieldUtil.ApplyRangeSuffixIfNecessary(kvp.Key, RangeType.Double); var doubles = FieldCache_Fields.DEFAULT.GetDoubles(indexReader, name, state); for (var index = 0; index < docsInQuery.Count; index++) { var doc = docsInQuery.Array[index]; var currentVal = doubles[doc - docBase]; if (kvp.Value.Average) { value.Average = currentVal + (value.Average ?? 0d); } if (kvp.Value.Min) { value.Min = Math.Min(value.Min ?? double.MaxValue, currentVal); } if (kvp.Value.Max) { value.Max = Math.Max(value.Max ?? double.MinValue, currentVal); } if (kvp.Value.Sum) { value.Sum = currentVal + (value.Sum ?? 0d); } } } }
private void HandleRangeFacets( List <ReaderFacetInfo> returnedReaders, KeyValuePair <string, FacetedQueryParser.FacetResult> result, bool legacy, CancellationToken token) { var needToApplyAggregation = result.Value.Aggregations.Count > 0; var facetValues = new Dictionary <string, FacetValues>(); var ranges = result.Value.Ranges; foreach (var range in ranges) { var key = range.RangeText; if (facetValues.TryGetValue(key, out var collectionOfFacetValues)) { continue; } collectionOfFacetValues = new FacetValues(legacy); if (needToApplyAggregation == false) { collectionOfFacetValues.AddDefault(key); } else { foreach (var aggregation in result.Value.Aggregations) { collectionOfFacetValues.Add(aggregation.Key, key); } } facetValues.Add(key, collectionOfFacetValues); } foreach (var readerFacetInfo in returnedReaders) { var name = FieldUtil.ApplyRangeSuffixIfNecessary(result.Value.AggregateBy, result.Value.RangeType); var termsForField = IndexedTerms.GetTermsAndDocumentsFor(readerFacetInfo.Reader, readerFacetInfo.DocBase, name, _indexName, _state); foreach (var kvp in termsForField) { foreach (var range in ranges) { token.ThrowIfCancellationRequested(); if (range.IsMatch(kvp.Key) == false) { continue; } var intersectedDocuments = GetIntersectedDocuments(new ArraySegment <int>(kvp.Value), readerFacetInfo.Results, needToApplyAggregation); var intersectCount = intersectedDocuments.Count; if (intersectCount == 0) { continue; } var collectionOfFacetValues = facetValues[range.RangeText]; collectionOfFacetValues.IncrementCount(intersectCount); if (needToApplyAggregation) { var docsInQuery = new ArraySegment <int>(intersectedDocuments.Documents, 0, intersectedDocuments.Count); ApplyAggregation(result.Value.Aggregations, collectionOfFacetValues, docsInQuery, readerFacetInfo.Reader, readerFacetInfo.DocBase, _state); IntArraysPool.Instance.FreeArray(intersectedDocuments.Documents); intersectedDocuments.Documents = null; } } } } foreach (var kvp in facetValues) { if (kvp.Value.Any == false) { continue; } result.Value.Result.Values.AddRange(kvp.Value.GetAll()); } }