How to make QueryParser in numerical ranges of Lucene descriptors?

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

it only works for string indexed fields. Let's say I have a field called count, where count is an integer field (when indexing a field that I considered as a data type)

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

The above does not work. Instead, if I used "NumericRangeQuery.newIntRange" , that works. But I need only one ...

+6
java lucene
source share
5 answers

Had the same problem and solved it, so I share my solution:

To create my own query analyzer that will parse the following query, “INTFIELD_NAME: 1203” or “INTFIELD_NAME: [1 to 10]” and treat the INTFIELD_NAME field as Intfield, I redefined newTermQuery with the following:

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

I took the code indicated in this thread from 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 and made 3 modifications:

  • rewrote newRangeQuery a little prettier

  • replaced in newTermQuery method NumericUtils.intToPrefixCoded NumericUtils.intToPrefixCoded(Integer.parseInt(term.text()),NumericUtils.PRECISION_STEP_DEFAULT)));

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

when I first used this method in a filter in the same number field, I set 0 because I found it as the default in the lucene class, and it just worked.

  • replaced by newTermQuery

    TermQuery tq = new TermQuery(new Term(field,

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

using a "field" is wrong because if your request contains multiple sentences (FIELD: text OR INTFIELD: 100), it accepts the field of the first or previous sentence.

+5
source share

You need to inherit from QueryParser and override GetRangeQuery(string field, ...) . If field is one of your number field names, return an instance of NumericRangeQuery , otherwise return base.GetRangeQuery(...) .

There is an example of such an implementation in this thread: http://www.mail-archive.com/ java-user@lucene.apache.org /msg29062.html

+2
source share

QueryParser will not create NumericRangeQuery since it does not know if the field has been indexed using NumericField. Just open QueryParser to handle this case.

+1
source share

In Lucene 6, the protected QueryParser#getRangeQuery method still exists with an argument list (String fieldName, String low, String high, boolean startInclusive, boolean endInclusive) and overrides it to interpret the range as a numeric range if this information is indexed using one of new Point fields.

When indexing your field:

 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 

In your custom query syntax (extension queryparser.classic.QueryParser ), override the method with something like this:

 @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); } 
0
source share

I adapted Jeremis's answer for C # and Lucene.Net 3.0.3. I also need a double type instead of an int. This is my code:

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

I improved my code to also allow requests such as larger and lower than when transmitting an asterisk. For example. 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); ... 
0
source share

All Articles