Elasticsearch構建全文搜尋系統
阿新 • • 發佈:2020-03-15
[toc]
# 前言
Elasticsearch 是一個分散式、可擴充套件、實時的搜尋與資料分析引擎,通過它我們可以構建出一個強大的全文搜尋系統,解決諸如文章檢索慢,商品檢索慢、MySQL的like查詢慢這樣的問題。
Elasticsearch是基於hadoop創始人道哥的另一傑作Lucene實現的,速度非常快,核心是使用了倒排索引這樣的結構。關於倒排索引是什麼,可以參考[搜尋引擎中的倒排索引是什麼](https://www.cnblogs.com/chenqionghe/p/12464671.html)
接下來,就以這篇倒排索引中的例子,演示一下ElasticSearch的使用
假設我們有海量文章,如下
頁碼 | 內容
-|-|
1| 生命在於運動 |
2| 運動是生命的源泉|
3| 日復一日地堅持練下去吧,只有活動適量才能保持訓練的熱情和提高運動的技能.——塞涅卡 |
4 | 活動是生活的基礎!——歌德 |
5| 人的健全,不但靠飲食,尤靠運動 |
6| 奧林匹克的格言是“更高,更快,更強” |
7| 身體的健康因靜止不動而破壞,因運動練習而長期保持.——蘇格拉底|
8| chenqionghe喜歡運動,繩命是如此的精彩,繩命是如此的輝煌|
我們想像這是千萬級別的表,最後需要實現傳入關鍵字,返回相應的文章
例如:搜尋`運動`返回頁碼`1,2,3,5,7,8`對應的文章、搜尋`chenqionghe`返回頁碼為`8`的文章
# 一、安裝
## 1.安裝es
檢視[官網地址](https://www.elastic.co/cn/downloads/elasticsearch),直接下載安裝就行了,我用的是mac直接下了mac版本的,另外也可以使用[dokcer安裝](https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html)
解壓後長這樣
![](https://img2020.cnblogs.com/blog/662544/202003/662544-20200315121158088-1387246598.png)
es依賴java環境,需要指定jdk版本,我們加入一下java相關環境變數
```
export JAVA_HOME=/Users/chenqionghe/web/elk/elasticsearch-7.6.1/jdk.app/Contents/Home/
export PATH=$JAVA_HOME/bin:$PATH
```
啟動一下看看
```
./bin/elasticsearch
```
看到啟動報錯
```
uncaught exception in thread [main]
ElasticsearchException[Failure running machine learning native code. This could be due to running on an unsupported OS or distribution, missing OS libraries, or a problem with the temp directory. To bypass this problem by running Elasticsearch without machine learning functionality set [xpack.ml.enabled: false].]
```
解決辦法,修改`./config/elasticsearch.yml`新增
```
xpack.ml.enabled: false
```
再次啟動,成功執行,畫風如下
![](https://img2020.cnblogs.com/blog/662544/202003/662544-20200315121208657-929502035.png)
預設啟動的是9200埠,我們來測試一下
```
➜ ~ curl localhost:9200
```
可以看到,es可以正常執行起來了
![](https://img2020.cnblogs.com/blog/662544/202003/662544-20200315121216533-1014285671.png)
## 2.啟動叢集
一般es都是以叢集的方式存在,接下我們演示一下啟動叢集。
編輯`./config/elasticsearch.yml`,指定叢集名稱,叢集名稱我指定成了chenqionghe
```
cluster.name: chenqionghe
```
指定節點名稱
```
ode.name: chenqionghe-1
```
設定初始化的節點
```
cluster.initial_master_nodes: ["chenqionghe-1"]
```
設定監聽的埠,這裡不限定ip,指定為0.0.0.0
```
network.host: 0.0.0.0
```
埠預設9200
```
http.port: 9200
```
新增支援elasticsearch-head介面引數
```
http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-methods: OPTIONS, HEAD, GET, POST, PUT, DELETE
http.cors.allow-headers: "X-Requested-With, Content-Type, Content-Length, X-User"
```
再次啟動
```
./bin/elasticsearch
```
## 3.安裝管理介面
elasticsearch-head可以很方便的檢視es叢集狀態,檢視官網地址:[elasticsearch-head](https://github.com/mobz/elasticsearch-head)
```
git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install
npm run start
```
開啟http://localhost:9100/,如下
![](https://img2020.cnblogs.com/blog/662544/202003/662544-20200315121232262-345797038.png)
## 4.安裝分詞外掛
外掛我們使用的是elasticsearch-analysis-ik,參考地址:[elasticsearch-analysis-ik/](https://github.com/medcl/elasticsearch-analysis-ik/)
```
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.6.1/elasticsearch-analysis-ik-7.6.1.zip
```
驗證一下分外掛
```
curl -X POST "localhost:9200/_analyze?pretty" -H 'Content-Type: application/json' -d '{ "analyzer": "ik_smart", "text": "chenqionghe徒手健身" }'
```
![](https://img2020.cnblogs.com/blog/662544/202003/662544-20200315121241769-1518906183.png)
可以看到,已經可以分詞了,oh yeah~
# 二、使用
ES中有index、document、filed、mapping這樣的概念,我們以MySQL的結構為參考對照一下,如下
ElasticSearch | MySQL |
-|-|
Iindex| 表 |
document | 行 |
field | 列 |
mapping| 表結構 |
Elasticsearch主要還是使用API,具體使用請參考:[Document APIs](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs.html)
## 1.建立索引
這裡index我取名叫book
```
➜ ~ curl -X PUT "localhost:9200/book" -H 'Content-Type: application/json' -d '{
"mappings": {
"properties": {
"page": {
"type": "long"
},
"content": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
}
}
}
}'
{"acknowledged":true,"shards_acknowledged":true,"index":"book"}
```
建立成功,但是檢視head介面,但是這個黃色不怎麼優雅呀,原因是雖然啟用了叢集,但是還是單節點執行的,群集無法放置副本。
![](https://img2020.cnblogs.com/blog/662544/202003/662544-20200315121250044-1787264960.png)
叢集的健康狀況為 yellow 則表示全部主分片(number_of_shards)都正常執行,但是副本分片沒有全部處在正常狀態,單節點無論有多少個副本分片(number_of_replicas)都是 unassigned ,它們都沒有被分配到任何節點。
在同一個節點上既儲存原始資料又儲存副本是沒有意義的,因為一旦失去了那個節點,我們也將丟失該節點上的所有副本資料。
我們需要把這個副本設定為0,因為索引一旦建立,分片數量不能變,我們需要刪除再重新建立一下索引
```
curl -XDELETE http://localhost:9200/book
curl -X PUT "localhost:9200/book" -H 'Content-Type: application/json' -d '{
"settings":{
"number_of_shards": "1",
"number_of_replicas": "0"
},
"mappings": {
"properties": {
"page": {
"type": "long"
},
"content": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
}
}
}
}'
```
再次檢視,健康了
![](https://img2020.cnblogs.com/blog/662544/202003/662544-20200315121259943-1586110094.png)
## 2.插入資料
```
curl -X POST "localhost:9200/book/_doc/" -H 'Content-Type: application/json' -d '{
"page":1,
"content": "生命在於運動"
}'
```
我們可以看到已經成功插入一條資料
![](https://img2020.cnblogs.com/blog/662544/202003/662544-20200315121307920-119753340.png)
## 3.批量插入資料
```
curl -X POST "localhost:9200/book/_doc/_bulk?pretty" -H 'Content-Type: application/json' -d'
{ "index":{} }
{ "page":2 , "content": "運動是生命的源泉"}
{ "index":{} }
{ "page":3 , "content": "日復一日地堅持練下去吧,只有活動適量才能保持訓練的熱情和提高運動的技能.——塞涅卡"}
{ "index":{} }
{ "page":4 , "content": "活動是生活的基礎!——歌德"}
{ "index":{} }
{ "page":5 , "content": "人的健全,不但靠飲食,尤靠運動"}
{ "index":{} }
{ "page":6 , "content": "奧林匹克的格言是“更高,更快,更強”"}
{ "index":{} }
{ "page":7 , "content": "身體的健康因靜止不動而破壞,因運動練習而長期保持.——蘇格拉底"}
{ "index":{} }
{ "page":8 , "content": "chenqionghe喜歡運動,繩命是如此的精彩,繩命是如此的輝煌"}
'
```
可以看到成功批量插入
![](https://img2020.cnblogs.com/blog/662544/202003/662544-20200315121315595-727201784.png)
## 4.查詢資料
* 搜尋`chenqionghe`
```
curl -s -X GET 'localhost:9200/book/_search?pretty' -H 'Content-Type: application/json' -d '{
"query" : { "match" : { "content" : "chenqionghe" }}
}'|jq
```
可以看到匹配到了
![](https://img2020.cnblogs.com/blog/662544/202003/662544-20200315121336104-1253296038.png)
* 搜尋`運動`,應該是會返回`1,2,3,5,7,8`這幾條
```
curl -s -XGET 'localhost:9200/book/_search?pretty' -H 'Content-Type: application/json' -d '{
"query" : { "match" : { "content" : "運動" }}
}'|jq .hits.hits|jq '.[]._source'
```
可以看到,驗證通過
![](https://img2020.cnblogs.com/blog/662544/202003/662544-20200315121343026-1019607932.png)
## 5.修改資料
拉下來,我們將chenqionghe這條記錄的`繩命`改為`生命`,
```
curl -X POST "localhost:9200/book/_doc/HFn_2XABkofzJYzpQIy4" -H 'Content-Type: application/json' -d '{
"page":8,
"content": "chenqionghe喜歡運動,生命是如此的精彩,生命是如此的輝煌"
}'
```
可以看到,更新成功
![](https://img2020.cnblogs.com/blog/662544/202003/662544-20200315121350113-2124928207.png)
## 6.刪除資料
* 根據id刪除
```
curl -X DELETE "localhost:9200/book/_doc/GFn_2XABkofzJYzpQIy4"
```
* 根據條件刪除
```
curl -X POST "localhost:9200/book/_delete_by_query?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match": {
"content": "chenqionghe"
}
}
}
'
```
## 7.索引關閉和開啟
如果關閉了一個索引,就無法通過ES來讀取和寫入其中的資料,直到道再次開啟它
```
# 關閉
curl -XPOST 'localhost:9200/book/_close'
# 開啟
curl -XPOST 'localhost:9200/book/_open'
```
# 總結
通過Elasticsearch,我們可以快速構建出一個強大的全文搜尋系統,安裝簡單,通過API使用也簡單。
倒排索引為搜尋而生,先對需要索引的欄位進行分詞,再通過詞直接匹配出文件,速度非常快,這是優點。但是,相比資料庫採用的 B 樹索引,它的寫入和更新效能都比較差,因此倒排索引也只是適合全文搜尋,不適合更新頻繁的交易類資料。
總之,安裝使用Elasticsearch其實就是這麼簡單,驚不驚喜,意不意外呀,light weight baby!
更多資料請參考 :[Eelasticsearch權威指南](https://www.elastic.co/guide/cn/elasticsearch/guide/cn/prefac