Beispiel #1
0
        private static Lucene.Net.Search.Query HandleEndsWith(Query query, MethodExpression expression, QueryMetadata metadata, BlittableJsonReaderObject parameters)
        {
            var fieldName = ExtractIndexFieldName(query, parameters, expression.Arguments[0], metadata);

            var(value, valueType) = GetValue(fieldName, query, metadata, parameters, (ValueExpression)expression.Arguments[1]);

            if (valueType != ValueTokenType.String)
            {
                ThrowMethodExpectsArgumentOfTheFollowingType("endsWith", ValueTokenType.String, valueType, metadata.QueryText, parameters);
            }

            var valueAsString = GetValueAsString(value);

            valueAsString = string.IsNullOrEmpty(valueAsString)
                ? LuceneQueryHelper.Asterisk
                : valueAsString.Insert(0, LuceneQueryHelper.Asterisk);

            return(LuceneQueryHelper.Term(fieldName, valueAsString, LuceneTermType.WildCard));
        }
Beispiel #2
0
        private static Lucene.Net.Search.Query HandleSearch(Query query, MethodExpression expression, QueryMetadata metadata, BlittableJsonReaderObject parameters,
                                                            Analyzer analyzer)
        {
            QueryFieldName fieldName;

            if (expression.Arguments[0] is FieldExpression ft)
            {
                fieldName = ExtractIndexFieldName(query, parameters, ft, metadata);
            }
            else if (expression.Arguments[0] is ValueExpression vt)
            {
                fieldName = ExtractIndexFieldName(vt, metadata, parameters);
            }
            else
            {
                throw new InvalidOperationException("search() method can only be called with an identifier or string, but was called with " + expression.Arguments[0]);
            }

            var(value, valueType) = GetValue(fieldName, query, metadata, parameters, (ValueExpression)expression.Arguments[1]);

            if (valueType != ValueTokenType.String)
            {
                ThrowMethodExpectsArgumentOfTheFollowingType("search", ValueTokenType.String, valueType, metadata.QueryText, parameters);
            }

            Debug.Assert(metadata.IsDynamic == false || metadata.WhereFields[fieldName].IsFullTextSearch);

            var valueAsString = GetValueAsString(value);
            var values        = valueAsString.Split(' ');

            if (metadata.IsDynamic)
            {
                fieldName = new QueryFieldName(AutoIndexField.GetSearchAutoIndexFieldName(fieldName.Value), fieldName.IsQuoted);
            }

            if (values.Length == 1)
            {
                var nValue = values[0];
                return(LuceneQueryHelper.AnalyzedTerm(fieldName, nValue, GetTermType(nValue), analyzer));
            }

            var occur = Occur.SHOULD;

            if (expression.Arguments.Count == 3)
            {
                var fieldExpression = (FieldExpression)expression.Arguments[2];
                if (fieldExpression.Compound.Count != 1)
                {
                    ThrowInvalidOperatorInSearch(metadata, parameters, fieldExpression);
                }

                var op = fieldExpression.Compound[0];
                if (string.Equals("AND", op, StringComparison.OrdinalIgnoreCase))
                {
                    occur = Occur.MUST;
                }
                else if (string.Equals("OR", op, StringComparison.OrdinalIgnoreCase))
                {
                    occur = Occur.SHOULD;
                }
                else
                {
                    ThrowInvalidOperatorInSearch(metadata, parameters, fieldExpression);
                }
            }

            var q = new BooleanQuery();

            foreach (var v in values)
            {
                q.Add(LuceneQueryHelper.AnalyzedTerm(fieldName, v, GetTermType(v), analyzer), occur);
            }

            return(q);

            LuceneTermType GetTermType(string termValue)
            {
                if (string.IsNullOrEmpty(termValue))
                {
                    return(LuceneTermType.String);
                }

                if (termValue[0] == LuceneQueryHelper.AsteriskChar)
                {
                    return(LuceneTermType.WildCard);
                }

                if (termValue[termValue.Length - 1] == LuceneQueryHelper.AsteriskChar)
                {
                    if (termValue[termValue.Length - 2] != '\\')
                    {
                        return(LuceneTermType.Prefix);
                    }
                }

                return(LuceneTermType.String);
            }
        }
Beispiel #3
0
        private static Lucene.Net.Search.Query HandleExists(Query query, BlittableJsonReaderObject parameters, MethodExpression expression, QueryMetadata metadata)
        {
            var fieldName = ExtractIndexFieldName(query, parameters, expression.Arguments[0], metadata);

            return(LuceneQueryHelper.Term(fieldName, LuceneQueryHelper.Asterisk, LuceneTermType.WildCard));
        }
