private void HandleTermsFacet(string index, Facet facet, IndexQuery indexQuery, IndexSearcher currentIndexSearcher, Dictionary<string, IEnumerable<FacetValue>> results) { var terms = database.ExecuteGetTermsQuery(index, facet.Name, null, database.Configuration.MaxPageSize); var termResults = new List<FacetValue>(); var baseQuery = database.IndexStorage.GetLuceneQuery(index, indexQuery, database.IndexQueryTriggers); foreach (var term in terms) { var termQuery = new TermQuery(new Term(facet.Name, term)); var joinedQuery = new BooleanQuery(); joinedQuery.Add(baseQuery, BooleanClause.Occur.MUST); joinedQuery.Add(termQuery, BooleanClause.Occur.MUST); var topDocs = currentIndexSearcher.Search(joinedQuery, null, 1); if (topDocs.TotalHits > 0) { termResults.Add(new FacetValue { Count = topDocs.TotalHits, Range = term }); } } results[facet.Name] = termResults; }
private void HandleRangeFacet(string index, Facet facet, IndexQuery indexQuery, IndexSearcher currentIndexSearcher, Dictionary<string, IEnumerable<FacetValue>> results) { var rangeResults = new List<FacetValue>(); foreach (var range in facet.Ranges) { var baseQuery = database.IndexStorage.GetLuceneQuery(index, indexQuery, database.IndexQueryTriggers); //TODO the built-in parser can't handle [NULL TO 100.0}, i.e. a mix of [ and } //so we need to handle this ourselves (greater and less-than-or-equal) var rangeQuery = database.IndexStorage.GetLuceneQuery(index, new IndexQuery { Query = facet.Name + ":" + range }, database.IndexQueryTriggers); var joinedQuery = new BooleanQuery(); joinedQuery.Add(baseQuery, BooleanClause.Occur.MUST); joinedQuery.Add(rangeQuery, BooleanClause.Occur.MUST); var topDocs = currentIndexSearcher.Search(joinedQuery, null, 1); if (topDocs.TotalHits > 0) { rangeResults.Add(new FacetValue { Count = topDocs.TotalHits, Range = range }); } } results[facet.Name] = rangeResults; }
public void CanUseNullablesForFacets() { Facet facet = new Facet<Thread>() { Name = t => t.CreationDate, Ranges = { t => t.CreationDate.Value < new DateTime(2012,1,1), } }; Assert.Equal(@"[NULL TO 2012\-01\-01T00\:00\:00.0000000]", facet.Ranges[0]); }
public void AdvancedAPIAdvancedEdgeCases() { var testDateTime = new DateTime(2001, 12, 5); var edgeCaseFacet = new Facet<Test> { Name = x => x.Date, Ranges = { x => x.Date < DateTime.Now, x => x.Date > new DateTime(2010, 12, 5) && x.Date < testDateTime } }; var facet = TriggerConversion(edgeCaseFacet); Assert.Equal(2, facet.Ranges.Count); Assert.False(String.IsNullOrWhiteSpace(facet.Ranges[0])); Assert.Equal(@"[2010\-12\-05T00\:00\:00.0000000 TO 2001\-12\-05T00\:00\:00.0000000]", facet.Ranges[1]); }
public static Facet[] GetFacetsFromHttpContext(this IHttpContext context) { var dictionary = new Dictionary<string, Facet>(); foreach (var facetString in context.Request.QueryString.AllKeys .Where(x=>x.StartsWith("facet.", StringComparison.OrdinalIgnoreCase)) .ToArray()) { var parts = facetString.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length != 3) throw new InvalidOperationException("Could not parse query parameter: " + facetString); var fieldName = parts[1]; Facet facet; if (dictionary.TryGetValue(fieldName, out facet) == false) dictionary[fieldName] = facet = new Facet { Name = fieldName }; foreach (var value in context.Request.QueryString.GetValues(facetString) ?? Enumerable.Empty<string>()) { switch (parts[2].ToLowerInvariant()) { case "mode": FacetMode mode; if (Enum.TryParse(value, true, out mode) == false) throw new InvalidOperationException("Could not parse " + facetString + "=" + value); facet.Mode = mode; break; case "range": facet.Ranges.Add(value); break; } } } return dictionary.Values.ToArray(); }
private void ApplyAggregation(Facet facet, FacetValue value, List<int> docsInQuery, IndexReader indexReader, int docBase) { var sortOptionsForFacet = GetSortOptionsForFacet(facet.AggregationField); switch (sortOptionsForFacet) { case SortOptions.String: case SortOptions.StringVal: case SortOptions.Byte: case SortOptions.Short: case SortOptions.Custom: case SortOptions.None: throw new InvalidOperationException(string.Format("Cannot perform numeric aggregation on index field '{0}'. You must set the Sort mode of the field to Int, Float, Long or Double.", TryTrimRangeSuffix(facet.AggregationField))); case SortOptions.Int: int[] ints = FieldCache_Fields.DEFAULT.GetInts(indexReader, facet.AggregationField); foreach (var doc in docsInQuery) { var currentVal = ints[doc - docBase]; if (facet.Aggregation.HasFlag(FacetAggregation.Max)) { value.Max = Math.Max(value.Max ?? Double.MinValue, currentVal); } if (facet.Aggregation.HasFlag(FacetAggregation.Min)) { value.Min = Math.Min(value.Min ?? Double.MaxValue, currentVal); } if (facet.Aggregation.HasFlag(FacetAggregation.Sum)) { value.Sum = currentVal + (value.Sum ?? 0d); } if (facet.Aggregation.HasFlag(FacetAggregation.Average)) { value.Average = currentVal + (value.Average ?? 0d); } } break; case SortOptions.Float: var floats = FieldCache_Fields.DEFAULT.GetFloats(indexReader, facet.AggregationField); foreach (var doc in docsInQuery) { var currentVal = floats[doc - docBase]; if (facet.Aggregation.HasFlag(FacetAggregation.Max)) { value.Max = Math.Max(value.Max ?? Double.MinValue, currentVal); } if (facet.Aggregation.HasFlag(FacetAggregation.Min)) { value.Min = Math.Min(value.Min ?? Double.MaxValue, currentVal); } if (facet.Aggregation.HasFlag(FacetAggregation.Sum)) { value.Sum = currentVal + (value.Sum ?? 0d); } if (facet.Aggregation.HasFlag(FacetAggregation.Average)) { value.Average = currentVal + (value.Average ?? 0d); } } break; case SortOptions.Long: var longs = FieldCache_Fields.DEFAULT.GetLongs(indexReader, facet.AggregationField); foreach (var doc in docsInQuery) { var currentVal = longs[doc - docBase]; if (facet.Aggregation.HasFlag(FacetAggregation.Max)) { value.Max = Math.Max(value.Max ?? Double.MinValue, currentVal); } if (facet.Aggregation.HasFlag(FacetAggregation.Min)) { value.Min = Math.Min(value.Min ?? Double.MaxValue, currentVal); } if (facet.Aggregation.HasFlag(FacetAggregation.Sum)) { value.Sum = currentVal + (value.Sum ?? 0d); } if (facet.Aggregation.HasFlag(FacetAggregation.Average)) { value.Average = currentVal + (value.Average ?? 0d); } } break; case SortOptions.Double: var doubles = FieldCache_Fields.DEFAULT.GetDoubles(indexReader, facet.AggregationField); foreach (var doc in docsInQuery) { var currentVal = doubles[doc - docBase]; if (facet.Aggregation.HasFlag(FacetAggregation.Max)) { value.Max = Math.Max(value.Max ?? Double.MinValue, currentVal); } if (facet.Aggregation.HasFlag(FacetAggregation.Min)) { value.Min = Math.Min(value.Min ?? Double.MaxValue, currentVal); } if (facet.Aggregation.HasFlag(FacetAggregation.Sum)) { value.Sum = currentVal + (value.Sum ?? 0d); } if (facet.Aggregation.HasFlag(FacetAggregation.Average)) { value.Average = currentVal + (value.Average ?? 0d); } } break; default: throw new ArgumentOutOfRangeException("Cannot understand " + sortOptionsForFacet); } }
private void ApplyFacetValueHit(FacetValue facetValue, Facet value, int docId, ParsedRange parsedRange) { facetValue.Hits++; if (value.Aggregation == FacetAggregation.Count || value.Aggregation == FacetAggregation.None) { return; } FacetValueState set; if (matches.TryGetValue(facetValue, out set) == false) { matches[facetValue] = set = new FacetValueState { Docs = new HashSet<int>(), Facet = value, Range = parsedRange }; } set.Docs.Add(docId); }
private void ApplyAggregation(Facet facet, FacetValue value, double currentVal) { if (facet.Aggregation.HasFlag(FacetAggregation.Max)) { value.Max = Math.Max(value.Max ?? Double.MinValue, currentVal); } if (facet.Aggregation.HasFlag(FacetAggregation.Min)) { value.Min = Math.Min(value.Min ?? Double.MaxValue, currentVal); } if (facet.Aggregation.HasFlag(FacetAggregation.Sum)) { value.Sum = currentVal + (value.Sum ?? 0d); } if (facet.Aggregation.HasFlag(FacetAggregation.Average)) { value.Average = currentVal + (value.Average ?? 0d); } }
private Facet TriggerConversion(Facet<Test> facet) { //The conversion is done with an implicit cast, //so we remain compatible with the original facet API return (Facet)facet; }
private bool AreFacetsEqual(Facet left, Facet right) { return left.Name == right.Name && left.Mode == right.Mode && left.Ranges.Count == right.Ranges.Count && left.Ranges.All(x => right.Ranges.Contains(x)); }
private void ApplyFacetValueHit(FacetValue facetValue, Facet value, int docId, ParsedRange parsedRange, IndexReader indexReader) { facetValue.Hits++; if ( IndexQuery.IsDistinct == false && (value.Aggregation == FacetAggregation.Count || value.Aggregation == FacetAggregation.None) ) { return; } FacetValueState set; if (matches.TryGetValue(facetValue, out set) == false) { matches[facetValue] = set = new FacetValueState { Docs = new HashSet<int>(), Facet = value, Range = parsedRange }; } if (IndexQuery.IsDistinct) { if(IndexQuery.FieldsToFetch.Length == 0) throw new InvalidOperationException("Cannot process distinct facet query without specifying which fields to distinct upon."); if (set.AlreadySeen == null) set.AlreadySeen = new HashSet<StringCollectionValue>(); var document = indexReader.Document(docId); var fields = new List<string>(); foreach (var fieldName in IndexQuery.FieldsToFetch) { foreach (var field in document.GetFields(fieldName)) { if (field.StringValue == null) continue; fields.Add(field.StringValue); } } if (fields.Count == 0) throw new InvalidOperationException("Cannot apply distinct facet on [" + string.Join(", ", IndexQuery.FieldsToFetch) + "], did you forget to store them in the index? "); if (set.AlreadySeen.Add(new StringCollectionValue(fields)) == false) { facetValue.Hits--;// already seen, cancel this return; } } set.Docs.Add(docId); }