欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

springboot整合Elasticsearch实现增删改查

程序员文章站 2022-10-03 10:50:02
springboot整合Elasticsearch实现增删改查,只看这一篇!...

平凡也就两个字: 懒和惰;
成功也就两个字: 苦和勤;
优秀也就两个字: 你和我。
跟着我从0学习JAVA、spring全家桶和linux运维等知识,带你从懵懂少年走向人生巅峰,迎娶白富美!
关注微信公众号【 IT特靠谱 】,每天都会分享技术心得~

 

springboot整合Elasticsearch实现增删改查

1 创建springboot项目

      创建的项目名称为:elasticsearch-demo

springboot整合Elasticsearch实现增删改查

      选择需要依赖的基础jar包。

springboot整合Elasticsearch实现增删改查

      创建成功后,项目结构如下图所示:

springboot整合Elasticsearch实现增删改查

 

2 添加springboot-elasticsearch依赖

    <!--添加springboot-elasticsearch依赖-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>

springboot整合Elasticsearch实现增删改查

 

3 调整springboot版本

3.1 为什么要调整springboot版本?

      由于之前的文章中,我们安装的是7.6.2版本的elasticsearch。而创建的springboot项目是2.4.0版本的,其默认依赖的是7.9.3版本的elasticsearch相关包。

      如果项目用到的es相关包版本与安装的es服务版本不一致,在实际使用es进行CRUD的时候就会出现一些版本导致的未知问题。因此,我们需要调整项目依赖的es版本或者调整springboot版本!

      恰好!springboot的2.3.0.RELEASE版本,默认依赖的就是7.6.2版本的es相关依赖包。那么我们调整springboot版本为2.3.0.RELEASE就达到目的了!

springboot整合Elasticsearch实现增删改查

springboot整合Elasticsearch实现增删改查

 

3.2 调整springboot版本

      将springboot版本调整为:2.3.0.RELEASE

springboot整合Elasticsearch实现增删改查

      自动下载完依赖后,查看依赖的es相关包版本:

springboot整合Elasticsearch实现增删改查

springboot整合Elasticsearch实现增删改查

      到此,项目组依赖的es相关包版本与es服务版本相同了!都为:7.6.2版本

 

4 编写代码

4.1 配置application.yml

#指定es服务访问url
spring:
  elasticsearch:
    rest:
      uris: http://localhost:9200

springboot整合Elasticsearch实现增删改查

 

4.2 创建实体类

      创建实体类:User.java

package com.test.elasticsearchdemo.entity;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

/**
 * 用户实体类
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "pms", type = "_doc") //es注解1。指定es索引名和类型。es8版本中会废弃掉type类型(实际上默认的type为"_doc")。
public class User implements Serializable {

  /**
   * 数据id Id注解:指明pms索引_doc类型中的文档的id为数据的id。如果insert到es中的数据的id值为空,那么es会自动生成一个唯一的uuid作为文档id
   */
  @Id
  private Long id;

  /**
   * 用户名 Text:其取代了string,当一个字段是要被全文搜索的,比如Email内容、产品描述,应该使用text类型。 设置text类型以后,字段内容会被分词,在生成倒排索引以前,字符串会被分词器分成一个个词项。text类型的字段不用于排序,很少用于聚合(termsAggregation除外)。
   * ik_max_word:指示了该字段使用到的分词算法,为:最细粒度分词
   */
  @Field(analyzer = "ik_max_word", type = FieldType.Text)
  private String name;

  /**
   * 用户密码 注意:password字段添加@Transient注解,也就意味着该字段不会被写入es中!
   */
  @Transient
  private String password;

  /**
   * 用户手机号 Keyword:关键词。该类型字段只能通过"精确查找"方式索引到,不会对该字段分词后与查询条件匹配
   */
  @Field(type = FieldType.Keyword)
  private String mobile;

  /**
   * 用户年龄 Integer:整数类型
   */
  @Field(type = FieldType.Integer)
  private Integer age;

  /**
   * 用户生日 Date:日期类型
   */
  @Field(type = FieldType.Date)
  private Date birthday;

  /**
   * 删除标识 Boolean:bool类型
   */
  @Field(type = FieldType.Boolean)
  private Boolean deleteStatus;

  /**
   * 用户标签 Nested:嵌套类型
   */
  @Field(type = FieldType.Nested)
  private List<Label> labels;

  @Data
  @Builder
  @AllArgsConstructor
  @NoArgsConstructor
  public static class Label implements Serializable {

    /**
     * 标签id
     */
    @Field(type = FieldType.Long)
    private Long id;

    /**
     * 标签编码
     */
    @Field(type = FieldType.Keyword)
    private String labelCode;

    /**
     * 标签名称
     */
    @Field(type = FieldType.Keyword)
    private String labelName;

    /**
     * 标签名称 注意:该字段不会被写入es中!
     */
    @Transient
    private String labelDesc;
  }
}

 

