如何給TiDB插上全文檢索的翅膀
“搜索”是內(nèi)容類App產(chǎn)品非常重要的一個(gè)功能,“全文檢索”是支持它不可或缺的一項(xiàng)基本能力。
目前業(yè)界很多公司產(chǎn)品的業(yè)務(wù)數(shù)據(jù)已經(jīng)向 TiDB 遷移了,但目前在 TiDB 上只能使用 SQL Like 對(duì)內(nèi)容進(jìn)行簡(jiǎn)單的檢索。
即便不考慮性能問題,SQL Like 仍然無法實(shí)現(xiàn)搜索場(chǎng)景下常見的信息檢索需求,單純使用 Like 會(huì)導(dǎo)致查詢到有歧義的結(jié)果或滿足搜索條件的結(jié)果無法返回。
由于TiDB 全文檢索能力的缺失,歲月很多公司依舊需要使用傳統(tǒng)的方式將數(shù)據(jù)同步到搜索引擎,在過程中根據(jù)業(yè)務(wù)特點(diǎn)做大量繁瑣的數(shù)據(jù)流水線工作來維護(hù)業(yè)務(wù)數(shù)據(jù)的全文索引。為了減少這樣的重復(fù)勞動(dòng),TiDB 引入“全文檢索”功能,為存儲(chǔ)在 TiDB 中的文本數(shù)據(jù)提供隨時(shí)隨地搜索的能力。
方案設(shè)計(jì)
選擇了一條穩(wěn)妥的設(shè)計(jì)方案——整合 Elasticsearch。
為什么選擇 Elasticsearch?
可以充分利用其成熟的生態(tài)直接獲得中文分詞和 Query 理解能力。
考慮到工作量,對(duì)于全文索引的數(shù)據(jù)同步方案,沒有采用 TiKV Raft Learner 機(jī)制,也沒有使用 TiDB Binlog 的方式進(jìn)行同步,而是采用了最保守的雙寫機(jī)制直接在 TiDB 的寫入流程中增加了全文索引更新的流程。

如上圖所示,TiDB 作為 Elasticsearch 和 TiKV 之間的橋梁,所有同 Elasticsearch 的交互操作都嵌入在 TiDB 內(nèi)部直接完成。
在 TiDB 內(nèi)部,將表額外增加了支持 全文(FULLTEXT)索引的元數(shù)據(jù)記錄,并且在 Elasticsearch 上面創(chuàng)建了對(duì)應(yīng)的索引和 Mapping,對(duì)于全文索引中的每一個(gè)文本列,都將它添加到 Mapping 中并指定好需要的 Analyzer,這樣就可以在索引上對(duì)這些文本列進(jìn)行全文檢索了。
在 Elasticsearch 索引的幫助下,只需要在寫入數(shù)據(jù)或者對(duì)數(shù)據(jù)進(jìn)行更新時(shí)在 Elasticsearch 的索引上進(jìn)行對(duì)應(yīng)的更新操作,就保持 TiDB 和 Elasticsearch 數(shù)據(jù)的同步。
而對(duì)于查詢,流程如下:
1. TiDB 解析用戶發(fā)送的 Query。
2. 如果發(fā)現(xiàn)該 Query 帶有全文檢索的 hint,TiDB 則會(huì)將請(qǐng)求發(fā)給 Elasticsearch,使用 Elasticsearch 索引查詢到記錄主鍵。
3. TiDB 拿到所有記錄主鍵之后,在 TiDB 內(nèi)部獲取實(shí)際的數(shù)據(jù),完成最終的數(shù)據(jù)讀取。
4. TiDB 將結(jié)果返回給用戶。
未來規(guī)劃
基于以上方案驗(yàn)證了整合 TiDB 和 ES 的可能性,當(dāng)然,也不會(huì)滿足于這套雙寫的方案。
未來考慮基于 Raft Learner 實(shí)時(shí)將數(shù)據(jù)變更同步給 Elasticsearch,將 TiDB 打造成一個(gè)真正的能支持實(shí)時(shí)全文檢索的 HTAP 數(shù)據(jù)庫(kù)。
使用 Raft Learner,對(duì)于寫流程,TiDB 會(huì)直接將數(shù)據(jù)寫給底層的 TiKV,而 TiKV 會(huì)通過 Raft 協(xié)議將寫入數(shù)據(jù)同步到 ES Learner 節(jié)點(diǎn),通過該 Learner 節(jié)點(diǎn)寫入到 ES。
對(duì)于讀流程,TiDB 會(huì)解析到用戶發(fā)過來的 Query 帶有全文檢索的 hint,然后將請(qǐng)求發(fā)給 ES Learner 節(jié)點(diǎn)。
ES Learner 節(jié)點(diǎn)首先通過 Raft 協(xié)議來確保節(jié)點(diǎn)上面有了最新的數(shù)據(jù),并且最新的數(shù)據(jù)已經(jīng)寫入到 Elasticsearch,再通過索引讀取到對(duì)應(yīng)的記錄主鍵,返回給 TiDB。
最后 TiDB 使用記錄主鍵獲取到完整的數(shù)據(jù),并返回給客戶端。
相比于之前讓 TiDB 雙寫到 Elasticsearch 和 TiKV 的方案,在寫入上面,TiDB 并不需要跟 Elasticsearch 進(jìn)行交互,而在讀取方面,通過 Raft 協(xié)議,TiDB 也能保證從 Elasticsearch 讀取到最新的數(shù)據(jù),保證了數(shù)據(jù)的一致性。