Springboot整合ElasticSearch的官方API實例


前言:在上一篇博客中,我介紹了從零開始安裝ElasticSearch,es是可以理解為一個操作數據的中間件,可以把它作為數據的存儲倉庫來對待,它具備強大的吞吐能力和計算能力,其基於Lucene服務器開發,在搜索領域具有統治般的地位。平時可以通過命令來執行語句來查詢ES,但是在實際的開發中,還是以使用API居多,關於ES的第三方框架有很多,比如BBOSS、spring也對其進行封裝叫做spring-elasticsearch-data,本篇博客,我們就來聚焦Spring的官方API,來做一個基本的demo實現api來操作Es(elasticsearch的簡稱)

本篇博客的目錄

一:ElasticSearch的基本概念

二:ElasticSearch5.2.2的安裝

三:ElasticSearch的官方API與Demo實現

四:總結

一:ElasticSearch的基本概念

1.1:索引 index

 索引是ES存儲數據的基本頂層單元目錄.它好比就是關系型數據庫中的數據庫,是存儲數據的地方。當搜索數據的時候,會直接從索引中查取,注意這里要與關系型數據的中的索引區分,他們是完全不同的概念。index的名字必須是小寫,不能包含逗號、下划線或者大寫字母

1.2:類型 type

type表示一類或者一種事物的抽象,在關系型數據庫中我們經常將一類結構相似的數據放在一個表里,而在elasticsearch中,使用相同類型的type表示相同的一類事物,它相當於關系型數據庫中的表(table),用於描述文檔中的各個字段的定義。每個type都有自己的映射(mapping)或者結構定義。type的名字可以是大寫或者小寫,不能包含下划線或者逗號。

1.3:文檔 document

document是index中的單條數據序列化成的json格式的數據,它以唯一id(_id)存儲在ES中,相當於關系表的數據行,存儲數據的載體,包含一個或多個存有數據的字段;

·字段(Field):文檔的一個Key/Value對;

·詞(Term):表示文本中的一個單詞;

·標記(Token):表示在字段中出現的詞,由該詞的文本、偏移量(開始和結束)以及類型組成

1.4:Node 與 Cluster

Elastic 本質上是一個分布式數據庫,允許多台服務器協同工作,每台服務器可以運行多個 Elastic 實例。單個 Elastic 實例稱為一個節點(node)。一組節點構成一個集群(cluster)。

1.5:與mysql進行比較

 二:ElasticSearch5.2.2的安裝

   上一篇博客已經介紹了ES2.0版本的安裝,這篇就不再贅述了。不過我還是決定說一些在安裝過程中的坑,安裝ES的坑確實很多,樓主分別安裝了2.0版本,5.5.2版本,5.2.2版本,還用docker安裝了,但是因為docker玩的不夠熟練,在配置文件上更改還是出了很多問題,最終還是靠傳統的安裝方式解決的。接下來就說說ES安裝過程中的一些坑以及主要的點:

2.1:cannot allocate memory

這個是因為ES無法獲取到足夠的內存,解決辦法就是,修改elasticseach的config目錄下的jvm.options,ES默認的大小是1G,最好修改成2的整數倍的容量,具體依自己的內存而定,我修改的是256m

2.2:Exception in thread "main" java.lang.RuntimeException: don't run elasticsearch as root.   

無法以root用戶啟動,ES直接以root用戶是無法啟動的,解決辦法很簡單,就是建立一個ES的專用的組和用戶:

groupadd elasticsearchgroup
useradd elasticsearchgroup -g elasticsearch -p elasticsearch
chown -R elasticsearchgroup:elasticsearch elasticsearch-5.2.2

這里是先建立了一個elasticsearch的組,然后再添加elasticsearch這個用戶,密碼也是elasticsearch,再給ES的安裝目錄添加權限

2.3:ERROR: bootstrap checks failed max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

解決辦法就是修改系統的修改配置sysctl.conf最大文件交換數量:

vi.sysctl.conf
vm.max_map_count=655360
sysctl -p

2.4: org.elasticsearch.client.transport.NoNodeAvailableException

