全网超详细的 SpringBoot 整合 Elasticsearch 实战教程

全网超详细的 SpringBoot 整合 Elasticsearch 实战教程

点击加入:

后端技术内卷群,一起学习!

最近系统中要用到搜索功能,如果直接使用MySQL的like查询语句会影响系统的性能,所以就采用了Elasticsearch来实现站内搜索。

本文以图书的搜索功能作为Demo来演示在Spring Boot如何整合Elasticsearch以及如何优雅的使用elasticsearch。

Spring Boot与Elasticsearch的对应版本

Elasticsearch更新非常快,最新的7.x版本已经不支持自定义类型了,默认以 _doc 作为类型,一个索引只能有一个类型。

为了避免使用的Elasticsearch版本和SpringBoot采用的版本不一致导致的问题,尽量使用一致的版本。下表是对应关系:

全网超详细的 SpringBoot 整合 Elasticsearch 实战教程

创建SpringBoot项目并引入Elasticsearch依赖

  • 本文使用的SpringBoot版本为2.3.7.RELEASE
  • 对应的Elasticsearch版本为7.6.2

引入Spring-Data-Elasticsearch依赖,Spring 团队将Elasticsearch归到“Data”的范畴,所以依赖是以Spring-Data开头。

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

这个例子中还使用了JPA,所以需要引入JPA依赖:

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

基于Java的Elasticsearch配置

新建类 RestClientConfig作为Elasticsearch Rest客户端的配置了类:

/**
 * ElasticSearch 客户端配置
 *
 * @author geng
 */

@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {
    @Override
    @Bean
    public RestHighLevelClient elasticsearchClient() {
        final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo("localhost:9200")
                .build();
        return RestClients.create(clientConfiguration).rest();
    }
}

注意:Elasticsearch从7版本开始TransportClient已经过时了不再推荐使用,将在8.0版本删除,具体参考:

https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/transport-client.html

Spring Data Elasticsearch支持TransportClient,只要它在已使用的Elasticsearch版本中可用,但从4.0版本起已经不再建议使用它。

强烈建议使用Hight Level Rest Client(也就是上边的配置)代替TransportClient

像操作普通数据库一样实现Elasticsearch的CRUD

说真的看到这,你是不是惊呆了,反正我是!Spring Boot提供高级接口,操作ElasticSearch就像写数据库的CRUD一样简单!大佬,请收下我的膝盖!

编码流程和数据库CRUD一样:

定义Book实体,官方叫Elasticsearch 对象映射:

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.util.Date;
/**
 * @author geng
 */

@Data
@Document(indexName = "book",createIndex = true)
public class Book {
    @Id
    @Field(type = FieldType.Text)
    private String id;
    @Field(analyzer="ik_max_word")
    private String title;
    @Field(analyzer="ik_max_word")
    private String author;
    @Field(type = FieldType.Double)
    private Double price;
    @Field(type = FieldType.Date,format = DateFormat.basic_date_time)
    private Date createTime;
    @Field(type = FieldType.Date,format = DateFormat.basic_date_time)
    private Date updateTime;
}
  • @Document定义在Elasticsearch中索引信息
  • @Id定义了Elasticsearch的_id
  • @Field定义字段类型等信息
  • …更多注解请参照官方文档…
Elasticsearch Repositories

创建接口ESBookRepository

import com.gyb.elasticsearch.demo.entity.es.Book;
import org.springframework.data.elasticsearch.annotations.Highlight;
import org.springframework.data.elasticsearch.annotations.HighlightField;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;

/**
 * ES Book repository
 *
 * @author geng
 */

public interface ESBookRepository extends ElasticsearchRepository<BookString{

    List<Book> findByTitleOrAuthor(String title, String author);

    @Highlight(fields = {
            @HighlightField(name = "title"),
            @HighlightField(name = "author")
    })
    @Query("{"match":{"title":"?0"}}")
    SearchHits<Book> find(String keyword);
}

该接口继承了ElasticsearchRepository接口,ElasticsearchRepository接口定义了Elasticsearch的CRUD,继承了该接口的接口甚至无需定义任何其他的方法就能满足基本需求。

比较厉害的是通过定义的方法名就能自动创建各种查询,例如:

import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

/**
 * 关系型数据库mysql Repository
 *
 * @author cloudgyb
 */