4.3 自定义ElasticsearchRepository

      创建自定义es仓库接口:EsUserRepository.java,继承ElasticsearchRepository.java接口。

      ElasticsearchRepository及其父接口封装了一些常用的CRUD方法。因此我们只需要继承该接口,就可以进行简单的增删改查操作了。当然如果希望实现更复杂的查询操作,就需要搭配RestHighLevelClient客户端来使用!

package com.test.elasticsearchdemo.repository;

import com.test.elasticsearchdemo.entity.User;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

/**
 * ES用户repository
 */
public interface EsUserRepository extends ElasticsearchRepository<User, Long> {

  /**
   * 根据名称查询
   */
  List<User> findByName(String name);

  /**
   * 分页搜索查询:分页查询名称或手机号相同的信息
   */
  Page<User> findByNameOrMobile(String name, String mobile, Pageable page);
}

 

4.4 创建service接口类

      创建service接口类:UserService.java

package com.test.elasticsearchdemo.service;

import com.test.elasticsearchdemo.dto.request.PageByNameOrMobileRequest;
import com.test.elasticsearchdemo.entity.User;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

/**
 * 用户service接口类
 */
public interface UserService {

  /**
   * 保存一条数据
   */
  void insert(User user);

  /**
   * 批量保存数据
   */
  void insertBatch(List<User> users);

  /**
   * 更新一条数据
   */
  void update(User user);

  /**
   * 删除一条数据
   * @param id 删除数据文档id(文档id与数据id相同)
   */
  void deleteById(Long id);

  /**
   * 根据名称查询
   */
  List<User> listByName(String name);

  /**
   * 根据id查询唯一数据
   */
  User findById(Long id);

  /**
   * 分页搜索查询:分页查询名称或手机号相同的信息
   */
  Page<User> findByNameOrMobile(PageByNameOrMobileRequest request);

  /**
   * 分页搜索查询:分页查询名称或手机号相同的信息,并按age升序排序
   */
  Page<User> pageByConditions(PageByNameOrMobileRequest request);
}

 

4.5 创建service接口实现类

      创建service接口实现类:UserServiceImpl.java

package com.test.elasticsearchdemo.service.impl;

import com.test.elasticsearchdemo.dto.request.PageByNameOrMobileRequest;
import com.test.elasticsearchdemo.entity.User;
import com.test.elasticsearchdemo.repository.EsUserRepository;
import com.test.elasticsearchdemo.service.UserService;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
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.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

/**
 * 用户接口实现类
 */
@Service
public class UserServiceImpl implements UserService {

  /**
   * 一般CRUD查询用这个!spring-data风格
   */
  @Autowired
  private EsUserRepository esUserRepository;

  /**
   * es复杂操作用这个!底层用的是RestHighLevelClient客户端
   */
  @Autowired
  private ElasticsearchRestTemplate elasticsearchRestTemplate;

  /***********************EsUserRepository新增、更新和删除***********************/
  /**
   * 新增一条数据
   */
  @Override
  public void insert(User user) {
    esUserRepository.save(user);
  }

  /**
   * 批量保存数据
   */
  @Override
  public void insertBatch(List<User> users) {
    esUserRepository.saveAll(users);
  }

  /**
   * 更新一条数据 说明:如果es数据库中存在相同id的数据,那么就是更新数据!否则就是新增数据。
   */
  @Override
  public void update(User user) {
    esUserRepository.save(user);
  }

  /**
   * 删除一条数据
   *
   * @param id 删除数据文档id(文档id与数据id相同)
   */
  @Override
  public void deleteById(Long id) {
    esUserRepository.deleteById(id);
  }

  /***********************EsUserRepository普通查询***********************/
  /**
   * 根据名称查询
   */
  @Override
  public List<User> listByName(String name) {
    return esUserRepository.findByName(name);
  }

  /**
   * 根据id查询唯一数据
   */
  @Override
  public User findById(Long id) {
    Optional<User> optional = esUserRepository.findById(id);
    return optional.orElse(null);
  }

  /**
   * 分页搜索查询:分页查询名称或手机号相同的信息
   */
  @Override
  public Page<User> findByNameOrMobile(PageByNameOrMobileRequest request) {
    Pageable pageable = PageRequest.of(request.getPage()-1, request.getSize());
    return esUserRepository.findByNameOrMobile(request.getName(), request.getMobile(), pageable);
  }

