Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[WARNING]
====
Features detailed in this section are _deprecated_: they should be avoided in favor of non-deprecated alternatives.

The usual https://hibernate.org/community/compatibility-policy/[compatibility policy] applies,
meaning the features are expected to remain available at least until the next major version of Hibernate Search.
Beyond that, they may be altered in a backward-incompatible way -- or even removed.

Usage of deprecated features is not recommended.
====
Original file line number Diff line number Diff line change
Expand Up @@ -289,52 +289,115 @@ include::{sourcedir}/org/hibernate/search/documentation/search/projection/Projec
[[search-dsl-projection-composite]]
== `composite`: combine projections

The `composite` projection applies multiple projections and combines their results.
The `composite` projection applies multiple projections and combines their results,
either as a `List<?>` or as a single object generated using a custom transformer.

To preserve type-safety, you can provide a custom combining function.
The combining function can be a `Function`, a `BiFunction`,
or a `org.hibernate.search.util.common.function.TriFunction`.
To preserve type-safety, you can provide a custom transformer.
The transformer can be a `Function`, a `BiFunction`,
or a `org.hibernate.search.util.common.function.TriFunction`,
depending on the number of inner projections.
It will receive values returned by inner projections and return an object combining these values.

Depending on the type of function,
either one, two, or three additional arguments are expected,
one for each inner projection.

.Returning custom objects created from multiple projected values
.Returning custom objects created from multiple projected values with `.composite().add(...).transform(...)`
====
[source, JAVA, indent=0, subs="+callouts"]
----
include::{sourcedir}/org/hibernate/search/documentation/search/projection/ProjectionDslIT.java[tags=composite-customObject]
----
<1> Call `.composite(...)`.
<2> Use the constructor of a custom object, `MyPair`, as the combining function.
<3> Define the first projection to combine as a projection on the `title` field,
meaning the constructor of `MyPair` will be called for each matched document
with the value of the `title` field as its first argument.
<4> Define the second projection to combine as a projection on the `genre` field,
meaning the constructor of `MyPair` will be called for each matched document
with the value of the `genre` field as its second argument.
<5> The hits will be the result of calling the combining function for each matched document,
<1> Call `.composite()`.
<2> Define the first projection to combine as a projection on the `title` field.
<3> Define the second projection to combine as a projection on the `genre` field.
<4> Define the transformer as the constructor of a custom object, `MyPair`.
The constructor of `MyPair` will be called for each matched document,
with the value of the `title` field as its first argument,
and the value of the `genre` field as its second argument.
<5> The hits will be the result of calling the transformer for each matched document,
in this case `MyPair` instances.
====

If you need more inner projections, or simply if you don't mind receiving the result of inner projections as a `List<?>`,
you can use the variant of `.composite(...)` that doesn't expect a function argument:
If you pass more than 3 projections as arguments,
then the transform function will have to take a `List<?>` as an argument,
and will be set using `transformList(...)` instead of `transform(..,)`:

.Returning custom objects created from multiple projected values with `.composite().add(...).transformList(...)`
====
[source, JAVA, indent=0, subs="+callouts"]
----
include::{sourcedir}/org/hibernate/search/documentation/search/projection/ProjectionDslIT.java[tags=composite-customObject-fromList]
----
<1> Call `.composite()`.
<2> Define the first projection to combine as a projection on the `title` field.
<3> Define the second projection to combine as a projection on the `genre` field.
<4> Define the third projection to combine as a projection on the `pageCount` field.
<5> Define the fourth projection to combine as a projection on the `description` field.
<6> Define the transformer as a lambda that will take elements of the list (the projections defined above, in order),
cast them, and pass them to the constructor of a custom class, `MyTuple4`.
<7> The hits will be the result of calling the transformer for each matched document,
in this case `MyTuple4` instances.
====

If you don't mind receiving the result of inner projections as a `List<?>`,
you can do without the transformer by calling `asList()`:

