SpringBoot2.x系列教程54--SpringBoot整合ElasticSearch方式一

一. Elastic Search

1. Elastic Search簡介

ElasticSearch是一個基於Lucene的開源的、分佈式實時搜索和分析引擎。它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java開發的,並作爲Apache許可條款下的開放源碼發佈,是當前流行的企業級搜索引擎。

Spring Boot爲Elasticsearch提供基本的自動配置,我們可以利用Spring Data Elasticsearch在Spring Boot中進行開發。

2. 搭建配置Elastic Search環境

在利用Elastic Search開發之前,請先搭建好Elastic Search環境,我這裏配置了ELK環境。關於ELK環境的搭建,感興趣的朋友可以自行搜索。

3. Spring Boot與Elastic Search版本關係

在新版本的Spring boot2.x中,spring-boot-starter-data-elasticsearch支持的Elasticsearch版本是2.X,但Elasticsearch實際上已經發展到6.5.X版本了,爲了更好的使用Elasticsearch的新特性,我們可以棄用spring-boot-starter-data-elasticsearch依賴,改爲直接使用Spring-data-elasticsearch,以便啓用對新版本支持,目前的版本對應關係如下:

二. Spring Boot2.2.5整合Elastic Search 5.6.8

1. 環境要求

  • Spring Boot 2.2.5;
  • Elastic Search 5.6.8;
  • Kibana 5.6.8;
  • Maven

2. 創建web項目

我們按照之前的經驗,創建一個web程序,並將之改造成Spring Boot項目,具體過程略。

3. 添加依賴包

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

注意:因爲我的elastic search 並不是6.5.x以上的最新版本,而是5.6.8版本,所以我這裏使用的還是spring-boot-starter-data-elasticsearch的依賴包。

4. 創建application.yml配置文件

# Elasticsearch
# 9200作爲Http協議,主要用於外部通訊,而9300作爲Tcp協議,是傳輸層監聽的默認端口,jar之間就是通過tcp協議通訊
elasticsearch:
  #注意cluster.name需要與config/elasticsearch.yml中的cluster.name一致
  # Elasticsearch cluster name.
  cluster:
    name: elasticsearch
  # Comma-separated list of cluster node addresses.
  ip: localhost
  port: 9300
  pool: 5

elastic search默認的端口號是9300。

5. 創建ElasticSearchConfig配置類

package com.yyg.boot.config;

import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;

import java.net.InetAddress;

/**
 * @Author 一一哥Sun
 * @Date Created in 2020/4/13
 * @Description Description
 */
@Slf4j
@Configuration
public class ElasticSearchConfig {

    @Value("${elasticsearch.ip}")
    private String hostName;

    @Value("${elasticsearch.port}")
    private String port;

    @Value("${elasticsearch.cluster.name}")
    private String clusterName;

    @Value("${elasticsearch.pool}")
    private String poolSize;

    /**
     * 構建TransportClient對象
     */
    @Bean(name = "transportClient")
    public TransportClient transportClient() {
        log.info("Elasticsearch初始化開始。。。。。");
        TransportClient transportClient = null;
        try {
            // 配置信息
            Settings esSetting = Settings.builder()
                    //集羣名字
                    .put("cluster.name", clusterName)
                    //增加嗅探機制,找到ES集羣
                    .put("client.transport.sniff", true)
                    //增加線程池個數,暫時設爲5
                    .put("thread_pool.search.size", Integer.parseInt(poolSize))
                    .build();
            //配置信息Settings自定義
            transportClient = new PreBuiltTransportClient(esSetting);
            TransportAddress transportAddress = new TransportAddress(InetAddress.getByName(hostName), Integer.valueOf(port));
            transportClient.addTransportAddresses(transportAddress);
        } catch (Exception e) {
            log.error("elasticsearch TransportClient create error!!", e);
        }
        return transportClient;
    }

    /**
     * 構建ElasticsearchTemplate對象
     */
    @Bean
    public ElasticsearchOperations elasticsearchTemplate() {
        Client client = transportClient();
        if (client != null) {
            return new ElasticsearchTemplate(client);
        } else {
            //彈出異常對象
            throw new RuntimeException("初始化Elasticsearch失敗!");
        }
    }

}

