Skip to content

Commit

Permalink
HSEARCH-5133 Document metric aggregations
Browse files Browse the repository at this point in the history
  • Loading branch information
fax4ever committed Jul 29, 2024
1 parent e2fcec1 commit 089b8d4
Show file tree
Hide file tree
Showing 2 changed files with 201 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,117 @@ See <<search-dsl-argument-type>> for more information.
* For fields in nested objects, all nested objects are considered by default,
but that can be <<search-dsl-aggregation-common-filter,controlled explicitly with `.filter(...)`>>.

[[search-dsl-aggregation-metric]]
== Metric aggregations

include::../components/_incubating-warning.adoc[]

Hibernate Search provides a set of most common metric aggregations such as `sum`, `min`, `max`, `count`,
`count distinct` and `avg`. These aggregations can be requested for fields of numerical or temporal type.

[NOTE]
====
At the moment, it is only possible to request metric aggregations at the root level;
that is, the aggregation will be applied to the entire hit set.
====

[IMPORTANT]
====
The fields that are targeted by the aggregation function must be declared <<mapping-directfieldmapping-aggregable,aggregable>>.
====

=== Sum metric aggregation

The `sum` aggregation sums up the field values.

.Sum the prices all of the science fiction books
====
[source, JAVA, indent=0, subs="+callouts"]
----
include::{sourcedir}/org/hibernate/search/documentation/search/aggregation/AggregationDslIT.java[tags=sums]
----
<1> Define the target field path to which you want to apply the aggregation function and the expected returned type.
====

[NOTE]
====
You can always use the field type for the expected returned type.
Another option is to set `Double.class` for the expected returned type and you can always do it
even if the field is not double typed.
====

=== Min metric aggregation

The `min` aggregation provides the minimum value among the field values.

.Find the min release date among all the science fiction books
====
[source, JAVA, indent=0, subs="+callouts"]
----
include::{sourcedir}/org/hibernate/search/documentation/search/aggregation/AggregationDslIT.java[tags=min]
----
<1> Define the target field path to which you want to apply the aggregation function and the expected returned type.
====

=== Max metric aggregation

The `max` aggregation provides the maximum value among the field values.

.Find the max release date among all the science fiction books
====
[source, JAVA, indent=0, subs="+callouts"]
----
include::{sourcedir}/org/hibernate/search/documentation/search/aggregation/AggregationDslIT.java[tags=max]
----
<1> Define the target field path to which you want to apply the aggregation function and the expected returned type.
====

=== Count metric aggregation

The `count` aggregation counts the field values.

.Count anytime the price field has a value among all the science fiction books
====
[source, JAVA, indent=0, subs="+callouts"]
----
include::{sourcedir}/org/hibernate/search/documentation/search/aggregation/AggregationDslIT.java[tags=count]
----
<1> Define the target field path to which you want to apply the aggregation function. For this function a `Long.class` value is always returned.
====

=== Count distinct metric aggregation

The `count distinct` aggregation counts the different field values.

.Count anytime the price field has a different value among all the science fiction books
====
[source, JAVA, indent=0, subs="+callouts"]
----
include::{sourcedir}/org/hibernate/search/documentation/search/aggregation/AggregationDslIT.java[tags=count-distinct]
----
<1> Define the target field path to which you want to apply the aggregation function. For this function a `Long.class` value is always returned.
====

=== Avg metric aggregation

Applies the SQL `avg` aggregation function on a given numeric or temporal field.

.Compute the average of the prices all of the science fiction books
====
[source, JAVA, indent=0, subs="+callouts"]
----
include::{sourcedir}/org/hibernate/search/documentation/search/aggregation/AggregationDslIT.java[tags=avg]
----
<1> Define the target field path to which you want to apply the aggregation function and the expected returned type.
====

[NOTE]
====
In the case of the `avg()` aggregation, the result may have some decimal values,
even if the field type is represented by one of the integer number types.
In this case, if you want to return decimals, provide `Double.class` for the expected returned type.
====

[[search-dsl-aggregation-withparameters]]
== `withParameters`: create aggregations using query parameters

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,96 @@ void withParameters() {
} );
}

