谷粒商城-高级-39 全文检索 Elasticsearch-Springboot 整合

一、Springboot整合

Elasticsearch-Rest-Client:官方RestClient,封装了 ES 操作,API层次分明,上手简单
最终选择:Elasticsearch-Rest-Client

Java REST Client

创建ES微服务

在我们当前项目,创建一个用于搜索的微服务:gulimall-search
file

选择依赖包:
file

创建好搜索服务后,导入 ES依赖包

gulimall-search/pom.xml导入ES包:

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.4.2</version>
</dependency>

导入之后可以看到相关的依赖版本:
file

为什么我们这里安装的是 6.4版本呢?
可以看一下我们springboot默认的版本依赖:spring-boot-dependencies/2.1.16.RELEASE/spring-boot-dependencies-2.1.16.RELEASE.pom

file

所以,我们要把系统自带的版本覆盖掉,修改 gulimall-search/pom.xml

<properties>
    <java.version>1.8</java.version>
    <!-- 覆盖掉springboot默认自带的6.4版本 -->
    <elasticsearch.version>7.4.2</elasticsearch.version>
  </properties>

然后再刷新Maven依赖包,可以看到系统自带的依赖包已经被替换了,统一换为:es:7.4.2 版本了:
file

配置注册中心

然后再导入项目的 gulimall-common
gulimall-search/pom.xml

<dependency>
      <groupId>com.atguigu.gulimall</groupId>
      <artifactId>gulimall-common</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>

gulimall-search/pom.xml 完整文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.16.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.atguigu.gulimall</groupId>
  <artifactId>gulimall-search</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>gulimall-search</name>
  <description>ElasticSearch检索服务</description>

  <properties>
    <java.version>1.8</java.version>
    <!-- 覆盖掉springboot默认自带的6.4版本 -->
    <elasticsearch.version>7.4.2</elasticsearch.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- 导入es的rest-high-level-client -->
    <dependency>
      <groupId>org.elasticsearch.client</groupId>
      <artifactId>elasticsearch-rest-high-level-client</artifactId>
      <version>7.4.2</version>
    </dependency>

    <dependency>
      <groupId>com.atguigu.gulimall</groupId>
      <artifactId>gulimall-common</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

</project>

创建 gulimall-search/src/main/resources/application.yml

spring:
  #  配置nacos注册中心
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  application:
    name: gulimall-search
server:
  port: 40000

启动类添加注册发现功能:
com/atguigu/gulimall/search/GulimallSearchApplication.java

package com.atguigu.gulimall.search;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient // 添加注册发现功能
@SpringBootApplication
public class GulimallSearchApplication {

  public static void main(String[] args) {
    SpringApplication.run(GulimallSearchApplication.class, args);
  }

}

二、创建配置文件

创建配置文件 gulimall/search/config/GulimallElasticSearchConfig.java

package com.atguigu.gulimall.search.config;

import com.sun.codemodel.internal.JDocComment;
import com.sun.codemodel.internal.JDocCommentable;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * ES配置
 *
 * @author: kaiyi
 * @create: 2020-08-25 11:09
 *
 * 步骤:
 * 1、导入依赖
 * 2、编写配置,给容器中注入一个RestHighLevelClient
 * 3、引入RequestOptions常量
 */
@Configuration
public class GulimallElasticSearchConfig {

// see doc https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.9/java-rest-low-usage-requests.html#java-rest-low-usage-request-options
  public static final RequestOptions COMMON_OPTIONS;
  static {
    RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
//    builder.addHeader("Authorization", "Bearer " + TOKEN);
//    builder.setHttpAsyncResponseConsumerFactory(
//        new HttpAsyncResponseConsumerFactory
//            .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024));
    COMMON_OPTIONS = builder.build();
  }

  @Bean
  public RestHighLevelClient esRestClient(){
    // see offical doc
    // https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.x/java-rest-high-getting-started-initialization.html

    RestHighLevelClient client = new RestHighLevelClient(
        RestClient.builder(
            new HttpHost("192.168.10.10", 9200, "http")));

    return client;
  }

}

单元测试是否连接ES服务成功:

package com.atguigu.gulimall.search;

import org.elasticsearch.client.RestHighLevelClient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class GulimallSearchApplicationTests {

  @Autowired
  private RestHighLevelClient client;

  @Test
  public void contextLoads() {

    System.out.println(client);
  }

}

将上架的商品加入到ES中,业务核心代码:
atguigu/gulimall/search/service/impl/ProductSaveServiceImpl.java

package com.atguigu.gulimall.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.common.to.es.SkuEsModel;
import com.atguigu.gulimall.search.config.GulimallElasticSearchConfig;
import com.atguigu.gulimall.search.constant.EsConstant;
import com.atguigu.gulimall.search.service.ProductSaveService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author: kaiyi
 * @create: 2020-08-27 16:01
 */
@Slf4j
@Service("productSaveService")
public class ProductSaveServiceImpl implements ProductSaveService {

  @Autowired
  RestHighLevelClient restHighLevelClient;

  @Override
  public Boolean prudoctStatusUp(List<SkuEsModel> skuEsModels) throws IOException {

    //保存到es
    // 1、给es中建立索引。product,建立好映射关系

    // 2、给es中保存这些数据
    // BulkRequest bulkRequest; RequestOptions options;
    BulkRequest bulkRequest = new BulkRequest();
    for(SkuEsModel model: skuEsModels){
      // 构造保存请求
      IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX);
      indexRequest.id(model.getSkuId().toString());
      String s = JSON.toJSONString(model);  // 转为json
      indexRequest.source(s, XContentType.JSON);

      bulkRequest.add(indexRequest);
    }

   BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);

   // TODO::如果批量错误
    boolean b = bulk.hasFailures();
    List<String> collect = Arrays.stream(bulk.getItems()).map(item ->{
      return item.getId();
    }).collect(Collectors.toList());

    log.error("商品上架成功:{}", collect);

    log.error("商品上架成功:{}", collect);

    return b;

  }
}

为者常成,行者常至