.Returning a `List` of projected values
.Returning a `List` of projected values with `.composite().add(...).asList()`
====
[source, JAVA, indent=0, subs="+callouts"]
----
include::{sourcedir}/org/hibernate/search/documentation/search/projection/ProjectionDslIT.java[tags=composite-list]
----
<1> Call `.composite()`.
<2> Define the first projection to combine as a projection on the `title` field.
<3> Define the second projection to combine as a projection on the `genre` field.
<4> Define the result of the projection as a list,
meaning the hits will be `List` instances with the value of the `title` field of the matched document at index `0`,
and the value of the `genre` field of the matched document at index `1`.
<5> The hits will be `List` instances holding the result of the given projections, in the given order, for each matched document.
====

Alternatively, to get the result as a `List<?>`,
you can use the shorter variant of `.composite(...)` that directly takes projections as arguments:

.Returning a `List` of projected values with `.composite(...)`
====
[source, JAVA, indent=0, subs="+callouts"]
----
include::{sourcedir}/org/hibernate/search/documentation/search/projection/ProjectionDslIT.java[tags=composite-list-singlestep]
----
<1> Call `.composite(...)`.
<2> Define the first projection to combine as a projection on the `title` field.
<3> Define the second projection to combine as a projection on the `genre` field.
<4> The hits will be `List` instances holding the result of the given projections, in the given order, for each matched document,
meaning the hits will be `List` instances with the value of the `title` field of the matched document at index `0`,
and the value of the `genre` field of the matched document at index `1`.
====

[[search-dsl-projection-composite-deprecated-variants]]
=== Deprecated variants

include::components/deprecated-warning.asciidoc[]

A few `.composite(...)` methods accepting both a function and a list of projections
are available on `SearchProjectionFactory`, but they are deprecated.

.Deprecated variant of `composite`
====
[source, JAVA, indent=0, subs="+callouts"]
----
include::{sourcedir}/org/hibernate/search/documentation/search/projection/ProjectionDslIT.java[tags=composite-customObject-singlestep]
----
<1> Call `.composite(...)`.
<2> Define the first projection to combine as a projection on the `title` field,
meaning the hits will be `List` instances with the value of the `title` field of the matched document at index `0`.
<3> Define the second projection to combine as a projection on the `genre` field,
meaning the hits will be `List` instances with the value of the `genre` field of the matched document at index `1`.
<4> The hits will be `List` instances holding the result of the given projections, in the given order, for each matched document.
<2> Define the transformer as the constructor of a custom object, `MyPair`.
<3> Define the first projection to combine as a projection on the `title` field,
meaning the constructor of `MyPair` will be called for each matched document
with the value of the `title` field as its first argument.
<4> Define the second projection to combine as a projection on the `genre` field,
meaning the constructor of `MyPair` will be called for each matched document
with the value of the `genre` field as its second argument.
<5> The hits will be the result of calling the transformer for each matched document,
in this case `MyPair` instances.
====


[[search-dsl-projection-extensions]]
== Backend-specific extensions

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,9 @@ public void smoke() {

List<Result> result = searchSession.search( WebPage.class )
.extension( LuceneExtension.get() )
.select( f -> f.composite(
Result::new,
f.entity(),
f.field( "pageRank", Float.class )
) )
.select( f -> f.composite()
.add( f.entity(), f.field( "pageRank", Float.class ) )
.transform( Result::new ) )
.where( f -> f.fromLuceneQuery(
// This affects the document score based on the pageRank
FeatureField.newSaturationQuery( "pageRank", "pageRank" )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.hibernate.search.engine.backend.types.ObjectStructure;
import org.hibernate.search.engine.backend.types.Projectable;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.GenericField;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexedEmbedded;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.KeywordField;
Expand All @@ -34,6 +35,12 @@ public class Book {
@KeywordField(projectable = Projectable.YES)
private Genre genre;

@GenericField(projectable = Projectable.YES)
private Integer pageCount;

@FullTextField(analyzer = "english", projectable = Projectable.YES)
private String description;

@ManyToMany
@IndexedEmbedded(structure = ObjectStructure.NESTED)
private List<Author> authors = new ArrayList<>();
Expand Down Expand Up @@ -65,6 +72,22 @@ public void setGenre(Genre genre) {
this.genre = genre;
}

public Integer getPageCount() {
return pageCount;
}

public void setPageCount(Integer pageCount) {
this.pageCount = pageCount;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public List<Author> getAuthors() {
return authors;
}
Expand Down
Loading