0
votes

Suppose I have a search using criteria such as a list countries. A user can select a set of countries to search across and combine this set with other criteria.

In SQL I'd do this in my where clause i.e. WHERE (country = 'brazil' OR country = 'france' OR country = 'china) AND (other search criteria).

It isn't clear how to do this in Lucene. Query.combine seems to have promise but that would increase in complexity very quickly if I have multiple sets of "OR" terms to work through.

Is Lucene capable in this regard? Or should I just hit my regular DB with these types of criteria and filter my Lucene results?

Digging deeper, it looks like you can nest boolean queries to accomplish this. I'll update with an answer if this technique works and if it is performant.

2

2 Answers

6
votes

Using the standard query parser(and you can take a look at the relevant documentation), you can use syntax similar to a DB query, such as:

 (country:brazil OR country:france OR country:china) AND (other search criteria)

Or, to simplify a bit:

 country:(brazil OR france OR china) AND (other search criteria)

Alternatively, Lucene also supports queries written using +/-, rather than AND/OR syntax. I find that syntax more expressive for a Lucene query. The equivalent in this form would be:

 +country:(brazil france china) +(other search criteria)

If manually constructing queries, you can indeed nest BooleanQueries to create a similar structure, using the correct BooleanClauses to establish the And/Or logic you've specified:

Query countryQuery = new BooleanQuery();
countryQuery.add(new TermQuery(new Term("country","brazil")),BooleanClause.Occur.SHOULD);
countryQuery.add(new TermQuery(new Term("country","france")),BooleanClause.Occur.SHOULD);
countryQuery.add(new TermQuery(new Term("country","china")),BooleanClause.Occur.SHOULD);

Query otherStuffQuery = //Set up the other query here, 
//or get it from a query parser, or something

Query rootQuery = new BooleanQuery();
rootQuery.add(countryQuery, BooleanClause.Occur.MUST);
rootQuery.add(otherStuffQuery, BooleanClause.Occur.MUST);
1
votes

Two ways.

1) Let the Lucene formulate the query. To accomplish that, send in the query string in the following format.

Query: "country(brazil france china)"

An inbuilt QueryParser parses the above string to a BooleanQuery with an OR operator.

    QueryParser qp = new QueryParser(Version.LUCENE_41, "country", new StandardAnalyzer(Version.LUCENE_41));
    Query q = qp.parse(s);

2) If you want to formulate the query yourself,

  BooleanQuery bq = new BooleanQuery();
  //
  TermQuery tq = new TermQuery(new Term("country", "brazil"));
  bq.add(tq, Occur.SHOULD); // SHOULD ==> OR operator
  //
  tq = new TermQuery(new Term("country", "france"));
  bq.add(tq, Occur.SHOULD);
  // 
  tq = new TermQuery(new Term("country", "china"));
  bq.add(tq, Occur.SHOULD);

Unless you add hundreds of subqueries, Lucene will meet your expectations performance-wise.