François F.
François F.

Reputation: 229

Hibernate search aggregation : countByDocumentType (with elaticsearch backend)

I'am coding a simple query which targeting multiple index :

//targetIndexes is a list of indexes
searchSession.search(targetIndexes).extension(ElasticsearchExtension.get())

Now I simply want a "countByDocumentType". It means that I want the number of result grouped by the index type. For this I have got two fields already present in my stored index, but I can't query them with hibernate search, damn it ! Actually, elastic search adds its native field named "_index" to allow filtering by index. Hibernate search add also its native field named "_entity_type". But I neither can query on "_index" nor "_entity_type" with hibernate search using aggregation like this :

AggregationKey<Map<String, Long>> countsByEntityKey = AggregationKey.of( "countsByEntity" );
...where(...).aggregation(countsByEntityKey, f -> f.terms()
                .field( "_entity_type", String.class ));

So do I really need to pollute all my classes by adding a custom third field into each hibernate mapped entities in order to be able to query on a specific index ?

@Indexed
public class MyIndexedEntity {
    ...
    @GenericField
    public String getEntityName() {
         return this.getClass.getName();
    }
}

Thanks for your answer

Upvotes: 0

Views: 568

Answers (1)

yrodiere
yrodiere

Reputation: 9977

EDIT: Starting with Hibernate Search 6.2.0.Alpha2, you can refer to some fields that are not part of the Hibernate Search mapping in the Hibernate Search DSL: _id, _index, _entity_type.

So your code should just work.


Previous answer:

Before Hibernate Search 6.2.0.Alpha2, you can't refer to fields that are not part of the Hibernate Search mapping in the Hibernate Search DSL.

I'd suggest using a native aggregation:

AggregationKey<JsonObject> countsByEntityTypeKey = AggregationKey.of( "countsByEntityType" );
SearchResult<Book> result = searchSession.search( Arrays.asList( Book.class, Author.class ) )
        .extension( ElasticsearchExtension.get() )
        .where( f -> f.matchAll() )
        .aggregation( countsByEntityTypeKey, f -> f.fromJson( "{\"terms\":{\"field\": \"_entity_type\"}}" ) )
        .fetch( 20 );

JsonObject countsByEntityTypeAsJson = result.aggregation( countsByEntityTypeKey );
Map<String, Long> countsByEntityType = new HashMap<>();
for ( JsonElement bucket: countsByEntityTypeAsJson.get("buckets").getAsJsonArray() ) {
    JsonObject bucketObject = bucket.getAsJsonObject();
    countsByEntityType.put( bucketObject.get( "key" ).getAsString(),
            bucketObject.get( "doc_count" ).getAsLong() );
}

You can still use the (less verbose) Hibernate Search APIs for everything else, in the same query.

Upvotes: 0

Related Questions