這個錯誤,是后台在連接APi出現的錯誤,為了解決這個問題,我花了很久(下面會說到版本號的問題),還有需要更改一下配置:

首先是編輯config目錄下的 elasticsearch.yml文件:

這里的host要把#號打開,然后寫上自己的外網IP的地址,還有cluster.name的名字也要記住,它在配置ES中需要用到

三:ElasticSearch的官方API與Demo實現

 3.1.1:引入TransPort5.2.2 

這里必須注意引入5.2.2版本,因為我服務上安裝的ES就是5.2.2版本。ES官方API眾多,每個版本之間不是互相兼容的,如果引入的版本對應,會報一個錯誤:

org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available.(這個錯誤折磨了我很久,所以一定要以自己的服務器上的版本為准,引入netty和elasticsearch、transport的版本互相對應)

        <dependency>
            <groupId>org.elasticsearch.plugin</groupId>
            <artifactId>transport-netty4-client</artifactId>
            <version>5.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>5.2.2</version>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
            <version>5.2.2</version>
        </dependency>

3.1.2:springboot配置ES

新建一個類叫做ESconfig,主要是配置ES服務器的IP和端口(注意這里是9300而不是9200),9300是ES的TCP服務端口,然后實例化客戶端;

package com.wyq.elasticsearch.easticsearchtest.config;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.InetAddress;
import java.net.UnknownHostException;

@Configuration
public class ESConfig {

    @Bean
    public TransportClient client() throws UnknownHostException {
        // 9300是es的tcp服務端口
        final  String host = "176.122.132.220";
        InetSocketTransportAddress node = new InetSocketTransportAddress(
                InetAddress.getByName(host),
                9300);

        // 設置es節點的配置信息
        Settings settings = Settings.builder()
                .put("cluster.name", "application").build();

        // 實例化es的客戶端對象
        TransportClient client = new PreBuiltTransportClient(settings);
        client.addTransportAddress(node);
        return client;
    }
}

 3.1.3:添加index

如果在ES里面添加一個index,我們需要以下命令,解釋以下就是指定數據的index和type,在里面在指定fieldname

curl -X PUT 'ip:port/index/type/id’ -d '
{
  “filedname”: “xxx”
}' 

ES提供了同等的API來供我們使用,按照下面的例子,我們將會添加一個index叫做animal,type叫做person的數據,並通過Springboot注入TransPortClient,然后用MVC來獲取請求參數,交給ES的api去處理:XContentFactory.jsonBuilder()去拼接不同的json字符串,用client去處理:

@RestController
public class ElasticSearchDemoController {

    @Autowired
    private TransportClient client;

    public static final String index = "product";

    public static final String type = "person";


/**
     * 添加一個人的數據
     *
     * @param name    名字
     * @param sex     性別
     * @param message 說明
     * @param job 工作
     * @param onlyMark 唯一標志
     * @return
     */
    @PostMapping("/es/add")
    public ResponseEntity add(@RequestParam("name") String name,
                              @RequestParam("sex") int sex,
                              @RequestParam("message") String message,
                              @RequestParam("job") String job,
                              @RequestParam("onlyMark") int onlyMark) {
        try {
            // 將參數build成一個json對象
            XContentBuilder content = XContentFactory.jsonBuilder()
                    .startObject()
                    .field("uniqueId", onlyMark)
                    .field("name", name)
                    .field("sex", sex)
                    .field("message", message)
                    .field("job", job)
                    .endObject();

            IndexResponse response = client.prepareIndex(index, type)
                    .setSource(content)
                    .get();

            return  ResponseEntity.getSuccess(response.getResult()+""+response.getId(), HttpStatus.OK.value());
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR.value());
        }
    }
}

3.1.4:查詢index

通過id去查詢,然后通過client(TransPortClient)的prepareGet方法去查詢,最后返回一個GetResponse結果然后獲取它的source結果:

 /**
     * 按id查詢
     *
     * @param id
     * @return
     */
    @GetMapping("/es/get")
    public ResponseEntity searchById(@RequestParam("id") String id) {
        if (id.isEmpty()) {
            return new ResponseEntity(HttpStatus.NOT_FOUND.value());
        }
        // 通過索引、類型、id向es進行查詢數據
        GetResponse response = client.prepareGet(index, type, id).get();

        if (!response.isExists()) {
            return new ResponseEntity(HttpStatus.NOT_FOUND.value());
        }
        return  ResponseEntity.getSuccess(response.getSource(), HttpStatus.OK.value());
    }

