Elasticsearch安裝、原理學習總結

  • 2020 年 9 月 22 日
  • 筆記

ElasticSearch

ElasticSearch概念

Elasticsearch是Elastic Stack核心的分散式搜索和分析引擎。

 

什麼是Elastic Stack

Elastic Stack,就是ElasticSearch + LogStash + Kibana

 

Logstash用於收集,聚合和豐富數據並將其存儲在Elasticsearch中。

Kibana提供了一套可視化介面,可以互動式的瀏覽數據,以及管理和監視堆棧。

ElasticSearch是一個分散式,高性能、高可用、可伸縮的搜索和分析系統。

 

Elasticsearch是用Java語言開發的,並作為Apache許可條款下的開放源碼發布,是一種流行的企業級搜索引擎。Elasticsearch主要用於雲計算中,能夠達到實時搜索,穩定,可靠,快速,並且安裝使用方便。官方客戶端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和許多其他語言中都是可用的。

 

Elasticsearch的使用場景

網上商場,搜索商品.

配合logStash和kibana進行日誌分析

 

為什麼要使用Elasticsearch

假設用關係型資料庫做搜索,當用戶在搜索框輸入「一名程式設計師」時,資料庫通常只能把這四個字去進行全部匹配。可是在文本中,可能會出現「他是一名合格的程式設計師」,這時候就沒有結果了,但是ES就可以實現檢索,而且速度極快。

 

Elasticsearch基本概念

Elasticsearch和關係型資料庫概念對應關係(方便理解ES的架構)

關係型資料庫

Elasticsearch

資料庫

索引

數據表

類型

文檔

欄位

 

近實時(NRT)

ES是一個近實時的搜索引擎(平台),代表著從添加數據到能被搜索到只有很少的延遲。(大約是1s)

 

文檔

Elasticsearch是面向文檔的。可以把文檔理解為關係型資料庫中的一條記錄,文檔會被序列化成json格式,保存在Elasticsearch中。同樣json對象由欄位組成,每一個欄位都有自己的類型(字元串,數值,布爾,二進位,日期範圍類型)。當我們創建文檔時,如果不指定類型,Elasticsearch會幫我們自動匹配類型。每個文檔都一個ID(_id),你可以自己指定,也可以讓Elasticsearch自動生成。json格式,支援數組/嵌套,在一個索引裡面,你可以存儲任意多的文檔。

具體欄位類型和屬性的對應關係請參考官網:

//www.elastic.co/guide/en/elasticsearch/reference/6.0/mapping-types.html

 

索引

索引是具有某種相似特性的文檔集合。例如,您可以擁有客戶數據的索引、產品目錄的索引以及訂單數據的索引。索引的名稱必須全部是小寫字母。在單個集群中,您可以定義任意多個索引。

 

類型

一個索引可以有多個類型。例如一個索引下可以有文章類型,也可以有用戶類型,也可以有評論類型。

 

 

從6.0開始,type已經被逐漸廢棄。在7.0之前,一個index可以設置多個types。7.0開始一個索引只能創建一個type(默認是_doc,索引創建以後會自動創建)

 

節點

節點是一個Elasticsearch實例,本質上就是一個java進程。

節點的類型主要分為如下幾種:

master eligible節點

每個節點啟動後,默認就是master eligible節點,可以通過node.master: false 禁止,

master eligible可以參加選舉成為master節點,當第一個節點啟動後,它會將自己選為master節點。

data節點

可以保存數據的節點。負責保存分片數據。

Coordinating(協調)節點

負責接收客戶端請求,當請求發送到某個節點的時候,這個節點就成為了協調節點,將請求發送到合適的節點,最終把結果彙集到一起,返回給客戶端。每個節點默認都起到了協調節點的職責。

分片和分片副本

一個索引可能會存儲大量數據,這些數據可能超過單個節點的硬體限制。例如,十億個文檔的單個索引佔用了1TB的磁碟空間,可能不適合單個節點的磁碟,或者可能太慢而無法單獨滿足來自單個節點的搜索請求。

為了解決此問題,Elasticsearch提供了將索引細分為多個碎片的功能。創建索引時,只需定義所需的分片數量即可。每個分片本身就是一個功能齊全且獨立的「索引」,可以託管在群集中的任何節點上。

分片很重要,它可能分布在多個節點上。

