Hibernate Search 6.0.0.Beta6 simplequerydsl breaking

On upgrading from 6.0.0.Beta5 to 6.0.0.Beta6, and not changing any code pertaining to hibernate search in my application, the query builder started breaking at simplequerydsl predicate. results in a null pointer exception,
Also, it is really difficult to troubleshoot older versions of 6.0.0 library, because the documentation page seems to contain only information regarding the latest version. And sometimes it will be difficult to move to latest version due to breaking changes like this, so would like the documentation for older versions to be available as well.

This looks like a bug. Could you please provide the stack trace and your code, specifically the part that builds the query?

While we do this for stable versions, there are no plans to do it for beta versions.

That being said:

  1. A list of breaking changes is included in every release announcement we make; for example here for 6.0.0.Beta6. Announcements can be accessed from the list of releases here.
  2. You can build the documentation from the sources of an earlier version if you really need to. With git and Maven 3.6.3+ installed on your computer, something like this should work:
    git clone https://github.com/hibernate/hibernate-search.git
    cd hibernate-search
    git checkout 6.0.0.Beta5
    mvn clean install -DskipTests -pl documentation -am
    xdg-open ./documentation/target/asciidoctor/en-US/html_single/index.html
    

Attaching the relevant stacktrace:

java.lang.NullPointerException
	at org.hibernate.search.backend.elasticsearch.search.predicate.impl.ElasticsearchSimpleQueryStringPredicateBuilder.doBuild(ElasticsearchSimpleQueryStringPredicateBuilder.java:141)
	at org.hibernate.search.backend.elasticsearch.search.predicate.impl.AbstractElasticsearchSearchPredicateBuilder.build(AbstractElasticsearchSearchPredicateBuilder.java:49)
	at org.hibernate.search.backend.elasticsearch.search.predicate.impl.ElasticsearchSearchPredicate.build(ElasticsearchSearchPredicate.java:28)
	at org.hibernate.search.backend.elasticsearch.search.predicate.impl.ElasticsearchBooleanPredicateBuilder.contributeClauses(ElasticsearchBooleanPredicateBuilder.java:142)
	at org.hibernate.search.backend.elasticsearch.search.predicate.impl.ElasticsearchBooleanPredicateBuilder.doBuild(ElasticsearchBooleanPredicateBuilder.java:108)
	at org.hibernate.search.backend.elasticsearch.search.predicate.impl.AbstractElasticsearchSearchPredicateBuilder.build(AbstractElasticsearchSearchPredicateBuilder.java:49)
	at org.hibernate.search.backend.elasticsearch.search.predicate.impl.ElasticsearchSearchPredicate.build(ElasticsearchSearchPredicate.java:28)
	at org.hibernate.search.backend.elasticsearch.search.predicate.impl.ElasticsearchSearchPredicateBuilderFactoryImpl.contribute(ElasticsearchSearchPredicateBuilderFactoryImpl.java:79)
	at org.hibernate.search.backend.elasticsearch.search.predicate.impl.ElasticsearchSearchPredicateBuilderFactoryImpl.contribute(ElasticsearchSearchPredicateBuilderFactoryImpl.java:41)
	at org.hibernate.search.engine.search.query.dsl.spi.AbstractSearchQueryOptionsStep.contribute(AbstractSearchQueryOptionsStep.java:193)
	at org.hibernate.search.engine.search.query.dsl.spi.AbstractSearchQueryOptionsStep.where(AbstractSearchQueryOptionsStep.java:68)
	at org.hibernate.search.engine.search.query.dsl.impl.DefaultSearchQuerySelectStep.where(DefaultSearchQuerySelectStep.java:92)
	at org.hibernate.search.engine.search.query.dsl.spi.AbstractDelegatingSearchQuerySelectStep.where(AbstractDelegatingSearchQuerySelectStep.java:74)

And here is the code that builds the query predicate:

return searchSession.search(searchScope).where(searchScope.predicate().bool(b -> {
            //making sure cross-customer data is not shown
            b.must(searchScope.predicate().match().field("customerId").matching(customerId));

            //matching objects according to presence of user query
            if (StringUtils.isBlank(finalQuery)) {
                b.must(searchScope.predicate().matchAll());
            } else {
                b.must(searchScope.predicate().simpleQueryString().fields()
                        .matching(SearchUtil.getLuceneQuery(finalQuery)));
            }

            //apply user table filter
            if (StringUtils.isNotBlank(filter)) {
                String[] filters = filter.split(";");
                for (String tempFilter : filters) {
                    String[] filterArray = tempFilter.split("=");
                    String[] filterValues = filterArray[1].split(",");
                    b.must(searchScope.predicate().bool(c -> {
                        for (String filterValue : filterValues) {
                            c.should(searchScope.predicate().match().field(filterArray[0]).matching(filterValue));
                        }
                    }));
                }
            }

            //apply global account filter
            if (!ObjectUtils.isEmpty(accountIds)) {
                b.must(searchScope.predicate().bool(c -> {
                    for (String accountId : accountIds) {
                        c.should(searchScope.predicate().match().field("accountId").matching(accountId));
                    }
                }));
            }

            //apply predicates for metrics if required
            if (!ObjectUtils.isEmpty(booleanPredicateClausesSteps)) {
                for (BooleanPredicateClausesStep booleanPredicateClausesStep : booleanPredicateClausesSteps)
                    b.must(booleanPredicateClausesStep);
            }

        }).toPredicate());

I forgot to mention it, but you can also download the documentation of older versions, even Beta versions, as part of the distribution package (i.e. the “Download” link on the list of releases). The documentation is included in the ZIP files in the docs/reference folder, both in HTML and PDF format.

1 Like

Thank you. Created HSEARCH-3883. This will be fixed in the next Beta.

1 Like

By the way, this code is (from the point of view of Hibernate Search) wrong and fixing it will get rid of the NPE:

You’re not passing any field path, so the predicate will not do anything. You should pass a non-empty array of field paths to fields.

I suppose this used to target all fields before 6.0.0.Beta6, but that was just by chance; it was not an intended feature. You can create a ticket if targeting all relevant fields instead of passing them explicitly is a valuable feature for you, but I wouldn’t recommend it as it may give end users access to technical fields that you did not intend to expose.

@yrodiere yes, the intention is to target all fields, I was experimenting around with passing all possible fields and just stumbled upon this scenario that passing no field parameter has the same effect. It does seem like a valuable feature at this point.