1. 程式人生 > >Elasticsearch構建全文搜尋系統

Elasticsearch構建全文搜尋系統

[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