public List <FacetResult> FacetedQuery(FacetQuery facetQuery, DocumentsOperationContext context, Func <string, SpatialField> getSpatialField, CancellationToken token) { var results = FacetedQueryParser.Parse(context, facetQuery); var query = facetQuery.Query; var facetsByName = new Dictionary <string, Dictionary <string, FacetValue> >(); var baseQuery = GetLuceneQuery(context, query.Metadata, query.QueryParameters, _analyzer, _queryBuilderFactories); var returnedReaders = GetQueryMatchingDocuments(_searcher, baseQuery, _state); foreach (var result in results) { if (result.Value.Ranges == null || result.Value.Ranges.Count == 0) { HandleFacets(returnedReaders, result, facetsByName); continue; } HandleRangeFacets(result, returnedReaders); } UpdateFacetResults(results, query, facetsByName); CompleteFacetCalculationsStage(results); foreach (var readerFacetInfo in returnedReaders) { IntArraysPool.Instance.FreeArray(readerFacetInfo.Results.Array); } return(results.Values .Select(x => x.Result) .ToList()); }
public async Task <FacetedQueryResult> ExecuteFacetedQuery(IndexQueryServerSide query, long?existingResultEtag, DocumentsOperationContext documentsContext, OperationCancelToken token) { if (query.Metadata.IsDynamic) { throw new InvalidQueryException("Facet query must be executed against static index.", query.Metadata.QueryText, query.QueryParameters); } var fq = FacetQuery.Create(documentsContext, query); var index = GetIndex(query.Metadata.IndexName); if (existingResultEtag.HasValue) { var etag = index.GetIndexEtag(query.Metadata) ^ fq.FacetsEtag; if (etag == existingResultEtag) { return(FacetedQueryResult.NotModifiedResult); } } using (QueryRunner.MarkQueryAsRunning(index.Name, query, token)) { return(await index.FacetedQuery(fq, documentsContext, token)); } }
private static string ExtractFieldName(BinaryExpression be, FacetQuery query) { if (be.Left is FieldExpression lfe) { return(lfe.GetText(null)); } if (be.Left is ValueExpression lve) { return(lve.Token.Value); } ThrowUnsupportedRangeExpression(query, be.Left); return(null); }
public override Task <FacetedQueryResult> FacetedQuery(FacetQuery query, DocumentsOperationContext documentsContext, OperationCancelToken token) { throw new NotSupportedException($"Index {Name} is in-memory implementation of a faulty index", _e); }
private static void ThrowUnsupportedRangeExpression(FacetQuery query, QueryExpression expression) { throw new InvalidQueryException($"Unsupported range expression of a facet query: {expression.GetType().Name}. Text: {expression.GetText(query.Query)}.", query.Query.Metadata.QueryText, query.Query.QueryParameters); }
private static void ThrowUnsupportedRangeOperator(FacetQuery query, OperatorType op) { throw new InvalidQueryException($"Unsupported operator in a range of a facet query: {op}", query.Query.Metadata.QueryText, query.Query.QueryParameters); }
private static void ThrowInvalidFieldInFacetQuery(FacetQuery query, SelectField field) { throw new InvalidQueryException( $"It encountered a field in SELECT clause which is not a facet. Field: {field.Name}", query.Query.Metadata.QueryText, query.Query.QueryParameters); }
private static void ThrowRangeDefinedOnDifferentFields(FacetQuery query, string fieldName, string differentField) { throw new InvalidQueryException($"Facet ranges must be defined on the same field while we got '{fieldName}' and '{differentField}' used in the same faced", query.Query.Metadata.QueryText, query.Query.QueryParameters); }
private static void ThrowDifferentTypesOfRangeValues(FacetQuery query, RangeType type1, RangeType type2, string field) { throw new InvalidQueryException( $"Expected to get values of the same type in range expressions while it got {type1} and {type2} for a field '{field}'", query.Query.Metadata.QueryText, query.Query.QueryParameters); }
private static ParsedRange ParseRange(QueryExpression expression, FacetQuery query, out RangeType type) { if (expression is BetweenExpression bee) { var hValue = ConvertFieldValue(bee.Max.Token.Value, bee.Max.Value, query.Query.QueryParameters); var lValue = ConvertFieldValue(bee.Min.Token.Value, bee.Min.Value, query.Query.QueryParameters); var fieldName = ((FieldExpression)bee.Source).GetText(null); if (hValue.Type != lValue.Type) { ThrowDifferentTypesOfRangeValues(query, hValue.Type, lValue.Type, fieldName); } type = hValue.Type; var range = new ParsedRange { Field = fieldName, HighInclusive = true, HighValue = hValue.Value, LowInclusive = true, LowValue = lValue.Value, RangeText = expression.GetText(query.Query) }; return(range); } if (expression is BinaryExpression be) { switch (be.Operator) { case OperatorType.LessThan: case OperatorType.GreaterThan: case OperatorType.LessThanEqual: case OperatorType.GreaterThanEqual: var fieldName = ExtractFieldName(be, query); var r = (ValueExpression)be.Right; var fieldValue = ConvertFieldValue(r.Token.Value, r.Value, query.Query.QueryParameters); type = fieldValue.Type; var range = new ParsedRange { Field = fieldName, RangeText = expression.GetText(query.Query) }; if (be.Operator == OperatorType.LessThan || be.Operator == OperatorType.LessThanEqual) { range.HighValue = fieldValue.Value; range.HighInclusive = be.Operator == OperatorType.LessThanEqual; return(range); } if (be.Operator == OperatorType.GreaterThan || be.Operator == OperatorType.GreaterThanEqual) { range.LowValue = fieldValue.Value; range.LowInclusive = be.Operator == OperatorType.GreaterThanEqual; return(range); } return(range); case OperatorType.And: var left = ParseRange(be.Left, query, out var lType); var right = ParseRange(be.Right, query, out var rType); if (lType != rType) { ThrowDifferentTypesOfRangeValues(query, lType, rType, left.Field); } type = lType; if (left.HighValue == null) { left.HighValue = right.HighValue; left.HighInclusive = right.HighInclusive; } if (left.LowValue == null) { left.LowValue = right.LowValue; left.LowInclusive = right.LowInclusive; } left.RangeText = $"{left.RangeText} and {right.RangeText}"; return(left); default: ThrowUnsupportedRangeOperator(query, be.Operator); break; } } ThrowUnsupportedRangeExpression(query, expression); type = RangeType.None; return(null); }
public static Dictionary <string, FacetResult> Parse(JsonOperationContext context, FacetQuery query) { var results = new Dictionary <string, FacetResult>(); foreach (var field in query.Query.Metadata.SelectFields) { if (field.IsFacet == false) { ThrowInvalidFieldInFacetQuery(query, field); } var facetField = (FacetField)field; if (facetField.FacetSetupDocumentId != null) { var facetSetup = query.Facets[facetField.FacetSetupDocumentId]; foreach (var f in ProcessFacetSetup(facetSetup)) { var r = ProcessFacet(f.Facet, f.Ranges, query); results[r.Result.Name] = r; } continue; } FacetBase facet; if (facetField.Ranges != null && facetField.Ranges.Count > 0) { var rangeFacet = new RangeFacet(); foreach (var range in facetField.Ranges) { rangeFacet.Ranges.Add(range.GetText(query.Query)); } facet = rangeFacet; } else { facet = new Facet { FieldName = facetField.Name, }; } facet.DisplayFieldName = facetField.Alias; facet.Aggregations = facetField.Aggregations; facet.Options = facetField.GetOptions(context, query.Query.QueryParameters) ?? FacetOptions.Default; var result = ProcessFacet(facet, facetField.Ranges, query); results[result.Result.Name] = result; } return(results); }
private static FacetResult ProcessFacet(FacetBase facet, List <QueryExpression> facetRanges, FacetQuery query) { var result = new FacetResult { Result = new Raven.Client.Documents.Queries.Facets.FacetResult(), Options = facet.Options }; string fieldName = null; if (facet is Facet aggregationOnlyFacet) { result.AggregateBy = aggregationOnlyFacet.FieldName ?? Constants.Documents.Querying.Facet.AllResults; fieldName = result.AggregateBy; } else if (facet is RangeFacet) { Debug.Assert(facetRanges != null && facetRanges.Count > 0); RangeType?rangeType = null; var ranges = new List <ParsedRange>(); foreach (var range in facetRanges) { var parsedRange = ParseRange(range, query, out var type); if (rangeType.HasValue == false) { rangeType = type; } else if (rangeType.Value != type) { ThrowDifferentTypesOfRangeValues(query, rangeType.Value, type, parsedRange.Field); } ranges.Add(parsedRange); if (fieldName == null) { fieldName = parsedRange.Field; } else { if (fieldName != parsedRange.Field) { ThrowRangeDefinedOnDifferentFields(query, fieldName, parsedRange.Field); } } } result.AggregateBy = fieldName; result.Ranges = ranges; result.RangeType = rangeType.Value; } else { ThrowUnknownFacetType(facet); } result.Result.Name = facet.DisplayFieldName ?? fieldName; foreach (var kvp in facet.Aggregations) { if (query.Legacy && kvp.Value.Count > 1) { throw new InvalidQueryException($"Detected duplicate facet aggregation operation '{kvp.Key}'. Each facet can only contain one of each available operations."); } foreach (var v in kvp.Value) { if (result.Aggregations.TryGetValue(v, out var value) == false) { result.Aggregations[v] = value = new FacetResult.Aggregation(); } switch (kvp.Key) { case FacetAggregation.Max: value.Max = true; break; case FacetAggregation.Min: value.Min = true; break; case FacetAggregation.Average: value.Average = true; break; case FacetAggregation.Sum: value.Sum = true; break; } } } return(result); }
private static FacetResult ProcessFacet(FacetBase facet, List <QueryExpression> facetRanges, FacetQuery query) { var result = new FacetResult { Result = new Raven.Client.Documents.Queries.Facets.FacetResult(), Options = facet.Options }; string fieldName = null; if (facet is Facet aggregationOnlyFacet) { result.AggregateBy = aggregationOnlyFacet.FieldName; fieldName = result.AggregateBy; } else if (facet is RangeFacet) { Debug.Assert(facetRanges != null && facetRanges.Count > 0); RangeType?rangeType = null; var ranges = new List <ParsedRange>(); foreach (var range in facetRanges) { var parsedRange = ParseRange(range, query, out var type); if (rangeType.HasValue == false) { rangeType = type; } else if (rangeType.Value != type) { ThrowDifferentTypesOfRangeValues(query, rangeType.Value, type, parsedRange.Field); } ranges.Add(parsedRange); result.Result.Values.Add(new FacetValue { Range = parsedRange.RangeText }); if (fieldName == null) { fieldName = parsedRange.Field; } else { if (fieldName != parsedRange.Field) { ThrowRangeDefinedOnDifferentFields(query, fieldName, parsedRange.Field); } } } result.AggregateBy = fieldName; result.Ranges = ranges; result.RangeType = rangeType.Value; } else { ThrowUnknownFacetType(facet); } result.Result.Name = facet.DisplayFieldName ?? fieldName; foreach (var kvp in facet.Aggregations) { if (result.Aggregations.TryGetValue(kvp.Value, out var value) == false) { result.Aggregations[kvp.Value] = value = new FacetResult.Aggregation(); } switch (kvp.Key) { case FacetAggregation.Max: value.Max = true; break; case FacetAggregation.Min: value.Min = true; break; case FacetAggregation.Average: value.Average = true; break; case FacetAggregation.Sum: value.Sum = true; break; } } return(result); }