I am using JPA 2.1 (Hibernate 4 as impl) and Spring Data JPA 1.9.0. How to implement full-text search?
My scenario is as follows. I have a User object, and in the user interface there is a table that displays most of the properties of users, and I want the user to provide a text box, enter the search term there and search in all the properties.
I see 2 options for this:
- Download all user users from the database and filter them in Java
- Write a JPQL query with many
ORs and LIKE % :searchString %
Option 1 is not suitable for performance, but pretty nice to write.
Option 2 is an executable beacuse, executable on the database side, but cumbersome to write.
Currently, option 1 is assigned to me, because I need to translate boolean to "yes"/"no" , and also have an enumeration of the profile where I want to search by its description of the field, and not by the actual value of the enumeration.
In the User object, I have a method that returns all the fields that I want to find, separated by spaces:
public String getSearchString(){ return StringUtils.join( Arrays.asList( login, firstName, lastName, email, active ? "yes" : "no", profile.getDescription()) , " "); }
In the service, I load all users from the database and filter this search string:
@Override public List<User> getUsers(final String searchText) { final List<User> users = getUsers(); if(StringUtils.isBlank(searchText)){ return users; } CollectionUtils.filter(users, new Predicate<User>() { @Override public boolean evaluate(User object) { return StringUtils.containsIgnoreCase(object.getSearchString(), searchText); } }); return users; }
On the other hand, in JPQL I get queries that I think are the easiest and easiest way to implement this function. There is also a problem with translatin boolean on "yes" and "no".
@Query("SELECT r FROM User r WHERE " + "r.firstname LIKE '%' || :searchString || '%' " + "OR r.lastname LIKE '%' || :searchString || '%' " + "OR r.login LIKE '%' || :searchString || '%' " + "OR r.profile.description LIKE '%' || :searchString || '%' " + "OR r.active LIKE '%' || :searchString || '%' " + "OR r.email LIKE '%' || :searchString || '%'") List<User> selectUsers(@Param("searchString")String searchString, Pageable page);
Is there a better solution to this problem?