Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use boolean operators with Hibernate Search

I'm learning the Hibernate Search Query DSL, and I'm not sure how to construct queries using boolean arguments such as AND or OR.

For example, let's say that I want to return all person records that have a firstName value of "bill" or "bob".

Following the hibernate docs, one example uses the bool() method w/ two subqueries, such as:

QueryBuilder b = fts.getSearchFactory().buildQueryBuilder().forEntity(Person.class).get();
Query luceneQuery = b.bool()
    .should(b.keyword().onField("firstName").matching("bill").createQuery())
    .should(b.keyword().onField("firstName").matching("bob").createQuery())
    .createQuery();

logger.debug("query 1:{}", luceneQuery.toString());

This ultimately produces the lucene query that I want, but is this the proper way to use boolean logic with hibernate search? Is "should()" the equivalent of "OR" (similarly, does "must()" correspond to "AND")?.

Also, writing a query this way feels cumbersome. For example, what if I had a collection of firstNames to match against? Is this type of query a good match for the DSL in the first place?

like image 352
NobodyMan Avatar asked Apr 19 '12 00:04

NobodyMan


2 Answers

Yes your example is correct. The boolean operators are called should instead of OR because of the names they have in the Lucene API and documentation, and because it is more appropriate: it is not only influencing a boolean decision, but it also affects scoring of the result.

For example if you search for cars "of brand Fiat" OR "blue", the cars branded Fiat AND blue will also be returned and having an higher score than those which are blue but not Fiat.

It might feel cumbersome because it's programmatic and provides many detailed options. A simpler alternative is to use a simple string for your query and use the QueryParser to create the query. Generally the parser is useful to parse user input, the programmatic one is easier to deal with well defined fields; for example if you have the collection you mentioned it's easy to build it in a for loop.

like image 197
Sanne Avatar answered Oct 30 '22 15:10

Sanne


You can also use BooleanQuery. I would prefer this beacuse You can use this in loop of a list.

    org.hibernate.search.FullTextQuery hibque = null; 

    org.apache.lucene.search.BooleanQuery bquery = new BooleanQuery();

    QueryBuilder qb = fulltextsession.getSearchFactory().buildQueryBuilder()
              .forEntity(entity.getClass()).get();
    for (String keyword : list) {
        bquery.add(qb.keyword().wildcard().onField(entityColumn).matching(keyword)
              .createQuery()  , BooleanClause.Occur.SHOULD);
    }

    if (!filterColumn.equals("") && !filterValue.equals("")) {
       bquery.add(qb.keyword().wildcard().onField(column).matching(value).createQuery()
                        , BooleanClause.Occur.MUST);
    } 

    hibque = fulltextsession.createFullTextQuery(bquery, entity.getClass());

    int num = hibque.getResultSize();
like image 23
vinay Avatar answered Oct 30 '22 13:10

vinay