How do I use boolean operators with Hibernate Search

两盒软妹~` 提交于 2019-12-03 07:02:06

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.

To answer you secondary question:

For example, what if I had a collection of firstNames to match against?

I'm not an expert, but according to (the third example from the end of) 5.1.2.1. Keyword queries in Hibernate Search Documentation, you should be able to build the query like so:

Collection<String> namesCollection = getNames(); // Contains "billy" and "bob", for example
StringBuilder names = new StringBuilder(100);
for(String name : namesCollection) {
    names.append(name).append(" "); // Never mind the space at the end of the resulting string.
}

QueryBuilder b = fts.getSearchFactory().buildQueryBuilder().forEntity(Person.class).get();
Query luceneQuery = b.bool()
    .should(
        // Searches for multiple possible values in the same field
        b.keyword().onField("firstName").matching( sb.toString() ).createQuery()
    )
    .must(b.keyword().onField("lastName").matching("thornton").createQuery())
    .createQuery();

and, have as a result, Persons with (firstName preferably "billy" or "bob") AND (lastName = "thornton"), although I don't think it will give the good ol' Billy Bob Thornton a higher score ;-).

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

I was looking for the same issue and have a somewhat different issue than presented. I was looking for an actual OR junction. The should case didn't work for me, as results that didn't pass any of the two expressions, but with a lower score. I wanted to completely omit these results. You can however create an actual boolean OR expression, using a separate boolean expression for which you disable scoring:

val booleanQuery = cb.bool();
val packSizeSubQuery = cb.bool();

packSizes.stream().map(packSize -> cb.phrase()
     .onField(LUCENE_FIELD_PACK_SIZES)
     .sentence(packSize.name())
     .createQuery())
     .forEach(packSizeSubQuery::should);

booleanQuery.must(packSizeSubQuery.createQuery()).disableScoring();
fullTextEntityManager.createFullTextQuery(booleanQuery.createQuery(), Product.class)
return persistenceQuery.getResultList();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!