• ElasticSearch Suggest Completion 智能补全技术 整合SpringBoot+Vue实现


    效果演示视频和教学讲解视频地址:演示地址

    1.首先在Kibana中创建索引和类型。

    PUT /campus_market
    {
      "mappings": {
        "product" : {
          "properties" : {
            "name" : {
              "type": "text",
              "analyzer": "ik_max_word",
              "fields": {
                "suggest" : {
                  "type" : "completion",
                  "analyzer": "ik_max_word"
                }
              }
            },
            "info": {
              "type": "text",
              "analyzer": "ik_max_word"
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2.然后在Kibana中导入文档数据,或者在SpringBoot中项目导出也是可以。本人是采取后者的做法,创建一个定时任务,定时从MySQL中取出数据然后更新ES中的数据。

     @Scheduled(cron = "*/20 * * * * ?") //20s执行一次
    //    @Scheduled(cron = "0 */10 * * * ?") //10分钟执行一次
        private void configureESTasks() {
            logger.info("开始更新ES中数据....");
            ResponseDTO<List<ProductDTO>> productDTOList = productService.getProductList(new ProductDTO());
            List<Product> productList = CopyUtil.copyList(productDTOList.getData(), Product.class);
            List<Product> allProductList = productMapper.selectByExample(new ProductExample());
            //先清空ElasticSearch中的数据
            for(Product product : allProductList) {
                productRepository.delete(product);
            }
            //从数据库中查询出数据添加到ES中
            for(Product product : productList){
                productRepository.save(product);
            }
            logger.info("更新ES中数据完成....");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    写定时任务之前,别忘了先给对应实体类创建Repository接口并且要在配置文件中进行相应配置
    Repository接口

    public interface ProductRepository extends ElasticsearchRepository<Product,String> {
    
    }
    
    • 1
    • 2
    • 3

    config配置文件配置

    @Configuration
    public class ESRestClientConfig extends AbstractElasticsearchConfiguration {
    
        @Override
        @Bean
        public RestHighLevelClient elasticsearchClient() {
            final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                    .connectedTo("127.0.0.1:9200")
                    .build();
            return RestClients.create(clientConfiguration).rest();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.接下来就是正戏了,写业务逻辑层代码!!!进行SuggestBuilder创建,然后获取查询出来的结果(代码中的keyword就是查询匹配的结果内容),返回给前端。

    
        @Qualifier("elasticsearchClient")
        @Autowired
        private RestHighLevelClient restHighLevelClient;
    
      /**
         * 智能匹配搜索
         * @param productDTO
         * @return
         */
        @Override
        public ResponseDTO<List<String>> suggestCompletionProduct(ProductDTO productDTO) {
            List<String> resultList = new ArrayList<>();
            CompletionSuggestionBuilder suggestion = SuggestBuilders
                    .completionSuggestion("name.suggest").prefix(productDTO.getName()).skipDuplicates(true);
            SuggestBuilder suggestBuilder = new SuggestBuilder();
            suggestBuilder.addSuggestion("product", suggestion);
    
    
            SearchRequest searchRequest = new SearchRequest();
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.suggest(suggestBuilder);
            searchRequest.indices("campus_market").types("product").source(searchSourceBuilder);
            try {
                SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                Suggest suggest = response.getSuggest();
                //SearchResponse response = elasticsearchRestTemplate.suggest(suggestBuilder, Product.class);
                int maxSuggestNum = 0; // 最多5个
                if (suggest != null) {
                    List<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> entries
                            = suggest.getSuggestion("product").getEntries();
                    for (Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option> entry : entries) {
                        for (Suggest.Suggestion.Entry.Option option : entry.getOptions()) {
                            String keyword = option.getText().string();
                            if (maxSuggestNum < 5) {
                                resultList.add(keyword);
                                maxSuggestNum++;
                            } else {
                                break;
                            }
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                return ResponseDTO.errorByMsg(CodeMsg.SYSTEM_ERROR);
            }
    
            return ResponseDTO.success(resultList);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    4.前端Vue要对用户输入的内容进行监听,然后调用接口获取数据。

     <div class="search-input">
    	<el-input v-model="searchName" placeholder="搜一搜好货" @input="changeInput" clearable>
    	     <el-select v-model="searchCategoryId" slot="prepend">
    	         <el-option label="全部类目" value="0">el-option>
    	         <el-option v-for="(item, index) in categoryList" :key="index" :label="item.name" :value="item.id">el-option>
    	     el-select>
    	 el-input>
    	 <div class="suggest-content">
    	     <div class="suggest-content-item" @click="toProductDetail(item.id)" v-for="(item, index) in suggestList" :key="index">
    	         {{item.name}}
    	     div>
    	 div>
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
     changeInput(e) {
         let _this = this;
         // 函数节流,防止数据频繁更新,每300毫秒才搜索一次
         if (!this.timer) {
             this.timer = setTimeout(function(){
                 _this.getSuggestList(e);
                 _this.timer = null;
             },300)
         }
     },
     getSuggestList(e) {
          let _this = this;
          this.$ajax.post(process.env.VUE_APP_SERVER + "/product/suggest", {name: e}).then((response)=>{
              let resp = response.data;
              let resultList = [];
              if(resp.code === 0){
                  let data = resp.data;
                  _this.productList.forEach(item => {
                     data.forEach(name => {
                         if(item.name === name) {
                             let val = {
                                 id: item.id,
                                 name: item.name
                             };
                             resultList.push(val);
                         }
                     })
                  });
              }
              _this.suggestList = resultList;
          });
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
     .suggest-content {
         position: absolute;
         background: #fff;
         width: 480px;
         margin-left: 110px;
         border: 1px solid #444444;
         z-index: 1;
         height: auto;
         max-height: 300px;
         overflow-y: auto;
         display: block;
     }
    
     .suggest-content-item {
         width: 98%;
         margin: 5px 5px;
         cursor: pointer;
     }
    
      .search-input .el-select {
          width: 110px;
      }
    
      .search-input {
          width: 590px;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
  • 相关阅读:
    web前端网页制作课作业:甜甜圈蛋糕店(HTML+CSS+JavaScript)
    基于 xml 配置文件的入门级 SSM 框架整合
    华为云云耀云服务器L实例评测|基于L实例使用Docker部署MySQL服务并连接MySQL—phpMyAdmin管理工具
    通关GO语言13 参数传递:值、引用及指针之间的区别?
    【Java八股文总结】之JDK常见问题排查
    警用移动执法远程视频监控方案:安防视频监控系统EasyCVR+4G/5G移动执法仪
    中国BI步入增长大周期,腾讯云ChatBI加速AI+BI融合
    Vue的路由
    IB音乐课难不难?
    java综合布线设备管理系统的研究与实现
  • 原文地址:https://blog.csdn.net/dgfdhgghd/article/details/126571996