How to use logical operators with Hibernate Search

I am studying the Hibernate Search Query DSL , and I am not sure how to create queries using boolean arguments such as AND or OR.

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

Following the docs of sleep mode, one example uses the bool () w / two subqueries method, for example:

 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 creates the lucene query that I want, but is this the correct way to use logic with sleep search? Is "should ()" the equivalent of "OR" (similarly, "must ()" matches "AND")?

In addition, recording a request in this way seems cumbersome. For example, what if I had a collection of firstNames for matching? Is this type of query a good match for DSL?

+8
java hibernate-search
source share
4 answers

Yes, your example is correct. Logical operators must be called instead of OR because of the names that they have in the Lucene API and documentation, and because it is more appropriate: this not only affects the logical decision, but also affects the result of the result.

For example, if you are looking for Fiat or blue cars, cars branded Fiat & blue will also be returned and have a higher score than blue but not Fiat cars.

This may seem cumbersome because it is software-based and provides many detailed options. A simpler alternative is to use a simple string for your query and use QueryParser to create the query. As a rule, a parser is useful for analyzing user input, it is easier for a programmer to cope with well-defined fields; for example, if you have the collection you mentioned, it's easy to build it in a for loop.

+3
source share

To answer a minor question:

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

I am not an expert, but according to (third example from the end) 5.1.2.1. When querying keywords in the Hibernate Search Documentation , you should build this query:

 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, as a result, Person with ( firstName preferably "billy" or "bob") AND ( lastName = "thornton"), although I don’t think it would give a good ol "Billy Bob Thornton - a higher score, -).

+1
source share

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

  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(); 
+1
source share

I was looking for the same problem and had a slightly different problem than the one presented. I was looking for the actual OR connection. The case did not work for me, as results that did not pass either of the two expressions, but with a lower score. I wanted to completely omit these results. However, you can create the actual logical OR expression using a separate logical expression for which you turn off 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(); 
+1
source share

All Articles