在隨時可能發生故障的網路環境中,分片副本非常有用,為了防止某節點因某種原因離線。導致數據查詢不到,Elasticsearch允許將索引分片的一個或多個副本製作為所謂的副本分片(簡稱副本)。如果分片/節點發生故障,分片副本可提供高可用性(相當於一個主從)。

 

重要的是要注意:副本碎片永遠不會與從其複製原始碎片的節點分配在同一節點上。

例如:node1和node2的集群,如果分片1在node1節點,那麼分片1的副本就不可能分布在node1節點,因為如果這樣設計的話就沒意義了,如果node1掛了,那麼分片1 和它的副本都不可用了。

 

創建索引後,可以隨時動態更改副本數,但不能更改分片數,因為如果修改了分片數的話會導致分片上的數據錯亂。

 

Elasticsearch寫數據原理

 

 

寫請求發送到集群節點,比如發送到了node1,這個節點內部會去根據ID計算hash,計算這個ID到底屬於哪個主分片(ID通過hash以後對主分片的數量取余),比如這個時候計算出來屬於主分片2,這個時候node1節點會把請求轉發到node2節點的主分片2,進行寫入數據,當主分片2寫入數據成功以後,會把請求並行轉發到對應的兩個副本R2-1和R2-2,寫入成功以後返回到主分片,然後返回到node1,最後由node1返回到客戶端,報告寫入成功,如果寫入副本的時候失敗了,會把寫入失敗的分片移除(防止讀取數據的時候從這個分片中讀不到數據或者讀到臟數據)。

 

以上寫入都是寫入到記憶體中,寫入之前會先轉換為段(這就是近實時中說到的,有1S的延遲時間),同時伴隨有一個日誌文件的寫入,當寫入到記憶體以後過五分鐘以後,通過定時任務,才把數據寫到磁碟上,日誌文件的存在是為了解決定時任務5分鐘期間記憶體出現問題導致讀取不到記憶體數據的問題,如果記憶體出現問題,直接讀取日誌文件,寫到磁碟。

 

官網參考:

//www.elastic.co/guide/en/elasticsearch/reference/6.0/docs-replication.html

 

Elasticsearch讀數據原理

Elasticsearch查詢分為兩個階段: Query(查)和 Fetch(取),假設我們進行分頁查詢從 from到 from + size 的文檔資訊,下面是查詢流程:

from:代表前面忽略多少數據,size:代表查詢數據的條數

Query 階段

 

 

1、客戶端發送一個search請求到node2上,node節點此時就是協調節點。

2、接著node2以協調節點的身份廣播這個search請求到索引裡面每一個主分片或者副分片上(不為主副),每個分片執行查詢並進行排序,返回from+size個排序後的文檔 ID給協調節點node2。

3、然後node2負責將所有分片查詢返回的數據給合併到一個全局的排序的列表。

 

Fetch 階段

1、協調節點node2從全局排序列表中,選取 from 到 from + size 個文檔的 ID,並發送一個批量的查詢請求到相關的分片上(即發送批量文檔ID,根據ID查詢文檔)。

2、協調節點node2將查詢到的結果集返回到客戶端上。

 

官網參考:

//www.elastic.co/guide/en/elasticsearch/reference/6.0/docs-replication.html

 

倒排索引

倒排索引就是為什麼ES查詢如此快的原因

官網地址:

//www.elastic.co/guide/en/elasticsearch/guide/current/inverted-index.html

 

原理自行參考:通過分詞到記憶體中找ID,再通過ID到磁碟上查找數據

//blog.csdn.net/jiaojiao521765146514/article/details/83750548

//www.cnblogs.com/dreamroute/p/8484457.html

 

Elasticsearch安裝(linux)

下載安裝包

下載elasticsearch安裝包,版本7.9.1(目前最新版本)

下載地址://www.elastic.co/cn/downloads/elasticsearch

 

 

安裝elasticsearch

特別注意:

elasticsearch和kibana的安裝路徑不能有空格,要不然kibana啟動會報如下錯誤

 

 

把安裝包上傳到伺服器的安裝目錄並解壓

 

 

注意:

elasticsearch是不允許使用root用戶啟動的

在6.xx之前,可以通過root用戶啟動。但是後來發現黑客可以通過elasticsearch獲取root用戶密碼,所以為了安全性,在6版本之後就不能通過root啟動elasticsearch

 

新建操作用戶

