我在JPA2中使用本机查询来查询此文本,以搜索不区分大小写或所用重音(基于http://www.guj.com.br/java/212706-accent-insensitive-hibernate)的纯文本:
public List<Hipotesis> findHipotesisByText(String srchtext) {
EntityManager em = getEntityManager();
String textNormalized =
Normalizer.normalize(srchtext, Normalizer.Form.NFD).replaceAll("[^\\p{ASCII}]", "").toUpperCase();
Query query =
em.createNativeQuery(
"select * from HIPOTESIS where ( UPPER(TRANSLATE( TEXTFIELD,'ÀÁÂÃáàâãÉÈÊéèêÍíÓÒÔÕóòôõÚÜúü','AAAAaaaaEEEeeeIiOOOOooooUUuu' ) ) like '%" + textNormalized + "%'",
Hipotesis.class);
@SuppressWarnings("unchecked")
List<Hipotesis> results = query.getResultList();
return results;
}
将搜索文本规范化为带重音符号,并转换为大写字母。
本机查询使用TRANSLATE将重音符号转换为纯文本,而UPPER将结果转换为大写字母。
因此,搜索文本eMeRgÊ将被归一化为EMERGE,并将匹配数据库中出现的任何紧急情况,例如emergecia,emergência,Emergência。
尽管SQL99指定了TRANSLATE,但它并不完全像标准一样支持或实现。
问题:不使用TRANSLATE可以实现该查询吗?还是不使用本机查询?
最佳答案
我个人认为,最优雅的解决方案是实际复制数据并将其转换为规范化形式。您在查询中使用了LIKE
条件,该条件基本上排除了任何常规的(缺少全文本)索引机制。这意味着TRANSLATE
查询很可能效率低下且难以优化。
使用JPA,您可以利用实体生命周期事件以相当方便的方式来管理标准化表格:
@Entity
public class Whatever implements Serializable {
private static final long serialVersionUID = 0L;
private String string;
private String normalizedString;
// getters and setters
@PreUpdate
@PrePersist
protected void normalize() {
normalizedString = yourNormalizationMethod(string);
}
}
我认为这是解决此类问题的最简洁,最优雅,最不了解数据库的方法。