Home > Back-end >  Use pagination on query on multiple indices in hibernate search
Use pagination on query on multiple indices in hibernate search

Time:08-24

we are implementing a global search that we can use to query all entities in our application, let's say cars, books and movies. Those entities do not share common fields, cars have a manufacturer, books have an author and movies have a director, for example.

In a global search field I'd like to search for all my entities with one query to be able to use pagination. Two aproaches come to my mind when thinking about how to solve this:

  1. Query one index after another and manually merge the result. This means that I have to implement pagination myself.
  2. Add common fields to each item like name and creator (or create an interface as shown here Single return type in Hibernate Search).In this case I can only search for fields in my global search that I map to the common fields.

My question is now: Is there a third (better) way? How would you suggest to implement such a global search on multiple indices?

CodePudding user response:

One approach would be to create a SQL view (SearchEntry?) that combines all of the tables you want to search. This allows you to alias your different column names. It won't be very good for performance but you could also just create one big field that is a concatenation of different searchable fields. Finally, include a "type" field that you tie back to your entity.

Now you can query everything in one go and use the type/id to tie back to a specific entity that the "search" data was initially pulled from.

CodePudding user response:

Query one index after another and manually merge the result. This means that I have to implement pagination myself.

I definitely wouldn't do that, as this will perform very poorly, especially with deep pagination (page 40, etc.).

Add common fields to each item like name and creator (or create an interface as shown here Single return type in Hibernate Search).In this case I can only search for fields in my global search that I map to the common fields.

That's the way. You don't even need a common interface since you can just target multiple fields in the same predicate. The common interface would only help to target all relevant types: you can call .search(MyInterface.class) instead of .search(Arrays.asList(Car.class, Book.class, Movie.class)).

You can still apply predicates to fields that are specific to each type; it's just that fields that appear in more than one type must be consistent (same type, etc.). Also, obviously, if you require that the "manufacturer" (and no other field) matches "james", Books and Movies won't match anymore, since they don't have a manufacturer.

Have you tried it? For example, this should work just fine as long as manufacturer, author and director are all text fields with the same analyzer:

SearchResult<Object> result = searchSession.search( Arrays.asList( 
                Car.class, Book.class, Movie.class
        ) )
        .where( f -> f.simpleQueryString() 
                .fields( "manufacturer", "author", "director"  )
                .matching( "james" ) )
        .fetch( 20 ); 
List<Object> hits = result.hits(); // Result is a mix of Car, Book and Movie.
  • Related