groupadd elasticsearch

useradd elasticsearch -g elasticsearch

cd /usr/local/src/elasticsearch

chown -R elasticsearch: elasticsearch elasticsearch-7.9.1

 

修改JVM參數

如果機器記憶體足夠的話也可以默認,默認1G

vi config/jvm.options

 

修改如下內容:

-Xms512m

-Xmx512m

 

修改ES相關配置

vi config/elasticsearch.yml

 

修改如下內容:

#集群名稱, 默認名稱為elasticsearch

cluster.name=zhongan-elasticsearch

#節點名稱

node.name=node-1

#允許訪問的IP

network.host: 0.0.0.0

#管理管埠

http.port: 9200

#允許成為主節點的節點名稱

cluster.initial_master_nodes: [“node-1”]

#數據保存路徑

path.data: /usr/local/src/elasticsearch/elasticsearch-7.9.1/data

#日誌路徑

path.logs: /usr/local/src/elasticsearch/elasticsearch-7.9.1/logs

 

修改sysctl.conf

vi /etc/sysctl.conf

 

寫入如下內容:

vm.max_map_count=655360

#使配置生效

sysctl -p

註:如果不修改,啟動會報如下錯誤:

vm最大虛擬記憶體,max_map_count[65530]太低,至少增加到[262144]

max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

 

修改limits.conf

vi /etc/security/limits.conf

寫入如下內容:

* soft nofile 65536

* hard nofile 131072

* soft nproc 2048

* hard nproc 4096

* 所有用戶

nofile – 打開文件的最大數目

noproc – 進程的最大數目

soft 指的是當前系統生效的設置值

hard 表明系統中所能設定的最大值

註:如果不修改,啟動會報如下錯誤:

最大文件描述符[4096]對於elasticsearch進程可能太低,至少增加到[65536]

descriptors [4096] for elasticsearch process likely too low, increase to at least [65536]

 

修改90-nproc.conf

vi /etc/security/limits.d/90-nproc.conf

寫入如下內容:

* soft nproc 4096

註:如果不修改,啟動會報如下錯誤:

用戶的最大執行緒數[2048]過低,增加到至少[4096]

max number of threads [2048] for user [tongtech] is too low, increase to at least [4096]

 

啟動

cd /usr/local/src/elasticsearch/elasticsearch-7.9.1/bin

#以後台方式運行

./elasticsearch -d

出現如下日誌表示啟動成功

 

 

防火牆設置

需要把ES相關埠添加白名單

#開啟9200埠

firewall-cmd –zone=public –add-port=9200/tcp –permanent

#開啟9300埠

firewall-cmd –zone=public –add-port=9300/tcp –permanent

#重啟防火牆

systemctl restart firewalld

 

驗證

瀏覽器訪問://ip:9200/

Elasticsearch重啟

ps -ef | grep elastic

kill -9 PID

 

 

Kibana安裝(linux)

下載安裝包