public interface BookRepository extends JpaRepository<BookString{
    List<Book> findByNameAndPrice(String name, Integer price);
}

这个方法将自动被转化成下面的Elasticsearch Json查询语句

{
    "query": {
        "bool" : {
            "must" : [
                { "query_string" : { "query" : "?""fields" : [ "name" ] } },
                { "query_string" : { "query" : "?""fields" : [ "price" ] } }
            ]
        }
    }
}

好NB有没有?

并且支持使用@Query注解自定义查询,使用@Highlight定义关键字高亮,没有一个注解解决不了的问题。

方法名支持的关键字如下:

全网超详细的 SpringBoot 整合 Elasticsearch 实战教程
全网超详细的 SpringBoot 整合 Elasticsearch 实战教程

这只是部分,更多查看官方文档。

并且方法支持多种返回类型,无需做任何适配,根据类型自动封装:

  • List
  • Stream
  • SearchHits
  • List<SearchHit>
  • Stream<SearchHit>
  • SearchPage
定义Service方法
/**
 * @author geng
 */

@Slf4j
@Service
public class BookService {
    private final BookRepository bookRepository;
    private final ESBookRepository esBookRepository;
    private final TransactionTemplate transactionTemplate;

    public BookService(BookRepository bookRepository,
                       ESBookRepository esBookRepository,
                       TransactionTemplate transactionTemplate)
 
{
        this.bookRepository = bookRepository;
        this.esBookRepository = esBookRepository;
        this.transactionTemplate = transactionTemplate;
    }

    public void addBook(Book book) {
        final Book saveBook = transactionTemplate.execute((status) ->
                bookRepository.save(book)
        );
        final com.gyb.elasticsearch.demo.entity.es.Book esBook = new com.gyb.elasticsearch.demo.entity.es.Book();
        assert saveBook != null;
        BeanUtils.copyProperties(saveBook, esBook);
        esBook.setId(saveBook.getId() + "");
        try {
            esBookRepository.save(esBook);
        }catch (Exception e){
            log.error(String.format("保存ES错误!%s", e.getMessage()));
        }
    }

    public List<com.gyb.elasticsearch.demo.entity.es.Book> searchBook(String keyword){
        return esBookRepository.findByTitleOrAuthor(keyword, keyword);
    }

    public SearchHits<com.gyb.elasticsearch.demo.entity.es.Book> searchBook1(String keyword){
        return esBookRepository.find(keyword);
    }
}
定义Controller

/**
 * @author geng
 */

@RestController
public class BookController {
    private final BookService bookService;
    
    public BookController(BookService bookService) {
        this.bookService = bookService;
    }

    @PostMapping("/book")
    public Map<String,String> addBook(@RequestBody Book book){
        bookService.addBook(book);
        Map<String,String> map = new HashMap<>();
        map.put("msg","ok");
        return map;
    }

    @GetMapping("/book/search")
    public SearchHits<com.gyb.elasticsearch.demo.entity.es.Book> search(String key){
        return bookService.searchBook1(key);
    }
}

测试看效果

1、启动Elasticsearch服务

无需手动创建Book索引,Springboot启动自动创建

2、启动SpringBoot项目
3、使用/book接口创建几条测试数据
curl -H "Content-Type:application/json" -XPOST http://localhost:8080/book -d
{
    "id":"1",
    "title":"富婆通讯录",
    "author":"耿小李",
    "price":9999.9,
    "createTime":"2020-12-21 12:00:00"
}
4、搜索数据

打开浏览器http://localhost:8080/book/search?key=富婆

全网超详细的 SpringBoot 整合 Elasticsearch 实战教程

Spring Data Elasticsearch官方文档:

https://docs.spring.io/spring-data/elasticsearch/docs/4.1.2/reference/html/#preface

GITHUB仓库源码:

https://github.com/cloudgyb/es-spring-boot

来源:cloudgyb.blog.csdn.net/article/details/111469217

精彩推荐
最全的java面试题库
开源版的高仿 “ 微信 ”,吊炸天!

与其在网上拼命找题? 不如马上关注我们~

全网超详细的 SpringBoot 整合 Elasticsearch 实战教程


↓点阅读原文,Java面试题库尽情看!

原文始发于微信公众号(Java面试题精选):全网超详细的 SpringBoot 整合 Elasticsearch 实战教程

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/54227.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!