前言
之前寫過一個關(guān)于Elastic Search的文章,當(dāng)時的我還不會使用markdown,還不知道怎么好好把自己所想的,總結(jié)成一個有條理的文章,所以我就想寫下了這一篇新文章,幫助自己消化所學(xué)的東西,也可以把知識分享給大家。
| 使用 | 版本 |
|---|---|
| 操作系統(tǒng) | MacOS |
| ES版本 | 6.3.0 |
| 可視化插件 | Head |
安裝
1.單實例安裝
elasticSearch 的安裝我覺得相對簡單一些,我們可以在官網(wǎng)或者是別的途徑,下載到它,官網(wǎng)的下載地址為https://www.elastic.co/downloads/elasticsearch,當(dāng)前最新的版本為6.4.2。而我使用的版本是6.3.0,如果想要下載到原來版本的ES,可以進入以下網(wǎng)址進行下載https://www.elastic.co/downloads/past-releases。
下載好后,執(zhí)行bin目錄下的elasticsearch即可。
啟動后,在瀏覽器輸入http://localhost:9200/即可,效果如下:

2.Head插件安裝
Head插件是依托于node環(huán)境的,我們在使用插件之前需要先下載node.js。node.js下載好后,通過node -v 查看是否安裝成功,然后就可以通過以下網(wǎng)址下載Head插件。Head 插件地址。下載好Head插件以及elasticsearch后,需要修改在elasticsearch 中的config的elasticsearch.yml中加上以下配置內(nèi)容:
http.cors.enabled: true
http.cors.allow-original: "*"
保證了Es以及Head插件的連通性。
Head插件的啟動
1.npm install phantomjs-prebuilt@2.1.15 --ignore-scripts(之所以不使用npm install 是因為這個包,一直都取不到,但是它也不怎么影響使用。)
2.npm install
3.npm run start
啟動后,在瀏覽器輸入http://localhost:9100,如果顯示了相關(guān)內(nèi)容即可。
3.分布式安裝
分布式的安裝和單實例安裝大同小異,把下載下來的ElasticSearch復(fù)制兩個副本,放在新創(chuàng)建的目錄ES_slave(slave為隨從奴隸的意思,在這里把我們之前安裝好的當(dāng)做一個master,然后其他的slave配合master形成一套分布式)中,如下圖所示:

這里是創(chuàng)建了兩個,如果有需求,可以根據(jù)需求繼續(xù)拓展。
然后把兩個slave中的elasticsearch.yml文件進行修改,加入以下配置:
#配置ElasticSearch的集群名稱
cluster.name: harry
#節(jié)點的名稱(另一個節(jié)點名稱可以使用slave2)
node.name: slave1
#設(shè)置綁定的IP地址
network.host: 127.0.0.1
#設(shè)置對外服務(wù)的端口號,默認(rèn)情況下為9200(這里只要使用沒被使用的端口號即可)
http.port: 8200
#設(shè)置是否打開多播發(fā)現(xiàn)節(jié)點,如果不進行配置,不會被主節(jié)點發(fā)現(xiàn)。
discovery.zen.ping.unicast.hosts: ["127.0.0.1"]
配置好后,啟動slave的elasticsearch即可。
Tips:我啟動的時候報了一個錯誤。
[2018-10-07T11:57:44,907][INFO ][o.e.d.z.ZenDiscovery ] [slave1] failed to
send join request to master [{master}{dLNpAPsSTvCFgzow1nuM6g}
{lZIG2Xm3Sx-4Y4eHU5x9CA}{127.0.0.1}{127.0.0.1:9300}
{ml.machine_memory=8589934592, ml.max_open_jobs=20,
xpack.installed=true, ml.enabled=true}], reason
[RemoteTransportException[[master][127.0.0.1:9300]
[internal:discovery/zen/join]]; nested: IllegalArgumentException[can't add node
{slave1}{dLNpAPsSTvCFgzow1nuM6g}{4NUyj79cSxuaJL8BMtGejw}{127.0.0.1}
{127.0.0.1:9301}{ml.machine_memory=8589934592, ml.max_open_jobs=20,
xpack.installed=true, ml.enabled=true}, found existing node {master}
{dLNpAPsSTvCFgzow1nuM6g}{lZIG2Xm3Sx-4Y4eHU5x9CA}{127.0.0.1}
{127.0.0.1:9300}{ml.machine_memory=8589934592, xpack.installed=true,
ml.max_open_jobs=20, ml.enabled=true} with the same id but is a different
node instance]; ]
因為我是把master的Es復(fù)制過來,作為slave,但是data中還有原來的數(shù)據(jù),所以報了這個錯,只要把,Es中的data文件夾中的東西都刪除就行。
我們現(xiàn)在把master 的ES啟動,slave1的ES啟動,slave2的ES啟動,最后把Head也啟動起來,然后瀏覽器輸入http://localhost:9100,效果如下,證明成功。

基本概念
1.索引,類型,文檔
Elastic Search 與關(guān)系型數(shù)據(jù)庫對比
| Elastic Search | 關(guān)系型數(shù)據(jù)庫 |
|---|---|
| 索引:index | 數(shù)據(jù)庫 |
| 類型:type | 表 |
| 文檔:document | 行 |
tips:在elastic search 6.0之后的版本已經(jīng)對type 這個概念逐漸淡化。
所以把索引比作數(shù)據(jù)庫中的表,文檔比作行更為恰當(dāng)。
在官方文檔中我們看到這樣一席話:
Indices created in Elasticsearch 6.0.0 or later may only contain a single mapping type. Indices created in 5.x with multiple mapping types will continue to function as before in Elasticsearch 6.x. Mapping types will be completely removed in Elasticsearch 7.0.0.更詳細(xì)的地址
這里的Elastic Search 泛指的是全文檢索。一個索引中,包含多個類型,一個類型中包含著多個文檔。
在剛接觸的時候,我想過這樣一個問題,在關(guān)系型數(shù)據(jù)庫mysql的like進行模糊查詢的效果,與Elastic Search這樣的全文檢索,效果幾乎就是一樣的,那為什么還要用全文檢索呢?
原因我覺得一共有兩個:
第一個是查詢的速度特別快。在關(guān)系型數(shù)據(jù)庫中,數(shù)據(jù)是結(jié)構(gòu)化的,我們當(dāng)要進行模糊查詢的時候,會從想要查詢的表的第一條數(shù)據(jù)開始比對,如果不是,繼續(xù)下一條,如果再不是,繼續(xù)去查,就這樣一直查下去,直到查到了,自己想要的那條數(shù)據(jù)。而Elastic Search呢?它其實使用了倒排索引。大概意思其實是這樣的:現(xiàn)在一個有三篇文章
| id | content |
|---|---|
| 文章1 | Java是世界上最好的 . |
| 文章2 | 人生苦短,快學(xué)python |
| 文章3 | C++是世界上最難的 . |
這也是存儲在關(guān)系型數(shù)據(jù)庫中的存儲形式,查詢的話,他會一行行的進行查詢。而如果存在了Elastic Search 中會變成什么樣子呢?在全文檢索中存在這分詞器這么個東西,分詞器會把輸入的句子自動的進行一定規(guī)律進行分割,例如過空格分割,下劃線分割,等等。如果是中文,也有插件可以對其進行語義分割。分割后的效果如下所示(只是舉例子,真實情況未必如此)
| 關(guān)鍵詞 | 文章號 |
|---|---|
| 世界 | 1,3 |
| 人生苦短 | 2 . |
| Java | 1 . |
| python | 2 |
| C++ | 3 |
當(dāng)我們輸入世界,立刻就知道出現(xiàn)在了第一個,和第三個文章中。
第二個是因為我們在做全文檢索的時候,根本用不到那么復(fù)雜的邏輯,我們用到基礎(chǔ)的增刪改查就行,使用了Elastic Search 之后,我們在也不用折騰數(shù)據(jù)庫那么多的數(shù)據(jù)了。
2.分片與索引
每一個索引包含了多個分片,每個分片是一個lucene索引(lucene是Elasticsearch的底層引擎。)只需要將分片拷貝一份,就完成了分片的備份。
3.集群和節(jié)點
每一個集群都有一個集群的名字,一個集群包含多個節(jié)點。我們只需要知道集群的名稱,便可以拓展集群中的節(jié)點。
4.elasticsearch.yml
我上面在啟動head插件和設(shè)置分布式集群的時候,有修改過這個文件,但是這個文件還有別的可配置屬性,我在這里說明一下,以備不時之需。
cluster.name: elasticsearch
#設(shè)置集群名稱,一個集群只可以有一個名稱,ElasticSearch會自己去查找同一個網(wǎng)段下的所有節(jié)點
node.name: node-1
#設(shè)置節(jié)點名稱
node.master: true
#設(shè)置該節(jié)點是否是master節(jié)點,默認(rèn)為true
node.data: true
#設(shè)置該節(jié)點,是否存儲索引數(shù)據(jù),默認(rèn)為true
index.number_of_shards: 5
#設(shè)置分片的數(shù)量,默認(rèn)為5個,這個配置只在5.0版本之前好用
index.number_of_replicas: 1
#設(shè)置索引副本數(shù)量,默認(rèn)為一個,同樣也是只在5.0之前好用。
path.data: /path/to/data
#設(shè)置索引數(shù)據(jù)的存儲路徑,默認(rèn)在data文件夾下,可以設(shè)置多個文件存儲路徑,用逗號分隔。
path.logs: /path/to/logs
#設(shè)置log日志的存儲路徑,默認(rèn)情況下是在logs文件夾下。
bootstrap.mlockall: true
#設(shè)置為true來鎖住內(nèi)存
network.host: 0.0.0.0
#設(shè)置綁定的Ip地址,默認(rèn)為0.0.0.0
http.port: 9200
#設(shè)置對外服務(wù)的HTTP端口號
transport.tcp.port: 9300
#設(shè)置節(jié)點間交互的TCP端口號,也是給Java API使用的端口號,默認(rèn)是9300。
transport.tcp.compress: false
#是否壓縮TCP傳輸?shù)臄?shù)據(jù),默認(rèn)為false
http.cors.enabled:true
#是否使用http提供對外的服務(wù),默認(rèn)為true
http.max_content_length: 100mb
#http傳輸內(nèi)容的最大容量。
discovery.zen.minimum_master_nodes: 1
#發(fā)現(xiàn)master節(jié)點的數(shù)量,默認(rèn)為1個。
discovery.zen.ping.timeout: 3s
#發(fā)現(xiàn)其他節(jié)點,超時的時間。
discovery.zen.ping.multicast.enabled:true
#是否打開多播發(fā)現(xiàn)節(jié)點。
discovery.zen.ping.unicast.hosts:["host1","host2:port","host3:[portX-portY]"]
#設(shè)置集群master幾點的初始列表。
script.engine.groovy.inline.update: on
#開啟groovy腳本的支持
script.inline: true
#開始所有腳本語言行內(nèi)執(zhí)行所有的操作。
基本用法
Elastic Search 我們可以使用REST API與其進行交互,說白了就是使用url地址,通過不同的method(get,post,put,delete)傳入不同的json數(shù)據(jù)。
head插件雖然很好,但是也并不是萬能的,我比較習(xí)慣用Post man進行api交互。下面講講具體的操作。
1.創(chuàng)建索引
| url地址 | method | 用途 |
|---|---|---|
| localhost:9200/索引名稱 | put | 創(chuàng)建索引 |
在創(chuàng)建索引之前,我要先說兩個概念分別是靜態(tài)映射和動態(tài)映射。
動態(tài)映射是在創(chuàng)建索引之初,不添加索引的類型和文檔中屬性的格式,而是在添加文檔的時候,格式會被自動轉(zhuǎn)化。兩種不同映射的設(shè)置,是由dynamic參數(shù)來決定的一共有三個可選值:
- true 動態(tài)映射自動添加字段
- false 靜態(tài)映射,不會自動添加字段
- strict 靜態(tài)映射,如果添加了新字段會報錯
動態(tài)轉(zhuǎn)換內(nèi)容如下:
| JSON格式的數(shù)據(jù) | 自動推測的字段類型 |
|---|---|
| null | 沒有字段被添加 |
| true or false | boolean |
| 浮點類型數(shù)字 | float |
| 數(shù)字 | long |
| JSON對象 | object |
| 數(shù)組 | 有數(shù)組中第一個非空值決定 |
| string | 有可能是date類型(開啟日企檢測),double,long,text,keyword |
動態(tài)映射json體:
{
"settings":{
"number_of_shards":3,
"number_of_replicas":1
}
}
number_of_shards是用來設(shè)置分片數(shù)量的
number_of_replicas是用來設(shè)置副本數(shù)量的
靜態(tài)映射Json體:
{
"settings":{
"number_of_shards":3,
"number_of_replicas":1
},
"mappings":{
"it": {
"dynamic":"strict",
"properties":{
"title":{
"type":"text"
},
"content":{
"type":"text"
},
"create_date":{
"type":"date"
}
}
}
}
}
這里的it指的就是類型,在properties中添加自己的字段,并且指定屬性的類型。
另外發(fā)送請求的content-type一定得是application/json,這個值得注意,成功后,會返回一個屬性acknowledged 是true的,就說明創(chuàng)建成功,其他的如下圖(Tips:幾個更換 json體,這里的截圖只是一個示范):

