wheeleruniverse
wheeleruniverse

Reputation: 1635

Full Text Search with Java Specification/Predicate

I am trying to compare a String against every column in the table. Is there an easier way to do this?

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();
    }
}

I don't want to have to change the specification code every time I add a new column to the table. Another option is a separate table that will hold a concatenated version of each column in a string. Such as:

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


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

But I don't want to create another table for each table I want to full text search on and I don't want the maintenance of populating this data or creating a SQL job to do it automatically.

Upvotes: 0

Views: 1217

Answers (2)

StanislavL
StanislavL

Reputation: 57421

For hibernate to retrieve list of columns from entity.

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

For JPA you can go through the list of fields

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

And you can use the same approach if you annotate methods.

Also check this and this. One more way to get metadata.

Then using the columns list jusst add your conditions in a loop.

Upvotes: 1

Dakoda
Dakoda

Reputation: 175

You could get the size() from the CriteriaBuilder and create a loop. This assumes the column starts at 1 and ends at number of columns.

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

Upvotes: 0

Related Questions