Is it possible to search multiple entities for the same keyword, filtering each type with a specific filter and getting them in a single list?
For example having the entities, breeder and animal and searching their data for the terms "Boston Terrier". After that the breeders are filtered for location and animals for species and a single list is returned containing both Animals and Breeders.
This list can then be trimmed to enable pagination of the results in the front end of a web-application:
// FullTextQuery ftq = .... definiing and filtering the query
int numResults = ftq.getResultSize();
ftq.setFirstResult((pageNum-1)*numPerPage);
ftq.setMaxResults(numPerPage);
List<Object> results = ftq.getResultList();
Assuming you don't care about the relation between breeders and animals, and just want to search for animals OR breeders: yes, you can.
But there are some conditions:
Animal
class and the Breeder
class: same analyzer in particular. Otherwise, your search results will probably be inconsistent. The fields do not have to exist in both indexes: filtering on an "animalName" and "breederName" fields should work fine.Animal
class. Otherwise, the animals will be filtered by location too.Breeder
class. Otherwise, the breeders will be filtered by species too.If the answer to all three items above is "yep, I'm good", then you can do the following.
EDIT: Nowadays I would strongly recommend upgrading to Hibernate Search 6.0 or above, which makes searching multiple indexes in the same query much easier.
In fact, you don't have to do anything specific, except listing the targeted types.
The snippet from my original answer, converted to Hibernate Search 6, would look something like this:
EntityManager em = ...;
List<Object> hits = Search.session(em)
.search(Arrays.asList(Animal.class, Breeder.class))
.where(f -> f.bool()
.must(f.simpleQueryString()
.fields("animalName",
"breeder.company.legalName",
"breeder.firstName",
"breeder.lastName")
.matching("Boston Terrier")
.defaultOperator(BooleanOperator.AND))
.must(f.bool()
.should(f.spatial().within()
.field("breederLocation")
.circle(42.0, 42.0,
50, DistanceUnit.KILOMETERS))
.should(f.match()
.field("species")
.matching(<some species>)))
.fetchHits( 20 );
ORIGINAL SOLUTION, for Hibernate Search 5:
QueryBuilder
for Animal
, say animalQueryBuilder
QueryBuilder
for Breeder
, say breederQueryBuilder
animalQueryBuilder
for the species filter.breederQueryBuilder
for the location filterThen, when creating the query, pass both the Animal class and the Breeder class to the createFullTextQuery
method.
The query should return both animals and breeders.
Something like that:
QueryBuilder animalQueryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity( Animal.class ).get();
QueryBuilder breederQueryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity( Breeder.class ).get();
Query locationQuery = breederQueryBuilder.spatial()
.onField( "breederLocation" )
.within( 10.0, DistanceUnit.KM )
.ofLatitude( 42.0 ).andLongitude( 42.0 )
.createQuery();
Query speciesQuery = animalQueryBuilder.keyword()
.onField( "species" )
.matching( <some species> );
Query termsQuery = animalQueryBuilder.simpleQueryString()
.onFields(
"animalName", "breeder.company.legalName",
"breeder.firstName", "breeder.lastName"
)
.withAndAsDefaultOperator()
.matching( "Boston Terrier" );
Query booleanQuery = animalQueryBuilder.bool()
.must( termsQuery )
.must( animalQueryBuilder.bool()
.should( locationQuery )
.should( speciesQuery )
.createQuery()
)
.createQuery();
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery( booleanQuery, Animal.class, Breeder.class );