使用Java Specification / Predicate进行全文搜索

时间:2017-05-10 13:59:35

标签: java spring full-text-search spring-data-jpa predicate

我正在尝试将String与表中的每一列进行比较。有更简单的方法吗?

public class MySpec implements Specification<Tbl> {

    private Tbl searchCriteria;

    public MySpec(Tbl searchCriteria){
        this.searchCriteria = searchCriteria;
    }

    @Override
    public Predicate toPredicate(Root<Tbl> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

        List<Predicate> textPredicates = new ArrayList<>();
        String searchText = "%" + searchCriteria.getSearchText() + "%";

        textPredicates.add(cb.like(root.get("col1"), searchText));
        textPredicates.add(cb.like(root.get("col2"), searchText));
        textPredicates.add(cb.like(root.get("col3"), searchText));
        textPredicates.add(cb.like(root.get("col4"), searchText));
        textPredicates.add(cb.like(root.get("col5"), searchText));
        textPredicates.add(cb.like(root.get("col6"), searchText));
        textPredicates.add(cb.like(root.get("col7"), searchText));
        textPredicates.add(cb.like(root.get("col8"), searchText));
        textPredicates.add(cb.like(root.get("col9"), searchText));

        return query.where(cb.or(textPredicates.toArray(new Predicate[0])
                    .distinct(true).getRestriction();
    }
}

每次向表中添加新列时,我都不想更改规范代码。另一个选项是一个单独的表,它将在字符串中保存每列的连接版本。如:

TBL
Col1 | Col2    | Col3    | Col4
-----------------------------------------
1    | "Name"  | "Value" | "Other Value" 


TBL_CACHE
Col1 | Col2
------------------------------
1    | "Name Value OtherValue" 

但是我不想为每个想要全文搜索的表创建另一个表,我不希望维护这些数据的填充或创建一个SQL作业来自动完成。

2 个答案:

答案 0 :(得分:1)

让hibernate从实体中检索列列表。

String[] columnNames = getSessionFactory().getClassMetadata(Entity.class).getPropertyNames();

对于JPA,您可以浏览字段列表

for (Field field : entity.getClass().getDeclaredFields()) {
   Column column = field.getAnnotation(Column.class);
   if (column != null) {
      columnNames.add(column.name());
   }
}

如果您注释方法,则可以使用相同的方法。

同时检查thisthis。另一种获取元数据的方法。

然后使用列表列表jusst在循环中添加条件。

答案 1 :(得分:0)

您可以从CriteriaBuilder获取size()并创建一个循环。这假设列从1开始并以列数结束。

int sz = cb.size();
for (int ii = 1; ii <= sz; ii++) {
    String textIndex = "" + ii;
    textPredicates.add(cb.like(root.get("col" + textIndex), searchText));
}