Hibernate Search is a library that integrates Hibernate ORM with Apache Lucene or Elasticsearch by automatically indexing entities, enabling advanced search functionality: full-text, geospatial, aggregations and more. For more information, see Hibernate Search on hibernate.org.

Following on the heels of 5.2.0.Final, Hibernate Search 5.3.0.Beta1 is now out. This time the faceting engine got an overhaul.

This work was long overdue, because there were several shortcomings with the existing implementation. For example, there were limitations with *ToMany associations. Also, the implementation was based on a custom Lucene Collector making use of the FieldCache API. FieldCache will be removed in Lucene 5, so updating the faceting API was also a requirement for upgrading to Lucene 5 in the near future.

What has changed? Actually not much when it comes to the API Hibernate Search exposes. You still create your FacetingRequest using QueryBuilder.facet().... You then enable the facet search by passing it to the FacetManager from which you also then retrieve the list of Facet instances after the query was executed. All this is unchanged and documented in the online documentation.

A few things have changed though. Most notably, you will need to tell Hibernate Search now which properties are used for faceting. You do so by adding @Facet (resp. @Facets) to these properties. The reason for this is, that under the hood the implementation is now based on Lucene's dynamic faceting capabilties. For this to work, we need to index the facet values using the appropriate DocValues type (SortedSetDocValuesFacetField, NumericDocValuesField or DoubleDocValuesField). Below we see the use of the @Facet(s) annotation:

    @Indexed
    public class Quux {
        @DocumentId
        private Integer id;
        
        @Field(analyze = Analyze.NO),
        @Facets({
                @Facet,
                @Facet(name = "string_facet_value", encoding = FacetEncodingType.STRING)
        })
        private double value;
    }
Notice that in this example the value field is configured with two facet annotations. The reason is, that per default numbers will be stored using numeric DocValues types (NumericDocValuesField and DoubleDocValuesField), whereas all other types use string based SortedSetDocValuesFacetField. Numeric values can then only be used with a range facet whereas discrete facets require string values. In the case where you want to use discrete faceting on a numeric field (for example if the field only contains a fixed number of possible values) FacetEncodingType.STRING needs to be used.

This is inline with the fact that Hibernate Search 5.x indexes numbers now per default numerically (see this blog).

A final caveat - there was a change in the default behaviour of includeZeroCounts as part of a facet request. The default was to include zero counts, but has changed now to not include it. Instead it must be explicitly specified (calculating zero counts for discrete facets comes with a performance penalty!):

    FacetingRequest request = queryBuilder( Car.class ).facet()
            .name( "quuxFacetRequest" )
            .onField( "string_facet_value" )
            .discrete()
            .includeZeroCounts( true )
            .createFacetingRequest();

Release info for Hibernate Search 5.3.0.Beta1

  • Full change log is available on JIRA
  • Artefact jars are available on Maven Central under the GAV org.hibernate:hibernate-search-orm:5.3.0.Beta1
  • Zip and tar bundles on SourceForge

Happy faceting!


Back to top