3.1.5:刪除index

同樣刪除index,也是通過id來匹配的,id是唯一標志,然后交給TransPort的prepareDelete方法去刪除

 /**
     * 按id刪除數據
     *
     * @param id
     * @return
     */
    @GetMapping("/es/delete")
    public ResponseEntity delete(@RequestParam("id") String id) {
        DeleteResponse response = client.prepareDelete(index, type, id).get();
      return  ResponseEntity.getSuccess(response.getResult(), HttpStatus.OK.value());
    }

3.1.6:更新index

通過獲取更新的內容,然后交給TransPort的update方法去更新需要更新的字段,最終返回更新的內容:

 /**
     * 根據文檔id更新某個文檔的數據
     *
     * @param uniqueId
     * @param name
     * @param sex
     * @param message
     * @param job
     * @return
     */
    @PutMapping("/es/update")
    public ResponseEntity update(@RequestParam("id") String id,
                                 @RequestParam(value = "name", required = false) String name,
                                 @RequestParam(value = "sex", required = false) Integer sex,
                                 @RequestParam(value = "message", required = false) String message,
                                 @RequestParam(value = "job", required = false) String job,
                                 @RequestParam(value = "uniqueId", required = false) Integer uniqueId){
        UpdateRequest update = new UpdateRequest(index, type, id);
        try {
            XContentBuilder builder = XContentFactory.jsonBuilder()
                    .startObject();

            if (Objects.nonNull(name)) {
                builder.field("name", name);
            }
            if (Objects.nonNull(sex)) {
                builder.field("sex", sex);
            }
            if (Objects.nonNull(message)) {
                builder.field("message", message);
            }
            if (Objects.nonNull(job)) {
                builder.field("job", job);
            }
            if (Objects.nonNull(uniqueId)){
                builder.field("uniqueId",uniqueId);
            }

            builder.endObject();
            update.doc(builder);
            UpdateResponse response = client.update(update).get();
            return  ResponseEntity.getSuccess(response.getResult(), HttpStatus.OK.value());
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR.value());
        }
    }

 3.2:測試

3.2.1:打開postman,然后我們來先來添加一個index,添加一些屬性,后台提示成功:我們在去ES中查詢一下:

3.2.2:在服務器中打開,然后輸入查詢所有index的命令,查詢animal這個index對應的數據,可以看到我們的數據已經順利添加:

3.2.3:查詢index

上面的方式是通過命令的方式來查詢的,我們再來通過程序來測試查詢index,可以看到數據查詢到了:

3.2.4:更新index

后台通過傳入的字段對指定有值的數據進行更新,在這里我們更新message:

 

 3.2.5:為了驗證我們的更改是否生效,我們再查詢一下這個index,發現message已經變化了:

3.2.6:刪除index

 

 3.2.7:同樣我們在驗證一下是否刪除成功,可以看出total為0,也代表沒有數據了:

 

四:總結

    礙於篇幅,本片博文就介紹到這里,主要是講述了ElasticSearch的官方API的使用,以及搭建ES中的一些坑,為了解決這些坑,我在下班之余耗費了好幾個星期研究這些問題,ES的版本眾多,一定要注意版本的選擇。本篇博文適合入門級別,沒有介紹ES的高級特性,關於它本身具有很多高端特性,實乃搜索利器,我們不能把它作為數據庫來看待,實際上它本身可以理解為一個搜索引擎,有着豐富的使用場景,"它遠大於數據庫,存儲只是它的一個細小的功能",好了,希望本篇博客可以幫助到你。

本篇博客的代碼分享:鏈接:https://pan.baidu.com/s/1k-E15_EtHArG3iYi_3wc9A  密碼:0nbp

如果關於本篇博客有任何問題,請加群:618626589

參考文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html

                http://www.ruanyifeng.com/blog/2017/08/elasticsearch.html

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM