Is it possible to entirely replace Lucenes MultiFieldQueryParser with Hibernate Search 6

82 views Asked by At

I am about to migrate from Hibernate 5 to hibernate search 6 and are looking for some advice. As I understand a main intention of the version 6 is to decouple the API more from the underlying implementation. I have something like this in my code:

FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
SearchFactory searchFactory = fullTextEntityManager.getSearchFactory();
QueryBuilder queryBuilder = searchFactory.buildQueryBuilder().forEntity(Service.class).get();
BooleanJunction<?> bool = queryBuilder.bool();
Analyzer analyzer = searchFactory.getAnalyzer("standard");

if (StringUtils.isNotBlank(searchString)) {
    MultiFieldQueryParser multiFieldQueryParser = new MultiFieldQueryParser(new String[] {
            "name", "description", "company.name", "configuration.name",
    }, analyzer);
    multiFieldQueryParser.setDefaultOperator(QueryParserBase.AND_OPERATOR);
    org.apache.lucene.search.Query querySearchString = multiFieldQueryParser.parse(searchString);
    bool.must(querySearchString);
}

Query fullTextQuery = fullTextEntityManager.createFullTextQuery(bool.createQuery(), Service.class);
return fullTextQuery.getResultList();

MultiFieldQueryParser, QueryParserBase and Query are classes from lucene backend. Is it possible to realize the same query with pure hibernate search query syntax (Query DSL)?

I found simple examples for fields but could I use something like "company.name" for a related entity field annotated with @IndexedEmbedded ?

Thanks and best Regards Matt

Thanks

2

There are 2 answers

1
mark_o On BEST ANSWER

Yes, that should be possible. Something along the next lines:

searchSession.search( Service.class )
    .where( f -> f.and(
            f.match().field( "name" ).matching( searchString ),
            f.match().field( "description" ).matching( searchString )
            f.match().field( "company.name" ).matching( searchString )
    ) )
    .fetchHits( .. )

Look at the documentation for nested structure here - https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#mapper-orm-indexedembedded-structure. There are examples of what you are looking for. Also, it is recommended to take a look at the migration guide - https://docs.jboss.org/hibernate/search/6.0/migration/html_single/. It contains a lot of helpful info on migration from 5 to 6

0
yrodiere On

There isn't an exact equivalent to MultiFieldQueryParser in the Hibernate Search DSL (at least not yet: HSEARCH-4563). But there is an equivalent to the SimpleQueryParser, which also supports multiple fields, and might be enough if you don't strictly need the Lucene query syntax (since the query syntax is different): simpleQueryString. The different syntax might be a good thing, since it's generally more understandable to end-users who are not experts in Lucene.

I'd suggest you try it out?

searchSession.search( Service.class )
    .where( f -> f.simpleQueryString()
            .fields( "name", "description", "company.name" )
            .matching( searchString ),
            .defaultOperator( BooleanOperator.AND ) )
    .fetchHits( .. )

Regarding @mark_o's answer, while it gives you a behavior similar to MultiFieldQueryParser, it's not exactly the same, especially if the search string contains multiple terms:

  • With MultiFieldQueryParser, not all fields need to match: what's important is that each term is matched by at least one field. With @mark_o's solution, each field must match at least one term.
  • With MultiFieldQueryParser, all terms must be matched by at least one field. With @mark_o's solution, the query will match even if only one term is matched, by every field.