如何使Lucene中的QueryParser处理数值范围?

时间:2011-02-17 07:27:56

标签: java lucene

new QueryParser(.... ).parse (somequery);

它仅适用于字符串索引字段。 假设我有一个名为count的字段,其中count是一个整数字段(同时索引我认为是数据类型的字段)

new QueryParser(....).parse("count:[1 TO 10]");

上述不适用。相反,如果我使用“NumericRangeQuery.newIntRange”这是有效的。但是,我只需要上面的......

5 个答案:

答案 0 :(得分:5)

有同样的问题并解决了,所以我在这里分享我的解决方案:

创建一个自定义查询解析器,它将解析以下查询" INTFIELD_NAME:1203"或" INTFIELD_NAME:[1到10]"并将字段INTFIELD_NAME作为Intfield处理, 我用以下内容覆盖了newTermQuery:

public class CustomQueryParser extends QueryParser {

public CustomQueryParser(String f, Analyzer a) {
    super(f, a);
}

protected Query newRangeQuery(String field, String part1, String part2, boolean startInclusive,
    boolean endInclusive) {

    if (INTFIELD_NAME.equals(field)) {
    return NumericRangeQuery.newIntRange(field, Integer.parseInt(part1), Integer.parseInt(part2),
        startInclusive, endInclusive);
    }
    return (TermRangeQuery) super.newRangeQuery(field, part1, part2, startInclusive, endInclusive);
}


protected Query newTermQuery(Term term) {
    if (INTFIELD_NAME.equals(term.field())) {

    BytesRefBuilder byteRefBuilder = new BytesRefBuilder();
    NumericUtils.intToPrefixCoded(Integer.parseInt(term.text()), 0, byteRefBuilder);
    TermQuery tq = new TermQuery(new Term(term.field(), byteRefBuilder.get()));

    return tq;
    } 
    return super.newTermQuery(term);

}
}

我从http://www.mail-archive.com/search?l=java-user@lucene.apache.org&q=subject:%22Re%3A+How+do+you+properly+use+NumericField%22&o=newest&f=1获取了该帖子中引用的代码并进行了3次修改:

  • 更好地重写了newRangeQuery

  • 替换为newTermQuery方法 NumericUtils.intToPrefixCoded(Integer.parseInt(term.text()),NumericUtils.PRECISION_STEP_DEFAULT)));

    NumericUtils.intToPrefixCoded(Integer.parseInt(term.text()), 0, byteRefBuilder);

当我第一次在同一个数字字段的过滤器中使用这个方法时,我把它设为0,因为我发现它是lucene类中的默认值,它只是起作用。

  • 替换为newTermQuery

    TermQuery tq = new TermQuery(new Term(field,

TermQuery tq = new TermQuery(new Term(term.field(),

使用"字段"是错误的,因为如果你的查询有几个子句(FIELD:text OR INTFIELD:100),它就是第一个或前一个子句字段。

答案 1 :(得分:2)

您需要继承QueryParser并覆盖GetRangeQuery(string field, ...)。如果field是您的数字字段名称之一,请返回NumericRangeQuery的实例,否则返回base.GetRangeQuery(...)

此线程中有一个此类实现的示例:http://www.mail-archive.com/java-user@lucene.apache.org/msg29062.html

答案 2 :(得分:1)

QueryParser不会创建NumericRangeQuery,因为它无法知道字段是否使用NumericField编制索引。只需扩展QueryParser即可处理这种情况。

答案 3 :(得分:1)

在Lucene 6中,受保护的方法QueryParser#getRangeQuery仍然存在参数列表(String fieldName, String low, String high, boolean startInclusive, boolean endInclusive),并且覆盖它以将范围解释为数值范围确实是可能的,只要该信息使用索引编制索引即可其中一个新的Point字段。

为您的字段编制索引时:

document.add(new FloatPoint("_point_count", value)); // index for efficient range based retrieval
document.add(new StoredField("count", value)); // if you need to store the value itself

在您的自定义查询解析器(扩展queryparser.classic.QueryParser)中,使用以下内容覆盖该方法:

@Override
protected Query getRangeQuery(String field, String low, String high, boolean startInclusive, boolean endInclusive) throws ParseException
{
    if («isNumericField»(field)) // context dependent
    {
        final String pointField = "_point_" + field;
        return FloatPoint.newRangeQuery(pointField,
                Float.parseFloat(low),
                Float.parseFloat(high));
    }

    return super.getRangeQuery(field, low, high, startInclusive, endInclusive);
}

答案 4 :(得分:0)

我根据C#和Lucene.Net 3.0.3修改了Jeremies的答案。 我还需要类型double而不是int。 这是我的代码:

using System.Globalization;
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Lucene.Net.Util;
using Version = Lucene.Net.Util.Version;

namespace SearchServer.SearchEngine
{
    internal class SearchQueryParser : QueryParser
    {
        public SearchQueryParser(Analyzer analyzer)
            : base(Version.LUCENE_30, null, analyzer)
        {
        }

        private const NumberStyles DblNumberStyles = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite | NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint;

        protected override Query NewRangeQuery(string field, string part1, string part2, bool inclusive)
        {
            if (field == "p")
            {
                double part1Dbl;
                if (!double.TryParse(part1, DblNumberStyles, CultureInfo.InvariantCulture, out part1Dbl))
                    throw new ParseException($"Error parsing value {part1} for field {field} as double.");
                double part2Dbl;
                if (!double.TryParse(part2, DblNumberStyles, CultureInfo.InvariantCulture, out part2Dbl))
                    throw new ParseException($"Error parsing value {part2} for field {field} as double.");
                return NumericRangeQuery.NewDoubleRange(field, part1Dbl, part2Dbl, inclusive, inclusive);
            }
            return base.NewRangeQuery(field, part1, part2, inclusive);
        }

        protected override Query NewTermQuery(Term term)
        {
            if (term.Field == "p")
            {
                double dblParsed;
                if (!double.TryParse(term.Text, DblNumberStyles, CultureInfo.InvariantCulture, out dblParsed))
                    throw new ParseException($"Error parsing value {term.Text} for field {term.Field} as double.");
                return new TermQuery(new Term(term.Field, NumericUtils.DoubleToPrefixCoded(dblParsed)));
            }
            return base.NewTermQuery(term);
        }
    }
}

我改进了我的代码,以便允许大于和小于星号传递时的查询。例如。 p:[* TO 5]

...
    double? part1Dbl = null;
    double tmpDbl;
    if (part1 != "*")
    {
        if (!double.TryParse(part1, DblNumberStyles, CultureInfo.InvariantCulture, out tmpDbl))
            throw new ParseException($"Error parsing value {part1} for field {field} as double.");
        part1Dbl = tmpDbl;
    }
    double? part2Dbl = null;
    if (part2 != "*")
    {
        if (!double.TryParse(part2, DblNumberStyles, CultureInfo.InvariantCulture, out tmpDbl))
            throw new ParseException($"Error parsing value {part2} for field {field} as double.");
        part2Dbl = tmpDbl;
    }
    return NumericRangeQuery.NewDoubleRange(field, part1Dbl, part2Dbl, inclusive, inclusive);
...