下載kibana安裝包,版本7.9.1(需要和ES版本一致

下載地址://www.elastic.co/cn/downloads/kibana

 

 

安裝Kibana

把安裝包上傳到伺服器的安裝目錄並解壓

 

修改配置文件

vi /usr/local/src/elasticsearch/kibana-7.9.1-linux-x86_64/config/kibana.yml

修改如下配置

#管理端埠

server.port: 5601

#允許訪問的IP

server.host: “0.0.0.0”

#管理端語言,默認未英文,修改為中文

i18n.locale: “zh-CN”

#ES地址

elasticsearch.hosts: [“//localhost:9200”]

 

啟動kibana

cd /usr/local/src/elasticsearch/kibana-7.9.1-linux-x86_64/bin

nohup ./kibana –allow-root &

 

防火牆設置

把kibana埠設置為白名單

#開啟5601埠

firewall-cmd –zone=public –add-port=5601/tcp –permanent

#重啟防火牆

systemctl restart firewalld

 

訪問kibana

瀏覽器訪問://ip:5601/

出現如下介面表示啟動成功

 

Kibana重啟

netstat -apn|grep 5601

kill -9 PID

 

Elasticsearch用戶設置

完成Elasticsearch和kibana的安裝以後發現管理端可以直接訪問數據,這樣是不安全的,下面就是Elasticsearch用戶相關介紹

 

用戶新增

Elasticsearch內部已經內置了一些用戶,只需要設置這些用戶的密碼,並修改配置文件即可。

修改配置文件

修改elasticsearch.yml文件加入如下配置,啟用節點上的Elasticsearch安全功能

xpack.security.enabled: true

xpack.license.self_generated.type: basic

xpack.security.transport.ssl.enabled: true

 

重啟ES,訪問ES,這個時候需要用戶名密碼訪問,如下截圖:

 

 

 

設置用戶密碼

ES bin目錄執行命令,依次設置用戶密碼

./elasticsearch-setup-passwords interactive

 

 

 

用戶登錄

 

 

 

Kibana配置

這個時候訪問kibana發現也需要登錄

需要修改kibana的配置文件:kibana.yml

加入以下配置:

#ES的登錄用戶名

elasticsearch.username: “elastic”

# ES的登錄用戶名密碼,需要對應

elasticsearch.password: “123456”

 

重啟kibana,訪問kibana

 

 

 

分詞器安裝

Elasticsearch內部已經內置了一些分詞器,無需進一步配置即可在任何索引中使用

官網地址:

//www.elastic.co/guide/en/elasticsearch/reference/current/analysis-analyzers.html

 

Standard

默認分詞器 按詞分類 小寫處理

Simple

非字母文本劃分為多個詞 小寫處理

Stop

小寫處理 停用詞過濾(the,a, is)

Whitespace

按空格切分

Keyword

不分詞,當成一整個term輸出

Patter

通過正則表達式進行分詞 默認是 \W+(非字母進行分隔)

Language

提供了 30 多種常見語言的分詞器

Standard分詞器簡單操作:

 

 

 

 

 

其他分詞器自行嘗試後看效果。。。

 

一般使用ES內置分詞器即可,但是內置分詞器對中文的分詞效果較差,一段中文經過內置分詞器分詞以後會變為一個一個的漢字,所以需要用分詞器插件,對中文分詞時可以實現在詞語之間分詞。

 

常用中文分詞器,IK、jieba、THULAC等,推薦使用IK分詞器。

 

IK分詞器

下載ik分詞器安裝包,版本7.9.1(需要和ES的版本對應)

下載地址://github.com/medcl/elasticsearch-analysis-ik/releases

 

 

                                                                       

安裝

安裝包解壓,在ES的plugins目錄下創建一個ik文件夾,把解壓後的內容放到該文件夾即可。

 

 

驗證

重啟ES,執行如下命令:

POST /_analyze

{

  “analyzer”: “ik_max_word”,  

  “text”: “一名程式設計師”

}

 

 

 

 

ElasticSearch基本API

索引操作

創建索引

官網地址:

//www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html

 

PUT /test

{

       “settings”: {

              “number_of_shards”: “2”,   //分片數

              “number_of_replicas”: “0”,  //副本數

              “write.wait_for_active_shards”: 1 //操作之前必須處於活動狀態的分片分片數

       }

}

 

修改索引

PUT test/_settings

{

    “number_of_replicas” : “2”//修改索引的副本數位2

}

 

刪除索引

DELETE /test

 

文檔操作

插入數據

//指定id

POST /test/_doc/1

{

  “id”:1001,

  “name”:”張三”,

  “age”:20,

  “sex”:”男”

}

 

//不指定id  es幫我們自動生成

POST /test/_doc

{

  “id”:1002,

  “name”:”三哥”,

  “age”:20,

  “sex”:”男”

}

 

更新數據

在Elasticsearch中,文檔數據是不能修改的,但是可以通過覆蓋的方式進行更新

POST /test/_doc/1

{

  “id”:1001,

  “name”:”張三四五”,

  “age”:20,

  “sex”:”男”

}

 

局部更新

其實Elasticsearch內部對局部更新的實際執行和全量替換方式是幾乎一樣的,其步驟如下

1、內部先獲取到對應的文檔;

2、將傳遞過來的field更新到文檔的json中(這一步實質上也是一樣的);

3、將老的文檔標記為deleted(到一定時候才會物理刪除);

4、將修改後的新的文檔創建出來

POST /test/_update/1

{

  “doc”:{

     “age”:46

  }

}

 

刪除數據

DELETE /test/_doc/1

 

根據ID搜索數據

GET /test/_doc/h5a3n3QBhTn7IjwCRtEV

#去掉元數據查詢

GET /test/_source/h5a3n3QBhTn7IjwCRtEV

#去掉元數據並且返回指定欄位

GET /test/_source/h5a3n3QBhTn7IjwCRtEV?_source=id,name 

 

根據屬性查詢

GET /test/_search?q=age:20 //查詢age為20的

 

返回節點說明

 

 

 

took           Elasticsearch運行查詢需要多長時間(以毫秒為單位)

timed_out     搜索請求是否超時

_shards      搜索了多少碎片,並對多少碎片成功、失敗或跳過進行了細分。

max_score    找到最相關的文檔的得分

 

搜索全部數據

 

GET /test/_search //默認最多返回10條數據

GET /test/_search?size=1000 //指定查詢的條數

 

高級檢索

查詢年齡等於23的

POST /test/_search

{

  “query” : {

    “match” : {      

      “age” : 20

    }

  }

}

 

查詢地址是南京市或者上海市的數據

GET /test/_search

{

  “query”: { “match”: { “address”: “南京市 上海市” } }

}

 

查詢地址是(南京市 上海市)的數據

GET /test/_search

{

  “query”: { “match_phrase”: { “address”: “南京市 上海市” } }

}

注意:

match 中如果加空格,那麼會被認為兩個單詞,包含任意一個單詞將被查詢到。

match_parase 將忽略空格,將該字元認為一個整體,會在索引中匹配包含這個整體的文檔。

 

查詢年齡大於20  並且性別是男的

POST /test/_search 

{

  “query”: {

    “bool”: {

      “filter”: {

        “range”: {

            “age”: {

              “gt”: 20

            }

          }

        },

      “must”: {

        “match”: {

          “sex”: “男”

        }

      }

    }

  }

}

 

聚合

avg :平均值

max:最大值

min:最小值

sum:求和

 

查詢前100條數據的年齡平均值

POST /test/_search

{

  “aggs”: {

    “test”: {  

      “avg”: {   

        “field”: “age”  

      }

    }

  },

  “size”: 100

}

 

分頁查詢

from跳過開頭的結果數;size查詢的結果數,默認為10

GET /test/_search?from=1&size=10

 

淺分頁

淺分頁,它的原理很簡單,就是查詢前20條數據,然後截斷前10條,只返回10-20的數據。這樣其實白白浪費了前10條的查詢

GET /test/_search

{

  “sort”: [

    {

      “age”: {

        “order”: “desc”

      }

    }

  ],

  “query”: {

    “match”: {

      “name”: “張三”

    }

  },

  “size”: 10,

  “from”: 0

}

 

scroll 深分頁

scroll 深分頁,使用scroll,每次只能獲取一頁的內容,然後會返回一個scroll_id。根據返回的這個scroll_id可以不斷地獲取下一頁的內容,因為查一次獲取下一頁,所以scroll並不適用於有跳頁的情景

scroll=5m表示設置scroll_id保留5分鐘可用。

使用scroll必須要將from設置為0。

size決定後面每次調用_search搜索返回的數量

GET /test/_search?scroll=5m

{

  “size”: 10,

  “from”: 0,

  “sort”: [

    {

      “_id”: {

        “order”: “desc”

      }

    }

  ]

}

會返回一個:

“_scroll_id” : “FGluY2x1ZGVfY29udGV4dF91dWlkDnF1ZXJ5VGhlbkZldGNoAhRzWmJzbjNRQmhUbjdJandDbWRjMgAAAAAAABHZFlRKaUV2aGRMVEM2LXM1enN6c0dLb0EUc3Bic24zUUJoVG43SWp3Q21kYzIAAAAAAAAR2hZUSmlFdmhkTFRDNi1zNXpzenNHS29B”

以後調用:

GET _search/scroll

{

  “scroll_id”: “FGluY2x1ZGVfY29udGV4dF91dWlkDnF1ZXJ5VGhlbkZldGNoAhRzWmJzbjNRQmhUbjdJandDbWRjMgAAAAAAABHZFlRKaUV2aGRMVEM2LXM1enN6c0dLb0EUc3Bic24zUUJoVG43SWp3Q21kYzIAAAAAAAAR2hZUSmlFdmhkTFRDNi1zNXpzenNHS29B”,

  “scroll”: “5m”

}

刪除scroll_id

DELETE _search/scroll/ FGluY2x1ZGVfY29udGV4dF91dWlkDnF1ZXJ5VGhlbkZldGNoAhRzWmJzbjNRQmhUbjdJandDbWRjMgAAAAAAABHZFlRKaUV2aGRMVEM2LXM1enN6c0dLb0EUc3Bic24zUUJoVG43SWp3Q21kYzIAAAAAAAAR2hZUSmlFdmhkTFRDNi1zNXpzenNHS29B

 

刪除所有scroll_id

DELETE _search/scroll/_all

 

結構化查詢

term查詢

term 主要用於精確匹配哪些值,比如數字,日期,布爾值等

POST /test/_search

{

  “query” : {

    “term” : {

      “age” : 20

    }

  }

}

terms查詢

terms 跟 term 有點類似,但 terms 允許指定多個匹配條件。 如果某個欄位指定了多個值,那麼文檔需要一起去做匹配:

POST /test/_search

{

  “query” : {

    “terms” : {

      “age” : [30,46]

    }

  }

}

 

range查詢

range 過濾允許我們按照指定範圍查找一批數據:

gt      大於

gte     大於等於

lt       小於

lte      小於等於

 

POST /test/_search

{

  “query”: {

    “range”: {

      “age”: {

        “gte”: 25,

        “lte”: 50

      }

    }

  }

}

 

exists查詢

exists 查詢可以用於查找文檔中是否包含指定欄位或沒有某個欄位,類似於SQL語句中的 IS_NULL 條件,包含這個欄位就返回這條數據

POST /test/_search

{

  “query”: {

    “exists”: {

      “field”: “address”

    }

  }

}

 

match查詢

match 查詢是一個標準查詢,不管你需要全文本查詢還是精確查詢基本上都要用到它。如果你使用 match 查詢一個全文本欄位,它會在真正查詢之前先用分詞器去分析一下查詢字元;如果用 match 下指定了一個確切值,在遇到數字,日期,布爾值的字元串時,它將為你搜索你給定的值,不再分詞:

POST /test/_search

{

  “query” : {

    “match” : {    

      “name” : “三個”

    }

  }

}

 

bool查詢

bool 查詢可以用來合併多個條件查詢結果的布爾邏輯,它包含一下操作符:

must       多個查詢條件的完全匹配,相當於 and 。

must_not   多個查詢條件的相反匹配,相當於 not 。

should      至少有一個查詢條件匹配, 相當於 or 。

這些參數可以分別繼承一個查詢條件或者一個查詢條件的數組:

POST /test/_search

{

       “query”: {

              “bool”: {

                     “must”: {

                            “term”: {

                                   “sex”: “男”

                            }

                     },

                     “must_not”: {

                            “term”: {

                                   “age”: “29”

                            }

                     },

                     “should”: [

                       {

                                   “term”: {

                                          “sex”: “男”

                                   }

                            },

                            {

                                   “term”: {

                                          “id”: 1003

                                   }

                            }

                     ]

              }

       }

}

 

 

Elasticsearch整合Springboot

版本對應關係

 

 

由於Elasticsearch版本為7.9.1,所以Springboot版本必須至少為2.3.x,此處採用目前官網最新版本:2.3.4.RELEASE

導入依賴

<parent>

       <groupId>org.springframework.boot</groupId>

       <artifactId>spring-boot-starter-parent</artifactId>

       <version>2.3.4.RELEASE</version>

       <relativePath/>

</parent>

 

<!–elasticsearch包–>

<dependency>

       <groupId>org.springframework.boot</groupId>

       <artifactId>spring-boot-starter-data-elasticsearch</artifactId>

</dependency>

 

<!–單元測試–>

<dependency>

       <groupId>org.springframework.boot</groupId>

       <artifactId>spring-boot-starter-test</artifactId>

       <scope>test</scope>

       <exclusions>

              <exclusion>

                     <groupId>org.junit.vintage</groupId>

                     <artifactId>junit-vintage-engine</artifactId>

              </exclusion>

       </exclusions>

</dependency>

 

配置類

配置類裡面配置了連接ES的連接資訊,相當於配置了一個數據源

import org.elasticsearch.client.RestHighLevelClient;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.data.elasticsearch.client.ClientConfiguration;

import org.springframework.data.elasticsearch.client.RestClients;

import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;

 

@Configuration

public class RestClientConfig extends AbstractElasticsearchConfiguration {

 

    @Override

    @Bean

    public RestHighLevelClient elasticsearchClient() {

        final ClientConfiguration clientConfiguration = ClientConfiguration.builder().connectedTo(“10.0.2.102:9200”)

                .withBasicAuth(“elastic”, “123456”).build();

        return RestClients.create(clientConfiguration).rest();

    }

}

 

創建實體類

實體類上加上Document註解,指定索引名稱和主分片副分片數量,type可以不用指定了,默認一個索引只有一個類型,屬性加上對應的註解,具體屬性和欄位對應關係文檔章節已經說明,請自行參考。

analyzer = “ik_max_word”是指定IK分詞器,說明name欄位分詞的時候需要根據IK分詞器去分詞,不採用ES內置的分詞器,也可以用ES內置的分詞器。

 

 

 

測試

注入elasticsearchRestTemplate

@Autowired

private ElasticsearchRestTemplate elasticsearchRestTemplate;

 

索引創建

/**

 * 創建索引

 */

@Test

public void createIndex() throws Exception {

       IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Item.class);

       boolean exists = indexOperations.exists();

       System.out.println(“索引是否已經存在:”+exists);

}

 

數據新增

/**

 * 測試新增數據

 */

@Test

void save() {

       SimpleDateFormat simpleDateFormat = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);

       String str = simpleDateFormat.format(new Date());

       Goods goods = new Goods(1093l, “”, “測試數據” + str, 37400, 20, 100,

                     “//m.360buyimg.com/mobilecms/s720x720_jfs/t1/10441/9/5525/162976/5c177debEaf815b43/3aa7d4dc182cc4d9.jpg!q70.jpg.webp”,

                     “//m.360buyimg.com/mobilecms/s720x720_jfs/t1/10441/9/5525/162976/5c177debEaf815b43/3aa7d4dc182cc4d9.jpg!q70.jpg.webp”,

                     10, str, str, “10000243333000”, 558, “測試”, “”, “”, 1, 1, 1, 5L);

       /*方法1*/

       Goods save = elasticsearchRestTemplate.save(goods);

       System.out.println(save.toString());

 

       /*方法2*/

       //        IndexQuery indexQuery = new IndexQueryBuilder()

       //                .withId(goods.getId()+””)

       //                .withObject(goods)

       //                .build();

       //        String documentId = elasticsearchRestTemplate.index(indexQuery,IndexCoordinates.of(“goods”));

       //        System.out.println(documentId);

}

 

