SpringBootElasticSearch 实现搜索建议 Suggester ,使用 ElasticsearchRestTemplate 方式

此篇文章分享 ElasticsearchRestTemplate 实现搜索建议

使用技术栈:SpringBoot 、Elastic Search 、 Kibana、Knife4j 接口文档

什么是搜索建议?

红色框的这个列表就是搜索建议

搜索建议也叫自动补全,我们输入查询时,基于部分输入动态提供可能的完整查询或相关建议的功能。

业务场景

搜索建议,建议什么呢? 我们以 mysql 的 title 字段作为搜索建议, 给 ES 库 suggest 字段的值。

解释前缀搜索建议:通过用户输入搜索词当作搜索前缀,匹配 ES 数据库所有的 suggest (搜索建议字段),成功匹配会返回一个 List<String> 集合。

这就是一个前缀搜索建议

      "suggest" : {
          "type" : "completion",
          "analyzer" : "simple",
          "preserve_separators" : true,
          "preserve_position_increments" : true,
          "max_input_length" : 50
        }

实现步骤

ES 要求:要实现搜索建议 Suggester,必须构造一个类型 completion 的字段索引,用来存搜索建议,用以下语法追加字段

PUT /post_v1/_mapping
{
  "properties": {
    "suggest": {
      "type": "completion"
    }
  }
}

1. 从 0 开始,新建 ES 索引

动 kibana,打开 dev tool 窗口

新建索引指令,不用过多关注 title 字段的 fields, 跟搜索建议无关

PUT post_v1
{
 "aliases": {
    "post": {}
  },
    "mappings": {
      "properties": {
        "favournum": {
          "type": "long"
        },
        "id": {
          "type": "long"
        },
        "isDelete": {
          "type": "keyword"
        },
        "tags": {
          "type": "keyword"
        },
        "thumbnum": {
          "type": "long"
        },
        "title": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          },
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart"
        },
        "suggest": {
          "type": "completion"
        }
      }
    }
  }

2. 同步数据到 ES

ES 索引目前是空的,把 MySQL 的数据同步到 ES ,使用 logstash ,编写配置文件 mytask.conf

根据配置文件,你需要提供一个 mysql 的 jar 包,才能正常运行 logstash, 本地 maven仓库里找一个就行

input {
  jdbc {
    jdbc_driver_library => "D:\software\ElasticStack\logstash-7.17.23\config\mysql-connector-java-8.0.29.jar(你本地的 mysql 依赖包)"
    jdbc_driver_class => "com.mysql.cj.jdbc.Driver"
    jdbc_connection_string => "jdbc:mysql://localhost:3306/my_db"
    jdbc_user => "你的mysql数据库账号"
    jdbc_password => "你的mysql数据库密码"
    statement => "SELECT * from post"
    parameters => { "favorite_artist" => "Beethoven" }
    schedule => "*/5 * * * * *" # 每五秒执行一次
    jdbc_default_timezone => "Asia/Shanghai"
    plugin_timezone => "local"
  }
}
filter {
if [title] and [title] != "" {
mutate {
add_field => {
"[suggest][input]" => "%{title}"
}
}
}
  }



output {
  stdout { codec => rubydebug }
  elasticsearch {
    hosts => "http://localhost:9200"  
    index => "post_v1"
    document_id => "%{id}"
    doc_as_upsert => true
  }
  }

运行 logstash , 在自己的 logstash 文件路径输出cmd,打开黑窗口,运行

bin> logstash.bat -f ..\config\mytask.conf

同步成功!ES 查询

3. ElasticsearchRestTemplate 实现搜索建议

引入依赖

<!-- elasticsearch-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

封装请求参数类

 封装响应类

写一个 SearchSuggestController, 用 ElasticsearchRestTemplate 实现搜索建议,根据输入的搜索词作为前缀匹配 ES 的 suggest 字段。匹配整个 post_v1 的 suggest, 所以返回 List<String>

ps:这里用到了自己封装的响应包装类 BaseResponse ,不用也一样

import org.springframework.data.elasticsearch.core.suggest.response.Suggest;

@RestController()
@RequestMapping("/search")
@Slf4j
public class SearchSuggestController {

    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @PostMapping("/suggest")
    public BaseResponse<SearchSuggestVO> searchAll(@RequestBody SearchRequest searchRequest, HttpServletRequest request) {
        String searchText = searchRequest.getSearchText();
        // 构造建议
        SuggestBuilder suggestBuilder = new SuggestBuilder()
        // "post-suggest" 是自定义搜索建议名称
        .addSuggestion("post-suggest", SuggestBuilders.completionSuggestion("suggest")
                       .prefix(searchText));
        // 构造查询
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
        .withSuggestBuilder(suggestBuilder)
        .build();
        SearchHits<PostEsDTO> searchHits = elasticsearchRestTemplate.search(searchQuery, PostEsDTO.class);
        // 提取搜索建议
        Suggest suggest = searchHits.getSuggest();
        List<String> suggestions = new ArrayList<>();
        if (suggest != null) {
            Suggest.Suggestion<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> postSuggest = suggest.getSuggestion("post-suggest");
            if (postSuggest != null) {
                for (Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option> entry : postSuggest.getEntries()) {
                    for (Suggest.Suggestion.Entry.Option option : entry.getOptions()) {
                        suggestions.add(option.getText()); // 添加每个建议结果到列表
                    }
                }
            }
        }
        SearchSuggestVO searchSuggestVO = new SearchSuggestVO();
        searchSuggestVO.setSuggestions(suggestions);
        return ResultUtils.success(searchSuggestVO);
    }

Knif4j 测试接口

响应了搜索建议,完成!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值