Home > Net >  Hibbernate search cannot use agregation on IndexedEmbedded
Hibbernate search cannot use agregation on IndexedEmbedded

Time:04-26

I am trying to do an aggregation on @IndexedEmbedded, unfortunatly is not working well, but the search on the same field is working ok.

I have

Book {
...
@IndexedEmbedded
@ManyToOne
@JoinColumn(name="auth_id")
private Author auth;
...
}

Author {
...
@FullTextField
private String name;
...
}

Search {
...
AggregationKey<Map<String, Long>> countsByAuthKey = AggregationKey.of("countsByAuth");
SearchResult<Book> result = searchSession.search(Book.class).
                            where(f -> f.match().field("title").matching(title).
                            aggregation(countsByAuthKey, f -> f.terms().
                            field("auth.name", String.class)).fetchAll();

...

It fails on last line with "Cannot use 'aggregation:terms' on field 'auth.name'. Make sure the field is marked as searchable/sortable/projectable/aggregable" (And the field is fulltextfield)

CodePudding user response:

As stated in the error message, you did not mark the field as aggregable. This is also mentioned in the reference documentation:

There are a few constraints regarding aggregations. In particular, in order for a field to be "aggregable", it must be marked as such in the mapping, so that it is correctly stored in the index.

And in fact, in this case you cannot mark the field as aggregable: Full-text fields cannot be the target of aggregations. Even if Hibernate Search allowed that, those fields are tokenized, so the aggregation would return one bucket per word in the author's name (e.g. one for "John" and one for "Smith"), which is most likely not what you want.

Just create another keyword field next to the full-text field. Use the full-text field for search, and the keyword field for aggregations.

Author {
...
@FullTextField
@KeywordField(name = "name_keyword", aggregable = Aggregable.YES)
private String name;
...
}
Search {
...
                            .aggregation(countsByAuthKey, f -> f.terms().
                            field("auth.name_keyword", String.class)).fetchAll();

...
}

Before you test this, remember that you need to re-create your indexes and reindex your database after a mapping change.

  • Related