查看head插件,如下圖

我們可以看到這里創(chuàng)建了三個分片(細(xì)線為粗線的副本)。
2.插入文檔
| url地址 | method | 用途 |
|---|---|---|
| localhost:9200/索引名稱/類型名稱/文檔id | put | 創(chuàng)建文檔(指定文檔id) |
| localhost:9200/索引名稱/類型名稱 | post | 創(chuàng)建文檔(隨機文檔id) |
3.修改文檔
| url地址 | method | 用途 |
|---|---|---|
| localhost:9200/索引名稱/類型名稱/文檔id/_update | post | 修改文檔 |
json體:
{
"doc":{
"修改字段名稱": "想要修改成的值"
}
}
4.刪除文檔
| url地址 | method | 用途 |
|---|---|---|
| localhost:9200/索引名稱/類型名稱/文檔id | delete | 刪除文檔 |
5.查詢文檔
這里先介紹簡單的查詢,復(fù)雜的地方,會在后面說到。
| url地址 | method | 用途 |
|---|---|---|
| localhost:9200/索引名稱/類型名稱/文檔id | get | 查詢文檔通過文檔id |
| localhost:9200/索引名稱/類型名稱/_search | post | 查詢所有數(shù)據(jù) |
簡單查詢數(shù)據(jù)結(jié)構(gòu)體為
{
"query":{
"match_all":{},(通過該屬性查詢所有數(shù)據(jù))
"match":{
"需要查詢的字段名稱":"查詢的值"
}
},
"from": "從第幾個開始"(可選),
"size": "要查詢多少個"(可選) ,
"sort": [
{"字段名稱":{"order": "desc 或者是 asc"}}(自定義排序,默認(rèn)通過score元字段進行排序)
]
}
聚合查詢結(jié)構(gòu)體為:
(可以定義多個聚合條件,放在不同的聚合名稱中)
{
"aggs":{
"聚合名稱1(自定義)": {
"terms":{
"field": "通過該字段進行聚合"
},
"status":{
"field": "通過該字段進行聚合"(status key可以計算這個聚合的相關(guān)參數(shù))
}
},
"聚合名稱2(自定義)": {
"terms":{
"field": "通過該字段進行聚合"
}
}
}
}
后記
這篇文章是學(xué)習(xí)了慕課網(wǎng)上瓦力老師的教程并參考《從lucene到Elasticsearch全文檢索實戰(zhàn)》所寫,課程地址為https://www.imooc.com/learn/889,在此感謝你們的分享,我會在后續(xù)的文章中繼續(xù)總結(jié)elasticsearch的更多查詢語法,以及Spring Boot 集成 Elastic Search 的相關(guān)知識。