1. 程式人生 > >SpringBoot 整合 ElasticSearch 之 ElasticsearchRepository 的 CRUD、分頁介面

SpringBoot 整合 ElasticSearch 之 ElasticsearchRepository 的 CRUD、分頁介面

一、前言

這裡寫圖片描述

前面使用了 SpringBoot 整合了 Solr: [增刪改查] SpringBoot 整合 Solr 實現 CRUD、分頁介面、高亮顯示
眼下有一個比 Solr 還火熱的 ElasticSearch,主要是用於大資料、分散式系統中,順便使用 SpringBoot 來整合

    Elasticsearch是一個基於Lucene的搜尋伺服器。
    它提供了一個分散式多使用者能力的全文搜尋引擎,基於RESTful web介面。Elasticsearch是用Java開發的,並作為Apache許可條款下的開放原始碼釋出,是當前流行的企業級搜尋引擎。設計用於雲端計算中,能夠達到實時搜尋,穩定,可靠,快速,安裝使用方便。

使用的方式主要兩種:
① 一種是經過 SpringData 封裝過的,直接在 dao 介面繼承 ElasticsearchRepository 即可
② 一種是經過 Spring 封裝過的,直接在 Service/Controller 中引入該 bean 即可

    @Autowired
    ElasticsearchTemplate elasticsearchTemplate;

    1
    2

二、程式碼

2018.7.14更新,程式碼已經放到 github 上了:https://github.com/larger5/SpringBoot_ElasticSearch_base.git
1、entity

package com.cun.entity;

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;

/**
 * 加上了@Document註解之後,預設情況下這個實體中所有的屬性都會被建立索引、並且分詞
 * @author linhongcun
 *
 */
//http://120.79.197.131:9200/product
@Document(indexName = "product", type = "book")
public class Book {
    @Id
    String id;
    String name;
    String message;
    String type;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53

2、dao 介面

package com.cun.dao;

import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import com.cun.entity.Book;

public interface BookDao extends ElasticsearchRepository<Book,String>{

}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

3、Controller
① ElasticsearchRepository

package com.cun.controller;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.cun.dao.BookDao;
import com.cun.entity.Book;

import springfox.documentation.swagger2.annotations.EnableSwagger2;

@RestController
@RequestMapping("/book")
@EnableSwagger2
public class BookController {

    @Autowired
    private BookDao bookDao;

    /**
     * 1、查  id
     * @param id
     * @return
     */
    @GetMapping("/get/{id}")
    public Book getBookById(@PathVariable String id) {
        return bookDao.findOne(id);
    }

    /**
     * 2、查  ++:全文檢索(根據整個實體的所有屬性,可能結果為0個)
     * @param q
     * @return
     */
    @GetMapping("/select/{q}")
    public List<Book> testSearch(@PathVariable String q) {
        QueryStringQueryBuilder builder = new QueryStringQueryBuilder(q);
        Iterable<Book> searchResult = bookDao.search(builder);
        Iterator<Book> iterator = searchResult.iterator();
        List<Book> list = new ArrayList<Book>();
        while (iterator.hasNext()) {
            list.add(iterator.next());
        }
        return list;
    }

    /**
     * 3、查   +++:分頁、分數、分域(結果一個也不少)
     * @param page
     * @param size
     * @param q
     * @return
     * @return
     */
    @GetMapping("/{page}/{size}/{q}")
    public List<Book> searchCity(@PathVariable Integer page, @PathVariable Integer size, @PathVariable String q) {

        // 分頁引數
        Pageable pageable = new PageRequest(page, size);

        // 分數,並自動按分排序
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery()
                .add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("name", q)),
                        ScoreFunctionBuilders.weightFactorFunction(1000)) // 權重:name 1000分
                .add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("message", q)),
                        ScoreFunctionBuilders.weightFactorFunction(100)); // 權重:message 100分

        // 分數、分頁
        SearchQuery searchQuery = new NativeSearchQueryBuilder().withPageable(pageable)
                .withQuery(functionScoreQueryBuilder).build();

        Page<Book> searchPageResults = bookDao.search(searchQuery);
        return searchPageResults.getContent();

    }

    /**
     * 4、增
     * @param book
     * @return
     */
    @PostMapping("/insert")
    public Book insertBook(Book book) {
        bookDao.save(book);
        return book;
    }

    /**
     * 5、刪 id
     * @param id
     * @return
     */
    @DeleteMapping("/delete/{id}")
    public Book insertBook(@PathVariable String id) {
        Book book = bookDao.findOne(id);
        bookDao.delete(id);
        return book;
    }

    /**
     * 6、改
     * @param book
     * @return
     */
    @PutMapping("/update")
    public Book updateBook(Book book) {
        bookDao.save(book);
        return book;
    }

}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133

② elasticsearchTemplate(簡單使用)

package com.cun.controller;

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

import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 簡單使用 elasticsearchTemplate
 * @author linhongcun
 *
 */
@RestController
@RequestMapping("/template")
public class BookControllerTemplate {

    @Autowired
    ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 查詢所有
     * @throws Exception
     */
    @GetMapping("/all")
    public List<Map<String, Object>> searchAll() throws Exception {
        //這一步是最關鍵的
        Client client = elasticsearchTemplate.getClient();
        // @Document(indexName = "product", type = "book")
        SearchRequestBuilder srb = client.prepareSearch("product").setTypes("book");
        SearchResponse sr = srb.setQuery(QueryBuilders.matchAllQuery()).execute().actionGet(); // 查詢所有
        SearchHits hits = sr.getHits();
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        for (SearchHit hit : hits) {
            Map<String, Object> source = hit.getSource();
            list.add(source);
            System.out.println(hit.getSourceAsString());
        }
        return list;
    }


}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54

4、yml

server:
  context-path: /
  port: 80
spring:
  data:
    elasticsearch:
      cluster-name: elasticsearch #預設即為 elasticsearch
      cluster-nodes: 120.79.197.131:9300 #配置es節點資訊,逗號分隔,如果沒有指定,則啟動ClientNode

    1
    2
    3
    4
    5
    6
    7
    8

5、pom

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

    1
    2
    3
    4

三、其他

使用 Swagger 生成介面測試頁面,所有介面均經過測試,完全沒有問題!

        <!-- swagger生成介面API -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.7.0</version>
        </dependency>

        <!-- 介面API生成html文件 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.6.1</version>
        </dependency>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

這裡寫圖片描述
四、小結

Ⅰ、應用

    Github、StackOverFlow 等網站都是使用 ElasticSearch 作為搜尋引擎的

Ⅱ、參考文章:

    ① springboot整合elasticsearch入門例子
    ②Spring Boot 整合Elasticsearch
    ③spring 操作elasticsearch
    ④ ElasticSearch搜尋例項含高亮顯示及搜尋的特殊字元過濾
    ⑤ docker環境 快速使用elasticsearch-head外掛

Ⅲ、其他知識須知

    9300埠: ES節點之間通訊使用
    9200埠: ES節點 和 外部 通訊使用
---------------------