Spring Boot 2.0 整合 ES 5 文章内容搜索实战

本章内容
文章内容搜索思路
搜索内容分词
搜索查询语句
筛选条件
分页、排序条件
小结html

1、文章内容搜索思路
上一篇讲了在怎么在 Spring Boot 2.0 上整合 ES 5 ,这一篇聊聊具体实战。简单讲下如何实现文章、问答这些内容搜索的具体实现。实现思路很简单:git

基于「短语匹配」并设置最小匹配权重值
哪来的短语,利用 IK 分词器分词
基于 Fiter 实现筛选
基于 Pageable 实现分页排序
这里直接调用搜索的话,容易搜出不尽人意的东西。由于内容搜索关注内容的链接性。因此这里处理方法比较 low ,但愿多交流一块儿实现更好的搜索方法。就是经过分词获得不少短语,而后利用短语进行短语精准匹配。github

ES 安装 IK 分词器插件很简单。第一步,在下载对应版本 https://github.com/medcl/elasticsearch-analysis-ik/releases。第二步,在 elasticsearch-5.5.3/plugins 目录下,新建一个文件夹 ik,把 elasticsearch-analysis-ik-5.5.3.zip 解压后的文件拷贝到 elasticsearch-5.1.1/plugins/ik 目录下。最后重启 ES 便可。spring

2、搜索内容分词elasticsearch

安装好 IK ,如何调用呢?优化

第一步,我这边搜搜内容会以 逗号 拼接传入。因此会先将逗号分割ui

第二步,在搜索词中加入本身自己,由于有些词通过 ik 分词后就没了... 这是个 bugthis

第三步,利用 AnalyzeRequestBuilder 对象获取 IK 分词后的返回值对象列表插件

第四步,优化分词结果,好比都为词,则保留所有;有词有字,则保留词;只有字,则保留字code

核心实现代码以下:

/**
     * 搜索内容分词
     */
    protected List<String>      handlingSearchContent(String searchContent) {
 
             List<String> searchTermResultList = new ArrayList<>();
             // 按逗号分割,获取搜索词列表
             List<String> searchTermList = Arrays.asList(searchContent.split(SearchConstant.STRING_TOKEN_SPLIT));
 
             // 若是搜索词大于 1 个字,则通过 IK 分词器获取分词结果列表
             searchTermList.forEach(searchTerm -> {
                 // 搜索词 TAG 自己加入搜索词列表,并解决 will 这种问题
                 searchTermResultList.add(searchTerm);
                 // 获取搜索词 IK 分词列表
                 searchTermResultList.addAll(getIkAnalyzeSearchTerms(searchTerm));
             });
 
             return searchTermResultList;
    }
 
    /**
     * 调用 ES 获取 IK 分词后结果
     */
    protected List<String>      getIkAnalyzeSearchTerms(String searchContent) {
             AnalyzeRequestBuilder ikRequest = new AnalyzeRequestBuilder(elasticsearchTemplate.getClient(),
                     AnalyzeAction.INSTANCE, SearchConstant.INDEX_NAME,      searchContent);
             ikRequest.setTokenizer(SearchConstant.TOKENIZER_IK_MAX);
             List<AnalyzeResponse.AnalyzeToken> ikTokenList =      ikRequest.execute().actionGet().getTokens();
 
             // 循环赋值
             List<String> searchTermList = new ArrayList<>();
             ikTokenList.forEach(ikToken -> {
                 searchTermList.add(ikToken.getTerm());
             });
 
             return handlingIkResultTerms(searchTermList);
    }
 
    /**
     * 若是分词结果:洗发水(洗发、发水、洗、发、水)
     * - 均为词,保留
     * - 词 + 字,只保留词
     * - 均为字,保留字
     */
    private List<String>      handlingIkResultTerms(List<String> searchTermList) {
             Boolean isPhrase = false;
             Boolean isWord = false;
             for (String term : searchTermList) {
                 if (term.length() > SearchConstant.SEARCH_TERM_LENGTH)      {
                     isPhrase = true;
                 } else {
                     isWord = true;
                 }
             }
 
             if (isWord & isPhrase) {
                 List<String> phraseList = new ArrayList<>();
                 searchTermList.forEach(term -> {
                     if (term.length() > SearchConstant.SEARCH_TERM_LENGTH)      {
                         phraseList.add(term);
                     }
                 });
                 return phraseList;
             }
 
             return searchTermList;
    }

3、搜索查询语句

构造内容枚举对象,罗列须要搜索的字段,ContentSearchTermEnum 代码以下:

import lombok.AllArgsConstructor;
 
@AllArgsConstructor
public enum ContentSearchTermEnum {
 
    // 标题
    TITLE("title"),
    // 内容
    CONTENT("content");
 
    /**
     * 搜索字段
     */
    private String      name;
 
    public String      getName() {
             return name;
    }
 
    public void      setName(String name) {
             this.name = name;
    }
 
}

循环进行「短语搜索匹配」搜索字段,而后并设置最低权重值为 1。核心代码以下:

相关文章
相关标签/搜索