數據查詢詳情

/**

 * 測試通過ID查詢

 */

@Test

void searchById() {

       Goods goods = elasticsearchRestTemplate.get(“1092”, Goods.class, IndexCoordinates.of(“goods”));

       System.out.println(goods.toString());

}

注意:

查詢的時候如果是根據ID查詢,那麼這個ID指的是文檔id(_id),而且查詢返回的實體裡面的id也是文檔id(分頁查詢返回結果中的實體id也是文檔id),所以最好讓文檔id和業務數據的id保持一致,如果不一致,請注意實體id和ES文檔id類型兼容,因為ES默認生成的文檔id是字元串,如果業務id為long類型的話查詢會報錯。

數據修改

/**

 * 測試修改數據

 */

@Test

void update() {

       Map<String, Object> map = new HashMap<>();

       map.put(“name”, “測試數據修改”);

       UpdateQuery updateQuery = UpdateQuery.builder(“1093”).withDocument(Document.from(map)).build();

       UpdateResponse updateResponse = elasticsearchRestTemplate.update(updateQuery, IndexCoordinates.of(“goods”));

       System.out.println(updateResponse.getResult());

}

 

分頁查詢

/**

 * 分頁查詢

 */

@Test

void getByMatch() {

       MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(“name”, “測試”);

       NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

       //id排序

       FieldSortBuilder sortBuilder = SortBuilders.fieldSort(“id”).order(SortOrder.ASC);

       //分頁

       Pageable pageable = PageRequest.of(0, 10);

       nativeSearchQueryBuilder.withFilter(matchQueryBuilder).withSort(sortBuilder).withPageable(pageable);

       NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();

       SearchHits<Goods> goods = elasticsearchRestTemplate

                     .search(nativeSearchQuery, Goods.class, IndexCoordinates.of(“goods”));

       goods.getSearchHits().forEach(info -> {

              Goods good = info.getContent();

              System.out.println(good.toString());

       });

}