6. 創建增刪改查接口

我這裏直接使用TransportClient進行增刪改查,後面的章節中,我會講解簡化方案。

package com.yyg.boot.web;

import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Author 一一哥Sun
 * @Date Created in 2020/4/13
 * @Description Description
 */
@RestController
@RequestMapping("/book")
public class BookController {

    @Autowired
    private TransportClient transportClient;

    /**
     * 添加博客索引信息
     */
    @PostMapping("/add")
    public ResponseEntity add(
            @RequestParam(name = "title") String title,
            @RequestParam(name = "author") String author,
            @RequestParam(name = "word_count") int wordCount,
            @RequestParam(name = "publish_date") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date publishDate
    ) {
        try {
            XContentBuilder content = XContentFactory.jsonBuilder()
                    .startObject()
                    .field("title", title)
                    .field("author", author)
                    .field("word_count", wordCount)
                    .field("publish_date", publishDate.getTime())
                    .endObject();
            IndexResponse result = this.transportClient.prepareIndex("blogs", "blog").setSource(content).get();
            return new ResponseEntity(result.getId(), HttpStatus.OK);
        } catch (Exception e) {
            e.printStackTrace();
            ;
            return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 根據id查詢
     */
    @GetMapping("/get")
    public ResponseEntity get(@RequestParam(name = "id", defaultValue = "") String id) {
        if (id.isEmpty()) {
            return new ResponseEntity((HttpStatus.NOT_FOUND));
        }
        GetResponse result = transportClient.prepareGet("blogs", "blog", id).get();
        if (!result.isExists()) {
            return new ResponseEntity((HttpStatus.NOT_FOUND));
        }
        return new ResponseEntity(result.getSource(), HttpStatus.OK);
    }

    /**
     * 按條件查詢
     */
    @GetMapping("/query")
    public ResponseEntity query(
            @RequestParam(name = "author", required = false) String author,
            @RequestParam(name = "title", required = false) String title,
            @RequestParam(name = "gt_word_count", defaultValue = "0") int gtWordCount,
            @RequestParam(name = "lt_word_count", required = false) Integer ltWordCount
    ) {
        //設置查詢條件
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (author != null) {
            boolQuery.must(QueryBuilders.matchQuery("author", author));
        }
        if (title != null) {
            boolQuery.must(QueryBuilders.matchQuery("title", title));
        }
        //按範圍查詢
        RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("word_count").from(gtWordCount);
        if (ltWordCount != null && ltWordCount > 0) {
            rangeQuery.to(ltWordCount);
        }
        boolQuery.filter(rangeQuery);

        SearchRequestBuilder builder = this.transportClient.prepareSearch("blogs")
                .setTypes("blog")
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .setQuery(boolQuery)
                //設置分頁查詢
                .setFrom(0)
                .setSize(10);
        System.out.println(builder);

        SearchResponse response = builder.get();
        List<Map<String, Object>> result = new ArrayList<>();

        for (SearchHit hit : response.getHits()) {
            result.add(hit.getSourceAsMap());
        }
        return new ResponseEntity(result, HttpStatus.OK);
    }

}

7. 創建Application入口類

package com.yyg.boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @Author 一一哥Sun
 * @Date Created in 2020/4/9
 * @Description Description
 */
@SpringBootApplication
public class ElasticApplication {

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

}

完整項目結構:

8. 啓動elastic search和kibana環境

elastic search正常啓動後效果

kibana正常啓動後效果

9. 在postman中進行測試

測試添加博客功能


可以看到最後返回了新增的博客id。

在kibana中進行索引的查看

在我們前面的代碼中,我們已經創建了index索引爲blogs,所以我們可以在kibana中把這個blogs索引同步過來。

到這一步,我們就把代碼中創建好的blogs索引同步過來了,接下來我們可以查看blogs索引中的內容。

發現blogs索引中已經有了我們之前添加的博客內容。

測試按id查詢博客接口

測試查詢全部結果的接口

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章