首页 > 解决方案 > 为多个字段构建 Lucene 查询

问题描述

我有一个具有搜索功能的 Spring MVC 应用程序。

流程:UI > CONTROLLER > BL > DATA > SOLR

允许用户使用多个字段搜索某些内容,例如按名称或部门搜索。业务层需要有一个 Lucene Query Builder,它接受字符串并为 SOLR 构建适当的 Lucene 查询。

我的控制器:

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

虚拟查询生成器

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

现在这个虚拟查询构建器不支持通配符或任何其他变体。我正在浏览 Apache Lucene Query API(也将 lucene core-7.7.1 添加到项目中)和一堆教授如何使用不同类型的查询实现(TermQuery、PhraseQuery、BooleanQuery 等)的文章,但它没有完全有道理。最后,我仍在手动构建查询。

有人可以通过展示我如何拥有一个正确的 Lucene 查询生成器类来帮忙吗?

我需要使用精确的短语和通配符为这些类型的文本生成查询

(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

组合查询:

nm:"Ohio State University" AND dpt:"Computer Science"

标签: javalucene

解决方案


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

推荐阅读