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

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

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

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

上面的一个不起作用。 相反,如果我使用“NumericRangeQuery.newIntRange” ,它正在工作。 但是,我只需要上面的……

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

要创建一个自定义查询解析器,它将解析以下查询“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+获取该post中引用的代码使用+ NumericField%22&o =最新&f = 1并进行了3次修改:

  • 重新编写newRangeQuery更好一点

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

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

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

  • 替换为newTermQuery

    TermQuery tq = new TermQuery(new Term(field,

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

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

您需要从QueryParserinheritance并覆盖GetRangeQuery(string field, ...) 。 如果field是您的数字字段名称NumericRangeQuery ,则返回base.GetRangeQuery(...)的实例,否则返回base.GetRangeQuery(...)

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

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

在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); } 

我根据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); ...