簡介
ES是一款基于Lucene實現(xiàn)的一款分布式搜索引擎,它有以下優(yōu)點
- 快
- Restful API,接入不需要編程語言支持
- 數(shù)據(jù)安全(主從)
- 功能豐富
- 接近實施的更新
Lucene
Lucene是一個由Java實現(xiàn)的搜索引擎,接下來簡要介紹下它的原理
1.倒排索引
倒排索引是搜索引擎常用的一種索引方式。
它十分簡單,首先將需要索引的語句進行分詞,然后以每個詞為key,需要索引的語句為value放入一個"MAP"中.
這里MAP之所以打引號,是因為我們不去限制這個MAP的實現(xiàn)方法,他可以用任意實現(xiàn),比如紅黑樹,hash或者之后會介紹的FST。
舉個例子:
需要索引的句子:
1.ElasticSearch 學習筆記
2.ElasticSearch 牛逼
倒排索引:
"ElasticSearch" : [1,2],
"學習" :[1]
"筆記" : [1]
"牛逼" : [2]
通過倒排索引,我們就能通過單個當詞語查詢到句子。
2.FST
FST全稱是Finite State Transducer,
單從字面上看它類似于有限自動機,但實際可以把它看作一個壓縮過但字典樹,
字典樹會對詞語對前綴進行合并,而FST還會對詞語對后綴進行合并。
我們以mon,thurs,tues三個詞為例,
FST和字典樹的結(jié)構(gòu)分別如下:


優(yōu)點:內(nèi)存占用率低,壓縮率一般在3倍~20倍之間、模糊查詢支持好、查詢快
缺點:結(jié)構(gòu)復雜、輸入要求有序、更新不易
如何構(gòu)建一個FST?
- 將所有的句子按照字典序進行排序
- 將句子先按照字典樹的方式插入
- 如果確定有相同的后綴,則進行鏈接。
具體原理可參考:https://www.shenyanchao.cn/blog/2018/12/04/lucene-fst/
3.怎么存儲倒排索引?(猜的)
一部分緩存在內(nèi)存,一部分存在硬盤。
當FST當一個前綴有超過一定數(shù)量當后綴則放到內(nèi)存中,否則存入磁盤。
真的是這樣??
ES 與 Lucene 當關系
ES 的結(jié)構(gòu)
ES是一個分布式服務,它由n個分片和m個備份構(gòu)成,分片(P)和備份(R)被分配在不同的機器(Node)上,

分片
一個分片里指存儲了部分集群信息,具體存哪些則根據(jù)文檔的routing字段決定(默認就是_id)
而一個分片上包含以下結(jié)構(gòu):
- 多個段(你可以把段理解為倒排索引)
- commit point,用于找到多個段
- In-memory buffer,用來收集更新信息
- transLog,類似與mysql的binLog,用于記錄更新操作

為什么要有多個段?
一個段相當于一個Lucene,那為什么要有多個段?
因為Lucene的倒排索引采用FST實現(xiàn),F(xiàn)ST雖然高效,并且內(nèi)存利用率高,但是更新困難。因此與其每次花大代價去更新原來的段,不如每次都新建一個段,之后索引時,遍歷所有的段,并得出搜索結(jié)果。
但是這樣做有兩個問題:
- 隨著段越來越多,搜索的效率會大大降低。
- 寫入一個新的段需要IO操作,因此如果頻繁寫入,那么效率底下。
為了解決問題1,ES啟動了一個后臺的合并任務,他會在空閑時把這些段合并成一個大段。(類似于LevelDB的level合并機制)
為了解決問題2,ES使用In-memory buffer在內(nèi)存中緩存新接受的更新請求。隔一段時間將這些請求整理成一個段,再將這個段放入系統(tǒng)段文件緩存中(注意不立即寫入磁盤)。同時將每一個更新操作寫入Translog當中,保證數(shù)據(jù)的持久性。當文件緩存中當段真正被寫入磁盤后,清除Translog即可。
怎樣把一個句子存入ES
首先我們得有一個句子,比如 "ES是=_=世界上最牛逼的搜索引擎",
ES通過句子的_id找到需要被存儲的分片位置,將該句子發(fā)送過去,
之后這個句子會被解析器進行解析。(在ES中有許多解析器,你可以根據(jù)需求定義字段對應的解析器)
- 首先這個句子首先經(jīng)過剔除特殊字符的解析器:
變成 => "ES是世界上最牛逼的搜索引擎"
- 經(jīng)過剔除無用字的解析器:
變成 => "ES世界牛逼搜索引擎"
3.經(jīng)過分詞的解析器
變成 => ['ES','世界','牛逼','搜索','引擎']
4.經(jīng)過同義詞添加的解析器
變成 => ['ES','ElasticSearch','世界','牛逼','厲害','狠','搜索','查找','引擎']
ES將經(jīng)解析的詞和句子做成倒排索引,然后通過上一節(jié)所講的方式存入磁盤。
如何進行搜索(match)
這個問題看起來很難,實則很簡單。
- 首先ES會將輸入的句子,通過上一節(jié)講的解析器,分解成多個詞。
- 將每個詞通過倒排索引找到包含的句子
- 將這些包含關鍵詞的句子收集起來,通過詞語命中次數(shù),命中種類,詞頻,詞權(quán)重等進行打分(ES提供了多種打分方法,但是常用的方法是詞頻/逆向文檔頻率(term frequency/inverse document frequency))
- 將打好分的句子,通過分數(shù)排序,然后取前N個返回給用戶。
以上講解的是對于match方法背后的步驟,當然實際并非這么簡單,了解原理就好。
當然term搜索也是ES中常用的一種搜索方式,它與match不同,他必須精確匹配。ES優(yōu)化term操作,為它添加了緩存,具體方法就是通過一個稀疏的數(shù)組來存儲命中的term節(jié)點,在將這個數(shù)組存入緩存中
中文分詞
IK 分詞器,
1、詞典樹Tire Tree的構(gòu)建,即將現(xiàn)在的詞典加載到一個內(nèi)存結(jié)構(gòu)中去
2、詞的匹配查找,就是切詞
3、歧義判斷,即對不同切分方式的判定,哪種應是更合理的