ElasticSearch7.8.0集成Springboot

本文ES版本为7.8.0 兼容很多新版本,代码都经过测试, 无坑, 大家放心食用


1. 准备环境工作

安装ES环境, 安装IK分词器,见博文: https://rourou.blog.csdn.net/article/details/101061408

 

2.MAVEN依赖

由于es各个版本变化很大,所以在选择依赖的时候要尤为注意!!!我们可以通过spring的官方网站来进行查询版本对应的信息

https://docs.spring.io/spring-data/elasticsearch/docs/4.0.2.RELEASE/reference/html/#new-features

ElasticSearch7.8.0集成Springboot_第1张图片

大家可以看到最新的官方文档更新到了7.6.2, 但是我们的版本是7.8.0,不过这个版本也是可以放心食用的.

我们一般使用spring的时候都用starter这边我们直接引入依赖


    org.springframework.boot
    spring-boot-starter-data-elasticsearch
    2.4.0-SNAPSHOT

3.在配置文件yml里添加es的基本配置

spring:
  elasticsearch:
    rest:
      uris: 47.114.142.39:9200
      read-timeout: 30s
      connection-timeout: 5s

无需单独写配置文件: 因为starter会帮我们自动依赖

4. 编写Index实体类(Index)

我们利用注解即可完成Index的创建, 和传统的json配置文件相比更加直观

package com.gupao.springbootdemo.bean;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

import java.util.List;

/**
 * 功能描述:ES的用户
 *
 * @Author: zhouzhou
 * @Date: 2020/7/30$ 9:57$
 */
@Data
@Document(indexName = "es_user")
public class ESUser {

    @Id
    private Long id;
    @Field(type = FieldType.Text)
    private String name;
    @Field(type = FieldType.Integer)
    private Integer age;
    @Field(type = FieldType.Keyword)
    private List tags;
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String desc;


}

注解的含义我简单介绍下:

@Document代表定义这个是文档, 其中indexName就是索引库的名字必须标注

@Id是标识文档的唯一id

@Field 就是字段了, 其中type为KeyWord代表这个字段不分词, analyzer是存数据的时候用的分词器

具体的含义和其他的注解请看官方文档

https://docs.spring.io/spring-data/elasticsearch/docs/4.0.2.RELEASE/reference/html/#elasticsearch.mapping

ElasticSearch7.8.0集成Springboot_第2张图片

5.编写Repository类

这是一个接口类, 类似我们的mybatis,其中有save方法(低版本应该是index方法),平时大多数常用的curd操作都可以用这个类来进行

支持编写派生方法!

package com.gupao.springbootdemo.repository;

import com.gupao.springbootdemo.bean.ESUser;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.List;

/**
 * 功能描述:
 *
 * @Author: zhouzhou
 * @Date: 2020/7/30$ 14:17$
 */
public interface EsUserRepository extends ElasticsearchRepository {

    long deleteESUserByName(String name);

    List queryESUserByName(String name);
}

6.常用API展示

本demo包括:

  1. 索引的创建和删除
  2. 文档的导入与更新
  3. 文档的高级搜索,多条件, 分页, 排序, 高亮
package com.gupao.springbootdemo.controller;

import com.gupao.springbootdemo.bean.ESUser;
import com.gupao.springbootdemo.repository.EsUserRepository;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * 功能描述:
 *
 * @Author: zhouzhou
 * @Date: 2020/7/30$ 14:35$
 */
@Api(tags = "es用户测试")
@RestController
@RequestMapping("/es/user")
public class EsUserController {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    private EsUserRepository esUserRepository;

    @RequestMapping(value = "/create-index", method = RequestMethod.POST)
    @ApiOperation("创建索引")
    public Object createEsIndex() {
        boolean index = elasticsearchRestTemplate.createIndex(ESUser.class);
        elasticsearchRestTemplate.putMapping(ESUser.class);

        System.out.println("创建索引结果是" + index);
        return index;
    }

    @RequestMapping(value = "/delete-index", method = RequestMethod.POST)
    @ApiOperation("删除索引")
    public Object deleteEsIndex() {
        boolean deleteIndex = elasticsearchRestTemplate.deleteIndex(ESUser.class);
        System.out.println("删除索引结果是" + deleteIndex);
        return deleteIndex;
    }

    @RequestMapping(value = "/exist-index", method = RequestMethod.POST)
    @ApiOperation("是否存在索引")
    public Object existEsIndex() {
        boolean existsIndex = elasticsearchRestTemplate.indexExists(ESUser.class);
        System.out.println("是否存在的结果是" + existsIndex);
        return existsIndex;
    }

    @RequestMapping(value = "/save-doc", method = RequestMethod.POST)
    @ApiOperation("保存文档")
    public ESUser saveEsDoc(@RequestBody ESUser esUser) {
        ESUser result = esUserRepository.index(esUser);
        return result;
    }

