- 正排索引:文檔ID到文檔內(nèi)容和單詞的關(guān)聯(lián)
- 倒排索引:單詞到文檔ID的關(guān)系
備注:ES對(duì)文檔每個(gè)字段都有自己的倒排索引,可以指定某些字段不做索引,這樣可以節(jié)省存儲(chǔ)空間,缺點(diǎn)是這個(gè)字段無法被搜索。
倒排索引不可變性
倒排索引采用Immutable Design,一旦生成,不可更改。
- 優(yōu)點(diǎn)
(1)無需考慮并發(fā)寫文件的問題,避免了鎖機(jī)制帶來的性能問題
(2)一旦讀入內(nèi)核的文件系統(tǒng)緩存,便留在那里。只要文件系統(tǒng)存有足夠大的空間。大部分請(qǐng)求就會(huì)直接請(qǐng)求內(nèi)存,不會(huì)命中磁盤,提升了很大的性能 - 缺點(diǎn)
不可變性也帶來了另一個(gè)挑戰(zhàn),如果需要讓一個(gè)新的文檔可以被索引,需要重建整個(gè)索引。
倒排索引文件結(jié)構(gòu)

- 在Lucene中,單個(gè)倒排索引文件被稱作Segment。Segment是不可變更的。多個(gè)Segment匯總在一起,稱為Lucene的Index,其對(duì)應(yīng)的就是ES中的Shard
- 當(dāng)有新文檔寫入時(shí),會(huì)生成新Segment,查找時(shí)會(huì)同時(shí)查找多個(gè)Segments,并且對(duì)結(jié)果進(jìn)行匯總。Lucene中有個(gè)Commit Point文件,用來記錄所有Segments信息。
- 刪除文檔的信息,會(huì)保存在.del文件中。在搜索時(shí),返回的結(jié)果會(huì)根據(jù).del中記錄的文檔信息,將其過濾掉。
ES索引文檔的過程
請(qǐng)求發(fā)送到Coordinating Node,如果該節(jié)點(diǎn)不是Master節(jié)點(diǎn),需要將該請(qǐng)求轉(zhuǎn)發(fā)到Master.
Master節(jié)點(diǎn)通過路由算法,確定該分片在哪個(gè)節(jié)點(diǎn)上:
shard = hash(_routing) % (num_of_primary_shards)
默認(rèn)使用文檔ID作為_routing值,也可以通過API指定_routing值分片節(jié)點(diǎn)收到請(qǐng)求后,會(huì)將請(qǐng)求寫入到Memory Buffer,然后定時(shí)(默認(rèn)是每隔1秒)寫入到Filesystem Cache(磁盤緩存),這個(gè)從Momery Buffer到Filesystem Cache(磁盤緩存)的過程就叫做Refresh。在寫入Buffer的同時(shí),會(huì)同時(shí)寫一個(gè)Transaction Log(每個(gè)分片會(huì)有一個(gè)Log文件)。當(dāng)做refresh時(shí),Buffer會(huì)被清空,Transaction Log不會(huì)清空。
ES每30分鐘,會(huì)有一個(gè)Flush操作。該操作會(huì)調(diào)用fsync,將Filesystem Cache中的數(shù)據(jù)寫入segment文件,舊的translog將被刪除并開始一個(gè)新的translog
ES會(huì)自動(dòng)進(jìn)行Merge操作,該操作會(huì)將多個(gè)Segment文件合并,在.del文件中被標(biāo)記為刪除的文檔將不會(huì)被寫入Segment,并且清空.del文件中的內(nèi)容
ES Refresh

- 創(chuàng)建索引時(shí),數(shù)據(jù)并不會(huì)直接寫入Segment文件,而是會(huì)先寫入一個(gè)Index Buffer緩沖區(qū)。而將Index Buffer中數(shù)據(jù)寫入Segment文件的過程就叫Refresh.
- Refresh的頻率默認(rèn)是每秒一次。可通過index.refresh_interval進(jìn)行配置。Refresh后,數(shù)據(jù)就可被搜索到了,這也是為什么ES被稱為近實(shí)時(shí)搜索。
- Index Buffer被占滿時(shí),也會(huì)觸發(fā)Refresh,默認(rèn)值是JVM的10%
Transaction Log

Segment寫入磁盤的過程相對(duì)耗時(shí),所以借助文件系統(tǒng)緩存,Refresh時(shí),先將Segment寫入文件緩存中,以開放查詢。但為了保證數(shù)據(jù)不會(huì)丟失,所以在創(chuàng)建索引時(shí),會(huì)同時(shí)寫Tansaction Log,類似操作日志。
在ES進(jìn)行Refresh時(shí),Index Buffer會(huì)被清空,Transaction Log不會(huì)清空。
ES Flush

Flush操作:
- 調(diào)用refresh,清空index buffer
- 清空transaction log
Flush觸發(fā)條件:
- 默認(rèn)30分鐘調(diào)用一次
- Transaction Log 默認(rèn)達(dá)到512M
ES Merge & Force Merge API
隨著索引的不斷創(chuàng)建,Segments文件會(huì)越來越多。ES會(huì)自動(dòng)進(jìn)行merge操作,將多個(gè)segments文件合并,以提高查詢效率。但Merge是很重的操作,對(duì)磁盤有頻繁IO操作,會(huì)對(duì)系統(tǒng)性能有影響。
除此之外,我們還可以通過api強(qiáng)制merge:
POST /my_index/_forcemerge?max_segements_num=1
// max_num_segments:最終合并成多少個(gè)segments
我們還可以通過配置refresh的頻率(refresh_interval),來適當(dāng)減少Segments產(chǎn)生的數(shù)量。