這是一篇結(jié)合實戰(zhàn)教同學快速入門使用Elasticsearch 解決實際業(yè)務場景的問題.
如果你還在用 sql like %xxx%
的方式進行內(nèi)容的全文搜索,很可能DBA或者老大就要找你去聊天了, 以mysql innodb引擎為例, 這種寫法將會進行十分低效全文檢索,而且不會使用索引.
接下來全文將 elasticsearch 簡稱為ES.
那么,本文將通過將之前在Flask框架上使用的社區(qū)搜索接口從like %xxx%
的寫法改成ES做全文索引,觀察是否會存在顯著的性能提升(如果不能提升,是否還有其他改進的方式),先看下從0-1怎么快速實現(xiàn).
看了其他的講實現(xiàn)的文章中都是把相關(guān)組件或者ES的文檔代碼直接貼過來,個人認為這些都是會存在升級以及文檔變更的可能,為了使用最新的api以及特性還是建議讀者花幾分鐘讀完文章中的外鏈文檔地址.
- ES是什么? 怎么玩?
- 地域問題,中文文章的分詞怎么整?
- 業(yè)務的實現(xiàn)
- 線上環(huán)境的部署與監(jiān)控(服務的穩(wěn)定性)
ES是什么? 怎么玩?
ES簡單的中文入門,在上線之前需要現(xiàn)在本地以及測試環(huán)境跑的溜,筆者本機是MacOS系統(tǒng),所以采用比較快捷的Homebrew的安裝方式
brew install elasticsearch
再根據(jù)文檔安裝了瀏覽器級的control工具sense,按著教程稍微跑一下教程之后就可以進入了正題. 有些朋友想吐槽ES快速入門太簡單了,畢竟是實戰(zhàn)導向的快速入門,把重點放在ES與業(yè)務結(jié)合的實現(xiàn).
地域問題,中文文章的分詞怎么整
如果筆者讀了上段寫的中文入門教程,會發(fā)現(xiàn)ES已經(jīng)提供英文搜索模糊匹配的功能,至于ES是怎么實現(xiàn)的,感興趣的讀者可以再深入查閱資料.這時候為了支持中文搜索我們需要安裝插件到ES目錄中的plugins文件夾中$ES_HOME/plugins/
. ik插件的github地址,按著文檔安裝之后可以跑一下里面的測試請求,驗證中國
的分詞查詢是有效的.ik插件的在analyzer和search_analyzer上有兩種配置:
- ik_max_word: 會將文本做最細粒度的拆分,比如會將“中華人民共和國國歌”拆分為“中華人民共和國,中華人民,中華,華人,人民共和國,人民,人,民,共和國,共和,和,國國,國歌”邮丰,會窮盡各種可能的組合梆靖;
- ik_smart: 會做最粗粒度的拆分,比如會將“中華人民共和國國歌”拆分為“中華人民共和國,國歌”焚碌。
核心的分詞問題就這樣解決了,在大批量的文章中是否會存在性能問題需要在實戰(zhàn)中驗證,接下來我們要做的事情就是將之前有的文章導入到ES中以及為新的文章建立文檔,這些要做的事情都將通過調(diào)用ES提供的api完成.
業(yè)務的實現(xiàn)
Elasticsearch 集群可以包含多個索引(Index),每個索引可以包含多個類型(Type),每個類型可以包含多個文檔(Document)育苟,每個文檔可以包含多個字段(Field)筹裕。以下是 MySQL 和 Elasticsearch 的術(shù)語類比圖鸠按,幫助理解:
MySQL | Elasticsearch |
---|---|
Database | Index |
Table | Type |
Row | Document |
Column | Field |
Schema | Mappping |
Index | Everything Indexed by default |
SQL | Query DSL |
就像使用 MySQL 必須指定 Database 一樣,要使用 Elasticsearch 首先需要創(chuàng)建 Index,這邊我們?yōu)樯鐓^(qū)文章創(chuàng)建index: forum-index
,以及type:post
ES提供了一套增刪改查的api,我們可以在SENSE模板中使用簡化API來測試驗證有效性,但是在后端開發(fā)中根據(jù)不同語言以及框架一般有已經(jīng)封裝好的庫可以直接配置使用,筆者這邊使用的是python的庫elasticsearch-dsl-py,如果您使用的是其他語言或者框架,上github上搜索一下有沒有封裝過的框架(記得要看是否版本匹配).在進行下一步之前,我們捋一下我們要做的事情,將原有的社區(qū)文章導入type
,根據(jù)提供給客戶端以及后臺的查詢功能加入對應匹配的字段,新增文章時需要加入ES中,編輯文章后需要修改ES中對應文檔的內(nèi)容,以及文章下架后要將文章從ES中移除.增刪改這些額外的ES操作會有額外的時間消耗以及失敗的可能,為了不影響接口可以將操作封裝放入隊列異步執(zhí)行,保證最終一致執(zhí)行便可.ES查詢性能與穩(wěn)定性的優(yōu)化等先調(diào)通基礎(chǔ)功能與接口后再考慮.
這是導入原有帖子數(shù)據(jù)后在sense console
上執(zhí)行以下模糊查詢語句與對應的返回:
GET /forum-index/post/_search
{
"query": {
"bool": {
"should": [
{ "match": { "content": "客戶端" }},
{ "match": { "title": "客戶端" }},
{ "match": { "summary": "客戶端" }}
]
}
}
}
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 19,
"max_score": 25.630516,
"hits": [
{
"_index": "forum-index",
"_type": "post",
"_id": "60000000012672",
"_score": 25.630516,
"_source": {
"user_id": 10144,
"title": "客戶端發(fā)帖測試",
"summary": "客戶端發(fā)帖測試內(nèi)容",
"content": """
客戶端發(fā)帖測試內(nèi)容
<img data-src="3f2b7dd51ddcb7d66b22f0f06645f16e.png" src="http://img-cn-hangzhou.aliyuncs.com/nb-imgs/3f2b7dd51ddcb7d66b22f0f06645f16e.png">
<br/>
</img>
""",
"last_modify": 1480665329,
"id": 60000000012672
}
},
...
返回json格式的數(shù)據(jù)中,took,_score,...
等等很多字段這個是什么意思呢?
可以參考官文說明.這邊也簡單說明下:
- took – time in milliseconds for Elasticsearch to execute the search
- timed_out – tells us if the search timed out or not
- _shards – tells us how many shards were searched, as well as a count of the successful/failed searched shards
- hits – search results
- hits.total – total number of documents matching our search criteria
- hits.hits – actual array of search results (defaults to first 10 documents)
- hits.sort - sort key for results (missing if sorting by score)
- hits._score and max_score - ignore these fields for now
這邊可以看到,在本地環(huán)境5000+的帖子文檔分詞查詢,消耗時間為4ms,算是一個非常不錯的結(jié)果了.將復雜的查詢功能使用ES來實現(xiàn),可以有效減少數(shù)據(jù)庫的請求壓力,接下來我們可以致力于優(yōu)化ES的使用以及查詢.按目前評估ES可以勝任生產(chǎn)級別的全文檢索服務.
線上環(huán)境的部署與監(jiān)控(服務的穩(wěn)定性)
由于工作調(diào)用的原因筆者很遺憾的沒有去實現(xiàn)完成最后這一步,但是可以大致說一下思路,線上部署配置后,可以使用supervisor等服務守護程序去保證服務的穩(wěn)定性,并做好性能壓測,為保證服務的持續(xù)可用建議部署上ES的集群.單個節(jié)點異常的時候也能保證線上服務的持續(xù).
總結(jié)
通過這次的學習發(fā)現(xiàn)ES是個強大好用的工具,目前比較流行的有用ELK進行日志分析(ElasticSearch + Logstash + Kibana),這邊僅僅是為讀者們打開了冰山的一角,繼續(xù)學習,與君共勉!