问题
I want to use this query: SELECT * FROM USER JOIN USER_CACHE ON USER.ID = USER_CACHE.ID WHERE MATCH (CACHE) AGAINST ( :someText ) > 0 inside the Predicate using Spring Data JPA with Root, CriteriaQuery and CriteriaBuilder classes and add the predicate to a list of predicates that I later condense.
For a while i was using the CONTAINS function, however the database version I updated to no longer supports this procedure.
Is what I am trying to achieve possible?
I don't want to use a nativeQuery because I have other search criteria that the user may want to query on besides the search text and too many columns in my table to create unique queries for every combination of variables.
I don't want to run multiple queries on the database and filter the result after the fact. It has to be one query or I won't be able to get the code passed inspection.
I can't alter the database scheme and can guarantee that the full text index is built and in place.
Database - Can't change this.
// User Table
ID | NAME | STATUS | TYPE
------------------------------------------------------
1 | Dan | Employed | Salary
2 | Mark | Retired | Salary
3 | Liz | Temporary | Hourly
4 | Paul | Employed | Salary
// Cache Table
ID | CACHE *Note: Full Text Search Index
------------------------------------------------------
1 | ID 1 NAME Dan STATUS Employed TYPE Salary
2 | ID 2 NAME Mark STATUS Retired TYPE Salary
3 | ID 3 NAME Liz STATUS Temporary TYPE Hourly
4 | ID 4 NAME Paul STATUS Employed TYPE Salary
Java
public UserSearchInput class {
private String searchText; // Full Text Search
private List<String> userNames;
private List<String> userStatuses;
private List<String> userTypes;
// Get & Set
}
// Specification
public MySearchSpec implements Specification<User> {
private UserSearchInput searchInput;
public MySearchSpec(UserSearchInput searchInput){
this.searchInput = searchInput;
}
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicates = new ArrayList<>();
if(searchInput.getSearchText() != null && !searchInput.getSearchText().trim().isEmpty()){
Root<UserCache> cache = query.from(UserCache.class);
/*
* SELECT * FROM USER
* JOIN USER_CACHE
* ON USER.ID = USER_CACHE.ID
* WHERE MATCH (CACHE) AGAINST ('"SEARCH STRING"') > 0;
*/
}
if(searchInput.getUserNames() != null && !searchInput.getUserNames().isEmpty()){
predicates.add(root.get("name").in(searchInput.getUserNames()));
}
if(searchInput.getUserStatuses() != null && !searchInput.getUserStatuses().isEmpty()){
predicates.add(root.get("status").in(searchInput.getUserStatuses());
}
if(searchInput.getUserTypes() != null && !searchInput.getUserTypes().isEmpty()){
predicates.add(root.get("type").in(searchInput.getUserTypes());
}
return query.where(cb.and(predicates.toArray(new Predicate[0])).getRestriction());
}
}
// Service Method
@Autowired
private UserRepository userRepo;
@Async
public Future<List<User>> getUsers(UserSearchInput searchInput, Integer page, Integer size){
page = page == null || page < 0 ? 0 : page;
size = size == null || size < 1 ? 100 : size;
Page<User> userPage = userRepo.findAll(new MySearchSpec(searchInput), new PageRequest(page, size));
return new AsyncResult<>(userPage.getContent());
}
I was reading this post : How to use MySQL's full text search from JPA and trying to follow it, but I found a few issues. I need to use EntityManager to set parameters which I can only do when I create the TypedQuery object and pull the results. Additionally doing this will not allow me to use Pagination and my table has way too many results to go without. I thought that I could add a limit, but wasn't too sure how I would grab the next page of results.
Then I thought I could just put the Native SQL inside of the Repository like:
@Query(value = "SELECT * FROM USER " +
"JOIN USER_CACHE " +
"ON USER.ID = USER_CACHE.ID " +
"WHERE MATCH (CACHE) AGAINST (' :searchString ') > 0",
nativeQuery = true)
public List<User> fullTextSearch(@Param("searchString") searchString);
but the pagination issues still arise. Furthermore I cannot filter by the other search criteria in the RequestBody with this approach.
来源:https://stackoverflow.com/questions/43989817/match-against-in-java-spring-data-jpa