    @RequestMapping(value = "/query-doc", method = RequestMethod.GET)
    @ApiOperation("根据名字查询文档")
    public List queryByName(String name) {
        List result = esUserRepository.queryESUserByName(name);
        return result;
    }

    @RequestMapping(value = "/exist-doc", method = RequestMethod.GET)
    @ApiOperation("根据id查询文档")
    public Object existDoc(Long id) {
        return esUserRepository.existsById(id);
    }


  //---------------- 复杂查询 ------------------
    @RequestMapping(value = "/query-doc/complex", method = RequestMethod.POST)
    @ApiOperation("根据名字查询文档")
    public Object queryByName(@RequestBody ESUser esUser) {
        String desc = esUser.getDesc();
        List tags = esUser.getTags();
        String name = esUser.getName();
        // 先构建查询条件
        BoolQueryBuilder defaultQueryBuilder = QueryBuilders.boolQuery();
        if (StringUtils.isNotBlank(desc)){
            defaultQueryBuilder.should(QueryBuilders.termQuery("desc", desc));
        }
        if (StringUtils.isNotBlank(name)){
            defaultQueryBuilder.should(QueryBuilders.termQuery("name", name));
        }
        if (!CollectionUtils.isEmpty(tags)){
            for (String tag : tags) {
                defaultQueryBuilder.must(QueryBuilders.termQuery("tags", tag));
            }
        }

        // 分页条件
        PageRequest pageRequest = PageRequest.of(0,10);
        // 高亮条件
        HighlightBuilder highlightBuilder = getHighlightBuilder("desc", "tags");
        // 排序条件
        FieldSortBuilder sortBuilder = SortBuilders.fieldSort("age").order(SortOrder.DESC);
        //组装条件
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(defaultQueryBuilder)
                .withHighlightBuilder(highlightBuilder)
                .withPageable(pageRequest)
                .withSort(sortBuilder).build();

        SearchHits searchHits = elasticsearchRestTemplate.search(searchQuery, ESUser.class);
        
        // 高亮字段映射
        List userVoList = Lists.newArrayList();
        for (SearchHit searchHit : searchHits) {
            ESUser content = searchHit.getContent();
            ESUserVo esUserVo = new ESUserVo();
            BeanUtils.copyProperties(content,esUserVo);
            Map> highlightFields = searchHit.getHighlightFields();
            for (String highlightField : highlightFields.keySet()) {
                if (StringUtils.equals(highlightField,"tags")){
                    esUserVo.setTags(highlightFields.get(highlightField));
                }else if(StringUtils.equals(highlightField,"desc")){
                    esUserVo.setDesc(highlightFields.get(highlightField).get(0));
                }

            }
            userVoList.add(esUserVo);
        }
        
        // 组装分页对象
        Page userPage = new PageImpl<>(userVoList,pageRequest,searchHits.getTotalHits());

        return userPage;



    }



    // 设置高亮字段
    private HighlightBuilder getHighlightBuilder(String... fields) {
        // 高亮条件
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器
        for (String field : fields) {
            highlightBuilder.field(field);//高亮查询字段
        }
        highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags("");   //高亮设置
        highlightBuilder.postTags("");
        //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片数
        highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段

        return highlightBuilder;
    }


}

7. 通过swagger文档进行复杂查询测试

搜索条件如下: 

ElasticSearch7.8.0集成Springboot_第3张图片

搜索结果如下: 分页信息和高亮都展示出来了


{
  "content": [
    {
      "id": 7,
      "name": "李8",
      "age": 19,
      "tags": [
        "Java",
        "Python"
      ],
      "desc": "精通Java,Python的能力,爱好吃西瓜"
    },
    {
      "id": 8,
      "name": "李9",
      "age": 19,
      "tags": [
        "Java",
        "Python"
      ],
      "desc": "精通Java,Python的能力,爱好吃西瓜"
    },
    {
      "id": 1,
      "name": "张三",
      "age": 18,
      "tags": [
        "Java",
        "Python"
      ],
      "desc": "精通Java,Linux,Python的能力,爱好吃瓜"
    }
  ],
  "pageable": {
    "sort": {
      "sorted": false,
      "unsorted": true,
      "empty": true
    },
    "offset": 0,
    "pageNumber": 0,
    "pageSize": 10,
    "paged": true,
    "unpaged": false
  },
  "last": true,
  "totalElements": 3,
  "totalPages": 1,
  "number": 0,
  "size": 10,
  "sort": {
    "sorted": false,
    "unsorted": true,
    "empty": true
  },
  "numberOfElements": 3,
  "first": true,
  "empty": false
}

 

你可能感兴趣的:(ElasticSearch)