  /***********************RestHighLevelClient高级查询***********************/
  @Override
  public Page<User> pageByConditions(PageByNameOrMobileRequest request) {
    //构建查询条件
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    //1.排序
    nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("age").order(SortOrder.ASC));
    //2.分页
    Pageable pageable = PageRequest.of(request.getPage() - 1, request.getSize());
    nativeSearchQueryBuilder.withPageable(pageable);
    //3.过滤
    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    boolQueryBuilder.must(QueryBuilders.termQuery("deleteStatus", false));
    nativeSearchQueryBuilder.withFilter(boolQueryBuilder);
    //4.搜索条件
    if (StringUtils.isEmpty(request.getMobile()) && StringUtils.isEmpty(request.getName())) {
      nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
    } else {
      List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
      if (!StringUtils.isEmpty(request.getMobile())) {
        filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("mobile", request.getMobile()),
            ScoreFunctionBuilders.weightFactorFunction(10)));
      }
      if (!StringUtils.isEmpty(request.getName())) {
        filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("name", request.getName()),
            ScoreFunctionBuilders.weightFactorFunction(7)));
      }
      FunctionScoreQueryBuilder.FilterFunctionBuilder[] builders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[filterFunctionBuilders.size()];
      filterFunctionBuilders.toArray(builders);
      FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(builders)
          .scoreMode(FunctionScoreQuery.ScoreMode.SUM)
          .setMinScore(3);
      nativeSearchQueryBuilder.withQuery(functionScoreQueryBuilder);
    }
    NativeSearchQuery query = nativeSearchQueryBuilder.build();
    SearchHits<User> searchHits = elasticsearchRestTemplate.search(query, User.class);
    if (searchHits.getTotalHits() <= 0) {
      return new PageImpl<>(null, pageable, 0);
    }
    List<User> userList = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());
    return new PageImpl<>(userList, pageable, searchHits.getTotalHits());
  }
}

 

4.6 创建controller控制器类

      创建控制器类:UserController.java

package com.test.elasticsearchdemo.controller;

import com.test.elasticsearchdemo.dto.request.PageByNameOrMobileRequest;
import com.test.elasticsearchdemo.entity.User;
import com.test.elasticsearchdemo.service.UserService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 用户api接口控制器
 */
@RestController
@RequestMapping(value = "/user")
public class UserController {

  @Autowired
  private UserService userService;

  /***********************EsUserRepository新增、更新和删除***********************/
  /**
   * 保存一条数据
   */
  @PostMapping("insert")
  public void insert(@RequestBody User user) {
    userService.insert(user);
  }

  /**
   * 批量保存数据
   */
  @PostMapping("insertBatch")
  public void insertBatch(@RequestBody List<User> users) {
    userService.insertBatch(users);
  }

  /**
   * 更新一条数据
   */
  @PostMapping("update")
  public void update(@RequestBody User user) {
    userService.update(user);
  }

  /**
   * 删除一条数据
   */
  @GetMapping("deleteById")
  public void deleteById(Long id) {
    userService.deleteById(id);
  }

  /***********************EsUserRepository普通查询***********************/
  /**
   * 根据名称查询
   */
  @GetMapping("listByName")
  public List<User> listByName(String name) {
    return userService.listByName(name);
  }

  /**
   * 根据id查询唯一数据
   */
  @GetMapping("findById")
  public User findById(Long id) {
    return userService.findById(id);
  }

  /**
   * 分页搜索查询:分页查询名称或手机号相同的信息
   */
  @PostMapping("findPageByNameOrMobile")
  public Page<User> findPageByNameOrMobile(@RequestBody PageByNameOrMobileRequest request) {
    return userService.findByNameOrMobile(request);
  }

  /***********************highLevelClient高级查询***********************/
  /**
   * 分页搜索查询:分页查询名称或手机号相同的信息,并按age升序排序
   */
  @PostMapping("pageByConditions")
  public Page<User> pageByConditions(@RequestBody PageByNameOrMobileRequest request) {
    return userService.pageByConditions(request);
  }
}

      到此,springboot整合Elasticsearch,并实现了基于repository和restHighLevel两种方式实现了数据的CRUD。

      如果需要本教程项目源码,关注微信公众号:IT特靠谱,完整回复"我要es源码"免费领取下载地址吧~

springboot整合Elasticsearch实现增删改查

本文地址:https://blog.csdn.net/IT_Most/article/details/109803772