isah
isah

Reputation: 5351

Lucene query with range

I'm indexing some items which include title and cost as fields. Cost is a double value. I'm preparing a query such as:

(title:item~0.8) AND (cost:[0.0 TO 200.0])

After parsing, query.toString() looks like this:

+title:item~0 +cost:[0.0 TO 200.0]

From the results returned, it is obvious that cost is not considered. I know for sure that cost is indexed because I can retrieve it. Indexing code:

public void index(Set<Item> items) throws IOException {
    String path = "D:\\lucenedata\\myproj";
    Directory fsDir = FSDirectory.open(new File(path));
    StandardAnalyzer analyzer = new StandardAnalyzer();
    IndexWriterConfig iwConf = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
    iwConf.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
    IndexWriter indexWriter = new IndexWriter(fsDir, iwConf);
    for (Item item : items) {
        Document d = new Document();
        if (item.getCost() != null) {
            d.add(new DoubleField("cost", item.getCost().doubleValue(), Store.YES));
        }
        d.add(new TextField("title", item.getTitle(), Store.YES));
        indexWriter.addDocument(d);
    }
    indexWriter.commit();
    indexWriter.close();
    System.out.println("Indexed " + items.size() + " items");
}

Upvotes: 1

Views: 5607

Answers (2)

isah
isah

Reputation: 5351

I ended up subclassing QueryParser and then creating a NumericRange when cost is encountered. It works well.

public class WebSearchQueryParser extends QueryParser {

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

    protected Query getRangeQuery(final String field, final String min, final String max,
            final boolean startInclusive, final boolean endInclusive) throws ParseException {
        if ("cost".equals(field)) {
            return NumericRangeQuery.newDoubleRange(field, Double.parseDouble(min), Double.parseDouble(max),
                    startInclusive, endInclusive);
        }
        return super.getRangeQuery(field, min, max, startInclusive, endInclusive);
    }
}

And then initialize:

QueryParser queryParser = new WebSearchQueryParser("title", new StandardAnalyzer());

and parse my query as before (title:item~0.8) AND (cost:[0.0 TO 200.0])

Upvotes: 3

femtoRgon
femtoRgon

Reputation: 33351

QueryParser does not generate numeric range queries. So you are searching for values where cost is between 0.0 and 200.0 lexicographically, rather than numerically. Furthermore, numeric fields are translated to a prefix coded form in the index, so your results will be pretty unpredictable.

It's better to generate your numeric ranges through the Query API, using NumericRangeQuery, instead of the QueryParser, and them combine them with your parsed query using a BooleanQuery. Something like:

Query parsedQuery = parser.parse(title:item~0.8);
Query costQuery = NumericRangeQuery.newDoubleRange("cost", 0.00, 200.0, true, true);
BooleanQuery finalQuery = new BooleanQuery();
finalQuery.add(new BooleanClause(parsedQuery, BooleanClause.Occur.MUST));
finalQuery.add(new BooleanClause(costQuery, BooleanClause.Occur.MUST));

Upvotes: 2

Related Questions