@Test
void sum() {
withinSearchSession( searchSession -> {
// tag::sums[]
AggregationKey<Double> sumPricesKey = AggregationKey.of( "sumPricesScienceFictionBooks" );
SearchResult<Book> result = searchSession.search( Book.class )
.where( f -> f.match().field( "genre" ).matching( Genre.SCIENCE_FICTION ) )
.aggregation( sumPricesKey, f -> f.sum().field( "price", Double.class ) ) // <1>
.fetch( 20 );
Double sumPrices = result.aggregation( sumPricesKey );
assertThat( sumPrices ).isEqualTo( 60.97 );
// end::sums[]
} );
}

@Test
void min() {
withinSearchSession( searchSession -> {
// tag::min[]
AggregationKey<Date> oldestReleaseKey = AggregationKey.of( "oldestRelease" );
SearchResult<Book> result = searchSession.search( Book.class )
.where( f -> f.match().field( "genre" ).matching( Genre.SCIENCE_FICTION ) )
.aggregation( oldestReleaseKey, f -> f.min().field( "releaseDate", Date.class ) ) // <1>
.fetch( 20 );
Date oldestRelease = result.aggregation( oldestReleaseKey );
assertThat( oldestRelease ).isEqualTo( Date.valueOf( "1950-12-02" ) );
// end::min[]
} );
}

@Test
void max() {
withinSearchSession( searchSession -> {
// tag::max[]
AggregationKey<Date> mostRecentReleaseKey = AggregationKey.of( "mostRecentRelease" );
SearchResult<Book> result = searchSession.search( Book.class )
.where( f -> f.match().field( "genre" ).matching( Genre.SCIENCE_FICTION ) )
.aggregation( mostRecentReleaseKey, f -> f.max().field( "releaseDate", Date.class ) ) // <1>
.fetch( 20 );
Date mostRecentRelease = result.aggregation( mostRecentReleaseKey );

// end::max[]
} );
}

@Test
void count() {
withinSearchSession( searchSession -> {
// tag::count[]
AggregationKey<Long> countPricesKey = AggregationKey.of( "countPrices" );
SearchResult<Book> result = searchSession.search( Book.class )
.where( f -> f.match().field( "genre" ).matching( Genre.SCIENCE_FICTION ) )
.aggregation( countPricesKey, f -> f.count().field( "price" ) ) // <1>
.fetch( 20 );
Long countPrices = result.aggregation( countPricesKey );
assertThat( countPrices ).isEqualTo( 3L );
// end::count[]
} );
}

@Test
void countDistinct() {
withinSearchSession( searchSession -> {
// tag::count-distinct[]
AggregationKey<Long> countDistinctPricesKey = AggregationKey.of( "countDistinctPrices" );
SearchResult<Book> result = searchSession.search( Book.class )
.where( f -> f.match().field( "genre" ).matching( Genre.SCIENCE_FICTION ) )
.aggregation( countDistinctPricesKey, f -> f.countDistinct().field( "price" ) ) // <1>
.fetch( 20 );
Long countDistinctPrices = result.aggregation( countDistinctPricesKey );
assertThat( countDistinctPrices ).isEqualTo( 3L );
// end::count-distinct[]
} );
}

@Test
void avg() {
withinSearchSession( searchSession -> {
// tag::avg[]
AggregationKey<Double> avgPricesKey = AggregationKey.of( "avgPrices" );
SearchResult<Book> result = searchSession.search( Book.class )
.where( f -> f.match().field( "genre" ).matching( Genre.SCIENCE_FICTION ) )
.aggregation( avgPricesKey, f -> f.avg().field( "price", Double.class ) ) // <1>
.fetch( 20 );
Double avgPrices = result.aggregation( avgPricesKey );
assertThat( avgPrices ).isEqualTo( 20.323333333333334 );
// end::avg[]
} );
}

private void withinSearchSession(Consumer<SearchSession> action) {
with( entityManagerFactory ).runInTransaction( entityManager -> {
SearchSession searchSession = Search.session( entityManager );
Expand Down

0 comments on commit 089b8d4

Please sign in to comment.