Hibernate Search - Projection DSL
Projections do just that: they allow the query to return something more precise than just "the matching entities". Projections can be configured when building the search query:
SearchSession searchSession = Search.session( entityManager );
List<String> result = searchSession.search( Book.class )
.select( f -> f.field( "title", String.class ) )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Start building the query as usual.
Mention that the expected result of the query is a projection on field "title", of type String. If that type is not appropriate or if the field does not exist, an exception will be thrown.
Fetch the results, which will have the expected type.
SearchScope<Book> scope = searchSession.scope( Book.class );
List<String> result = searchSession.search( scope )
.select( scope.projection().field( "title", String.class )
.toProjection() )
.where( scope.predicate().matchAll().toPredicate() )
.fetchHits( 20 );
documentReference: return references to matched documents
Returning references to matched documents
List<DocumentReference> hits = searchSession.search( Book.class )
.select( f -> f.documentReference() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
entityReference: return references to matched entities
Returning references to matched entities
List<EntityReference> hits = searchSession.search( Book.class )
.select( f -> f.entityReference() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
entity: return matched entities loaded from the database
Returning matched entities loaded from the database
List<Book> hits = searchSession.search( Book.class )
.select( f -> f.entity() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
.select( f -> f.field( "genre", Genre.class ) )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Returning field values from matched documents, without specifying the field type
List<Object> hits = searchSession.search( Book.class )
.select( f -> f.field( "genre" ) )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Returning field values from matched documents, without converting the field value
List<String> hits = searchSession.search( Book.class )
.select( f -> f.field(
"genre", String.class, ValueConvert.NO
) )
.where( f -> f.matchAll() )
.fetchHits( 20 );
score: return the score of matched documents
Returning the score of matched documents
List<Float> hits = searchSession.search( Book.class )
.select( f -> f.score() )
.where( f -> f.match().field( "title" )
.matching( "robot dawn" ) )
.fetchHits( 20 );
distance: return the distance to a point
Returning the distance to a point
GeoPoint center = GeoPoint.of( 47.506060, 2.473916 );
SearchResult<Double> result = searchSession.search( Author.class )
.select( f -> f.distance( "placeOfBirth", center ) )
.where( f -> f.matchAll() )
.fetch( 20 );
Returning the distance to a point with a given distance unit
GeoPoint center = GeoPoint.of( 47.506060, 2.473916 );
SearchResult<Double> result = searchSession.search( Author.class )
.select( f -> f.distance( "placeOfBirth", center )
.unit( DistanceUnit.KILOMETERS ) )
.where( f -> f.matchAll() )
.fetch( 20 );
composite: combine projections
List<MyPair<String, Genre>> hits = searchSession.search( Book.class )
.select( f -> f.composite(
MyPair::new,
f.field( "title", String.class ),
f.field( "genre", Genre.class )
) )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Call .composite(…).
Use the constructor of a custom object, MyPair, as the combining function. The combining function can be a Function, a BiFunction, or a org.hibernate.search.util.common.function.TriFunction. It will combine values returned by other projections and create an object returned by the composite projection. Depending on the type of function, either one, two, or three additional arguments are expected.
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.
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.
The hits will be the result of calling the combining function for each matched document, in this case MyPair instances.
.select( f -> f.composite(
f.field( "title", String.class ),
f.field( "genre", Genre.class )
) )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Call .composite(…).
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.
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.
The hits will be List instances holding the result of the given projections, in order for each matched document.
Returning the matched document as a native org.apache.lucene.document.Document
List<Document> hits = searchSession.search( Book.class )
.extension( LuceneExtension.get() )
.select( f -> f.document() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Returning the score explanation as a native org.apache.lucene.search.Explanation
List<Explanation> hits = searchSession.search( Book.class )
.extension( LuceneExtension.get() )
.select( f -> f.explanation() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
List<JsonObject> hits = searchSession.search( Book.class )
.extension( ElasticsearchExtension.get() )
.select( f -> f.source() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Returning the score explanation as a JsonObject
List<JsonObject> hits = searchSession.search( Book.class )
.extension( ElasticsearchExtension.get() )
.select( f -> f.explanation() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Direct changes to the HTTP request may conflict with Hibernate Search features and be supported differently by different versions of Elasticsearch.
Similarly, the content of the HTTP response may change depending on the version of Elasticsearch, depending on which Hibernate Search features are used, and even depending on how Hibernate Search features are implemented.
Thus, features relying on direct access to HTTP requests or responses cannot be guaranteed to continue to work when upgrading Hibernate Search, even for micro upgrades (x.y.z to x.y.(z+1)).
Use this at your own risk.
Returning the Elasticsearch hit as a JsonObject
List<JsonObject> hits = searchSession.search( Book.class )
.extension( ElasticsearchExtension.get() )
.select( f -> f.jsonHit() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Using projections to extract data from the index
SearchSession searchSession = Search.session( entityManager );List<String> result = searchSession.search( Book.class )
.select( f -> f.field( "title", String.class ) )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Start building the query as usual.
Mention that the expected result of the query is a projection on field "title", of type String. If that type is not appropriate or if the field does not exist, an exception will be thrown.
Fetch the results, which will have the expected type.
Using projections to extract data from the index — object-based syntax
SearchSession searchSession = Search.session( entityManager );SearchScope<Book> scope = searchSession.scope( Book.class );
List<String> result = searchSession.search( scope )
.select( scope.projection().field( "title", String.class )
.toProjection() )
.where( scope.predicate().matchAll().toPredicate() )
.fetchHits( 20 );
documentReference: return references to matched documents
Returning references to matched documents
List<DocumentReference> hits = searchSession.search( Book.class )
.select( f -> f.documentReference() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
entityReference: return references to matched entities
Returning references to matched entities
List<EntityReference> hits = searchSession.search( Book.class )
.select( f -> f.entityReference() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
entity: return matched entities loaded from the database
Returning matched entities loaded from the database
List<Book> hits = searchSession.search( Book.class )
.select( f -> f.entity() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
field: return field values from matched documents
Returning field values from matched documents
List<Genre> hits = searchSession.search( Book.class ).select( f -> f.field( "genre", Genre.class ) )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Returning field values from matched documents, without specifying the field type
List<Object> hits = searchSession.search( Book.class )
.select( f -> f.field( "genre" ) )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Returning field values from matched documents, without converting the field value
List<String> hits = searchSession.search( Book.class )
.select( f -> f.field(
"genre", String.class, ValueConvert.NO
) )
.where( f -> f.matchAll() )
.fetchHits( 20 );
score: return the score of matched documents
Returning the score of matched documents
List<Float> hits = searchSession.search( Book.class )
.select( f -> f.score() )
.where( f -> f.match().field( "title" )
.matching( "robot dawn" ) )
.fetchHits( 20 );
distance: return the distance to a point
Returning the distance to a point
GeoPoint center = GeoPoint.of( 47.506060, 2.473916 );
SearchResult<Double> result = searchSession.search( Author.class )
.select( f -> f.distance( "placeOfBirth", center ) )
.where( f -> f.matchAll() )
.fetch( 20 );
Returning the distance to a point with a given distance unit
GeoPoint center = GeoPoint.of( 47.506060, 2.473916 );
SearchResult<Double> result = searchSession.search( Author.class )
.select( f -> f.distance( "placeOfBirth", center )
.unit( DistanceUnit.KILOMETERS ) )
.where( f -> f.matchAll() )
.fetch( 20 );
composite: combine projections
Returning custom objects created from multiple projected values
List<MyPair<String, Genre>> hits = searchSession.search( Book.class ).select( f -> f.composite(
MyPair::new,
f.field( "title", String.class ),
f.field( "genre", Genre.class )
) )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Call .composite(…).
Use the constructor of a custom object, MyPair, as the combining function. The combining function can be a Function, a BiFunction, or a org.hibernate.search.util.common.function.TriFunction. It will combine values returned by other projections and create an object returned by the composite projection. Depending on the type of function, either one, two, or three additional arguments are expected.
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.
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.
The hits will be the result of calling the combining function for each matched document, in this case MyPair instances.
Returning a List of projected values
List<List<?>> hits = searchSession.search( Book.class ).select( f -> f.composite(
f.field( "title", String.class ),
f.field( "genre", Genre.class )
) )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Call .composite(…).
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.
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.
The hits will be List instances holding the result of the given projections, in order for each matched document.
Lucene: document
Returning the matched document as a native org.apache.lucene.document.DocumentList<Document> hits = searchSession.search( Book.class )
.extension( LuceneExtension.get() )
.select( f -> f.document() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Lucene: explanation
Explanations are rather costly performance-wise: only use them for debugging purposes.Returning the score explanation as a native org.apache.lucene.search.Explanation
List<Explanation> hits = searchSession.search( Book.class )
.extension( LuceneExtension.get() )
.select( f -> f.explanation() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Elasticsearch: source
Returning the matched document source as a JsonObjectList<JsonObject> hits = searchSession.search( Book.class )
.extension( ElasticsearchExtension.get() )
.select( f -> f.source() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Elasticsearch: explanation
Explanations are rather costly performance-wise: only use them for debugging purposes.Returning the score explanation as a JsonObject
List<JsonObject> hits = searchSession.search( Book.class )
.extension( ElasticsearchExtension.get() )
.select( f -> f.explanation() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Elasticsearch: jsonHit
This is particularly useful when customizing the request’s JSON to ask for additional data within each hit.Direct changes to the HTTP request may conflict with Hibernate Search features and be supported differently by different versions of Elasticsearch.
Similarly, the content of the HTTP response may change depending on the version of Elasticsearch, depending on which Hibernate Search features are used, and even depending on how Hibernate Search features are implemented.
Thus, features relying on direct access to HTTP requests or responses cannot be guaranteed to continue to work when upgrading Hibernate Search, even for micro upgrades (x.y.z to x.y.(z+1)).
Use this at your own risk.
Returning the Elasticsearch hit as a JsonObject
List<JsonObject> hits = searchSession.search( Book.class )
.extension( ElasticsearchExtension.get() )
.select( f -> f.jsonHit() )
.where( f -> f.matchAll() )
.fetchHits( 20 );
Comments
Post a Comment