我正在尝试实现简单的文本搜索。我想允许用户键入任意数量的单词,并对照文章标题检查所有这些单词。如果标题与搜索中的所有单词匹配(以任何顺序),则将返回结果。
一些示例数据库查询将如下所示:
SELECT * FROM Article WHERE
lower(title) like lower(concat('%', '<term1>', '%'));
SELECT * FROM Article WHERE
lower(title) like lower(concat('%', '<term1>', '%'))
AND lower(title) like lower(concat('%', '<term2>', '%'));
SELECT * FROM Article WHERE
lower(title) like lower(concat('%', '<term1>', '%'))
AND lower(title) like lower(concat('%', '<term2>', '%'));
AND lower(title) like lower(concat('%', '<term3>', '%'));
请注意在每种情况下如何搜索title
列,并将其与1、2或3(或更多)项进行比较。
我可以创建单个JPQL查询来做到这一点吗?
类似这样的东西:
@Query("SELECT a FROM Article a WHERE lower(a.title) in %:terms%")
Iterable<Article> findAllContainingTitle(String... terms)
似乎Java的varargs起作用了,但更多地体现了集合中的特定值。
更新1
感谢this question和this link,我学习了如何直接在Postgres查询中做到这一点:
SELECT * FROM Article WHERE ~~* ALL(ARRAY['%term1%', '%term2%', '%term3%']);
现在的挑战是尝试将其转换为Spring Data JPA查询。
注意:~~*
也可以与ILIKE
交换(不区分大小写的LIKE
语句)。
答案 0 :(得分:0)
这不能回答我的问题,但是如果其他任何人需要类似的东西,它至少提供了一种解决方法。要求的一部分是还使用JOIN FETCH
在单个查询中拉回所有数据,而不会遇到N + 1性能问题。
解决方法是使用CriteriaBuilder
和CriteriaQuery
动态生成查询。我觉得这会创建一个可读性较低的查询,但是它肯定总比没有好。
@Autowired
private EntityManager entityManager;
...
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder()
CriteriaQuery<Content> criteriaQuery = criteriaBuilder.createQuery(Article.class);
Root<Article> rootArticle = crirteriaQuery.from(Article.class);
// Provide any number of joins here
rootArticle.fetch("author", JoinType.INNER);
// This is where we dynamically add all of the 'like' statements
List<Predicate> predicates = new ArrayList<>();
// Assume that 'searchQuery' is plain text from the user, that will be split on spaces to get individual search terms.
for (String searchTerm : searchQuery.split(" ")) {
predicates.add(criteriaBuilder.like(
criteriaBuilder.lower(rootArticle.get("title")),
"%"+searchTerm.toLowerCase()+"%"));
}
criteriaQuery.where(predicates.toArray(new Predicate[0]));
TypedQuery<Article> query = entityManager.createQuery(criteriaQuery);
List<Article> articles = query.getResultList();
特别感谢this answer与this page的链接,其中https://bugs.llvm.org/show_bug.cgi?id=39363#c8解释了如何将JOIN
语句添加到CriteriaQuery
。