Beispiel #4
0
        private static Lucene.Net.Search.Query ToLuceneQuery(JsonOperationContext context, Query query, QueryExpression expression, QueryMetadata metadata,
                                                             BlittableJsonReaderObject parameters, Analyzer analyzer, Func <string, SpatialField> getSpatialField, bool exact = false)
        {
            if (expression == null)
            {
                return(new MatchAllDocsQuery());
            }

            if (expression is BinaryExpression where)
            {
                switch (where.Operator)
                {
                case OperatorType.Equal:
                case OperatorType.NotEqual:
                case OperatorType.GreaterThan:
                case OperatorType.LessThan:
                case OperatorType.LessThanEqual:
                case OperatorType.GreaterThanEqual:
                {
                    var fieldName = ExtractIndexFieldName(query, parameters, where.Left, metadata);
                    var(value, valueType) = GetValue(fieldName, query, metadata, parameters, where.Right);

                    var(luceneFieldName, fieldType, termType) = GetLuceneField(fieldName, valueType);

                    switch (fieldType)
                    {
                    case LuceneFieldType.String:
                        var valueAsString = GetValueAsString(value);


                        if (exact && metadata.IsDynamic)
                        {
                            luceneFieldName = AutoIndexField.GetExactAutoIndexFieldName(luceneFieldName);
                        }

                        switch (where.Operator)
                        {
                        case OperatorType.Equal:
                            return(LuceneQueryHelper.Equal(luceneFieldName, termType, valueAsString, exact));

                        case OperatorType.NotEqual:
                            return(LuceneQueryHelper.NotEqual(luceneFieldName, termType, valueAsString, exact));

                        case OperatorType.LessThan:
                            return(LuceneQueryHelper.LessThan(luceneFieldName, termType, valueAsString, exact));

                        case OperatorType.GreaterThan:
                            return(LuceneQueryHelper.GreaterThan(luceneFieldName, termType, valueAsString, exact));

                        case OperatorType.LessThanEqual:
                            return(LuceneQueryHelper.LessThanOrEqual(luceneFieldName, termType, valueAsString, exact));

                        case OperatorType.GreaterThanEqual:
                            return(LuceneQueryHelper.GreaterThanOrEqual(luceneFieldName, termType, valueAsString, exact));
                        }
                        break;

                    case LuceneFieldType.Long:
                        var valueAsLong = (long)value;

                        switch (where.Operator)
                        {
                        case OperatorType.Equal:
                            return(LuceneQueryHelper.Equal(luceneFieldName, termType, valueAsLong));

                        case OperatorType.NotEqual:
                            return(LuceneQueryHelper.NotEqual(luceneFieldName, termType, valueAsLong));

                        case OperatorType.LessThan:
                            return(LuceneQueryHelper.LessThan(luceneFieldName, termType, valueAsLong));

                        case OperatorType.GreaterThan:
                            return(LuceneQueryHelper.GreaterThan(luceneFieldName, termType, valueAsLong));

                        case OperatorType.LessThanEqual:
                            return(LuceneQueryHelper.LessThanOrEqual(luceneFieldName, termType, valueAsLong));

                        case OperatorType.GreaterThanEqual:
                            return(LuceneQueryHelper.GreaterThanOrEqual(luceneFieldName, termType, valueAsLong));
                        }
                        break;

                    case LuceneFieldType.Double:
                        var valueAsDouble = (double)value;

                        switch (where.Operator)
                        {
                        case OperatorType.Equal:
                            return(LuceneQueryHelper.Equal(luceneFieldName, termType, valueAsDouble));

                        case OperatorType.NotEqual:
                            return(LuceneQueryHelper.NotEqual(luceneFieldName, termType, valueAsDouble));

                        case OperatorType.LessThan:
                            return(LuceneQueryHelper.LessThan(luceneFieldName, termType, valueAsDouble));

                        case OperatorType.GreaterThan:
                            return(LuceneQueryHelper.GreaterThan(luceneFieldName, termType, valueAsDouble));

                        case OperatorType.LessThanEqual:
                            return(LuceneQueryHelper.LessThanOrEqual(luceneFieldName, termType, valueAsDouble));

                        case OperatorType.GreaterThanEqual:
                            return(LuceneQueryHelper.GreaterThanOrEqual(luceneFieldName, termType, valueAsDouble));
                        }
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(nameof(fieldType), fieldType, null);
                    }

                    throw new NotSupportedException("Should not happen!");
                }

                case OperatorType.And:
                case OperatorType.AndNot:
                    var andPrefix = where.Operator == OperatorType.AndNot ? LucenePrefixOperator.Minus : LucenePrefixOperator.None;
                    return(LuceneQueryHelper.And(
                               ToLuceneQuery(context, query, where.Left, metadata, parameters, analyzer, getSpatialField, exact),
                               LucenePrefixOperator.None,
                               ToLuceneQuery(context, query, where.Right, metadata, parameters, analyzer, getSpatialField, exact),
                               andPrefix));

                case OperatorType.Or:
                case OperatorType.OrNot:
                    var orPrefix = where.Operator == OperatorType.OrNot ? LucenePrefixOperator.Minus : LucenePrefixOperator.None;
                    return(LuceneQueryHelper.Or(
                               ToLuceneQuery(context, query, where.Left, metadata, parameters, analyzer, getSpatialField, exact),
                               LucenePrefixOperator.None,
                               ToLuceneQuery(context, query, where.Right, metadata, parameters, analyzer, getSpatialField, exact),
                               orPrefix));
                }
            }
            if (expression is BetweenExpression be)
            {
                var fieldName = ExtractIndexFieldName(query, parameters, be.Source, metadata);
                var(valueFirst, valueFirstType) = GetValue(fieldName, query, metadata, parameters, be.Min);
                var(valueSecond, _)             = GetValue(fieldName, query, metadata, parameters, be.Max);

                var(luceneFieldName, fieldType, termType) = GetLuceneField(fieldName, valueFirstType);

                switch (fieldType)
                {
                case LuceneFieldType.String:
                    var valueFirstAsString  = GetValueAsString(valueFirst);
                    var valueSecondAsString = GetValueAsString(valueSecond);
                    return(LuceneQueryHelper.Between(luceneFieldName, termType, valueFirstAsString, valueSecondAsString, exact));

                case LuceneFieldType.Long:
                    var valueFirstAsLong  = (long)valueFirst;
                    var valueSecondAsLong = (long)valueSecond;
                    return(LuceneQueryHelper.Between(luceneFieldName, termType, valueFirstAsLong, valueSecondAsLong));

                case LuceneFieldType.Double:
                    var valueFirstAsDouble  = (double)valueFirst;
                    var valueSecondAsDouble = (double)valueSecond;
                    return(LuceneQueryHelper.Between(luceneFieldName, termType, valueFirstAsDouble, valueSecondAsDouble));

                default:
                    throw new ArgumentOutOfRangeException(nameof(fieldType), fieldType, null);
                }
            }
            if (expression is InExpression ie)
            {
                var            fieldName         = ExtractIndexFieldName(query, parameters, ie.Source, metadata);
                LuceneTermType termType          = LuceneTermType.Null;
                bool           hasGotTheRealType = false;

                if (ie.All)
                {
                    var allInQuery = new BooleanQuery();
                    foreach (var value in GetValuesForIn(context, query, ie, metadata, parameters, fieldName))
                    {
                        if (hasGotTheRealType == false)
                        {
                            // here we assume that all the values are of the same type
                            termType          = GetLuceneField(fieldName, value.Type).LuceneTermType;
                            hasGotTheRealType = true;
                        }
                        if (exact && metadata.IsDynamic)
                        {
                            fieldName = new QueryFieldName(AutoIndexField.GetExactAutoIndexFieldName(fieldName.Value), fieldName.IsQuoted);
                        }

                        allInQuery.Add(LuceneQueryHelper.Equal(fieldName, termType, value.Value, exact), Occur.MUST);
                    }

                    return(allInQuery);
                }
                var matches = new List <string>();
                foreach (var tuple in GetValuesForIn(context, query, ie, metadata, parameters, fieldName))
                {
                    if (hasGotTheRealType == false)
                    {
                        // we assume that the type of all the parameters is the same
                        termType          = GetLuceneField(fieldName, tuple.Type).LuceneTermType;
                        hasGotTheRealType = true;
                    }
                    matches.Add(LuceneQueryHelper.GetTermValue(tuple.Value, termType, exact));
                }

                return(new TermsMatchQuery(fieldName, matches));
            }
            if (expression is TrueExpression)
            {
                return(new MatchAllDocsQuery());
            }
            if (expression is MethodExpression me)
            {
                var methodName = me.Name.Value;
                var methodType = QueryMethod.GetMethodType(methodName);

                switch (methodType)
                {
                case MethodType.Search:
                    return(HandleSearch(query, me, metadata, parameters, analyzer));

                case MethodType.Boost:
                    return(HandleBoost(context, query, me, metadata, parameters, analyzer, getSpatialField, exact));

                case MethodType.StartsWith:
                    return(HandleStartsWith(query, me, metadata, parameters));

                case MethodType.EndsWith:
                    return(HandleEndsWith(query, me, metadata, parameters));

                case MethodType.Lucene:
                    return(HandleLucene(query, me, metadata, parameters, analyzer));

                case MethodType.Exists:
                    return(HandleExists(query, parameters, me, metadata));

                case MethodType.Exact:
                    return(HandleExact(context, query, me, metadata, parameters, analyzer, getSpatialField));

                case MethodType.Within:
                case MethodType.Contains:
                case MethodType.Disjoint:
                case MethodType.Intersects:
                    return(HandleSpatial(query, me, metadata, parameters, methodType, getSpatialField));

                default:
                    QueryMethod.ThrowMethodNotSupported(methodType, metadata.QueryText, parameters);
                    return(null);    // never hit
                }
            }

            throw new InvalidQueryException("Unable to understand query", query.QueryText, parameters);
        }