3
votes

I have a spring MVC application with search capabilities.

Flow: UI > CONTROLLER > BL > DATA > SOLR

Users are allowed to search something using multiple fields, example search by name or department. The business layer needs to have a Lucene Query Builder which accepts the string and builds a proper Lucene query for SOLR.

My Controller:

@GetMapping(params = "name")
public Page<User> findUserByName(@RequestParam("name") final String name) {
    return userService.findUserByName(name);
}

@GetMapping(params = "department")
public Page<User> findUserByDepartment(@RequestParam final String department) {
    return userService.findUserByFulltext(department);
}

Dummy Query Builder

public String searchByNameQuery(final String name) {
    return "nm:" + name;
}
public String searchByDepartmentQuery(final String department) {
    return "dpt:" + department;
}

Now this dummy query builder doesn't support wildcard or any other varieties. I am going through the Apache Lucene Query API (added lucene core-7.7.1 to project as well) and bunch of articles that teaches how to use different types of Query implementations (TermQuery, PhraseQuery, BooleanQuery, etc) but it doesn't make sense at all. In the end, I am still manually building the queries.

Can someone please help by showing how can I have a proper Lucene Query Builder Class?

I need to generate queries for these type of texts with exact phrase and wildcards

(exact)Search by name: Ohio State University
Search by name: *State
Search by name: Ohio*University
Search by name: Ohio State*
Search by Department:Computer Science Dept
Search by Department: *Science

Combined Query:

nm:"Ohio State University" AND dpt:"Computer Science"
1
new WildcardQuery(new Term("fieldName", "wildcardSearchstring")).toString()JineshEP
I did like this - Query q = new WildcardQuery(new Term("nm","helloworld")); and the result is nm:helloworld. I need it to be nm:hello\\worldAMagic
Any suggestions on Combined (Boolean operators) query?AMagic
You could have a BooleanQuery that takes in multiple wildcard queries using Boolean query add.JineshEP

1 Answers

1
votes

A boolean query builder can be used like this for eg:

new BooleanQuery.Builder().add(query1, BooleanClause.OCCUR.MUST)
                              .add(query2, BooleanClause.OCCUR.MUST_NOT)
                              .build();

And if you would prefer to have complex aggregation , for the field and search strings - you may write something like -

public class CustomBooleanQueryBuilder {

    public Map<BooleanClause.Occur, List<Query>> getClauseQueryMap() {
        return clauseQueryMap;
    }

    private final Map<BooleanClause.Occur, List<Query>> clauseQueryMap = new HashMap();

    public static void main(String args[]) throws ParseException {
        CustomBooleanQueryBuilder queryBuilder = new CustomBooleanQueryBuilder();

        final Query regExpQuery = new RegexpQuery(new Term("nm", "Hello\\sWorld"));
        queryBuilder.addUpdateQueryMap(regExpQuery, BooleanClause.Occur.MUST);

        final Query wildcardQuery = new WildcardQuery(new Term("nm", "Hello?World"));
        queryBuilder.addUpdateQueryMap(wildcardQuery, BooleanClause.Occur.MUST_NOT);

        System.out.println(queryBuilder.aggregateQueryBoolean(queryBuilder.clauseQueryMap));

    }



    private String aggregateQueryBoolean(final Map<BooleanClause.Occur, List<Query>> clauseQueryMap) {
        final BooleanQuery.Builder booleanQueryBuilder = new BooleanQuery.Builder();
        clauseQueryMap.forEach((booleanClause, queryList) -> queryList.forEach((query) -> booleanQueryBuilder.add(query, booleanClause)));
        return booleanQueryBuilder.build().toString();
    }

    private void addUpdateQueryMap(final Query query, final BooleanClause.Occur booleanOccur) {
        if (clauseQueryMap.containsKey(booleanOccur)) {
            clauseQueryMap.get(booleanOccur).add(query);
        } else {
            final List<Query> queryList = new ArrayList();
            queryList.add(query);
            clauseQueryMap.put(booleanOccur, queryList);
        }
    }
}