예제 #1
0
        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());
        }
예제 #2
0
        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));
            }
        }
예제 #3
0
        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);
        }
예제 #4
0
 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);
 }
예제 #5
0
 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);
 }
예제 #6
0
 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);
 }
예제 #7
0
 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);
 }
예제 #8
0
 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);
 }
예제 #9
0
 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);
 }
예제 #10
0
        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);
        }
예제 #11
0
        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);
        }
예제 #12
0
        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);
        }
예제 #13
0
        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);
        }