一、集群搜索問(wèn)題
1.問(wèn)題:如何聚合多個(gè)節(jié)點(diǎn)或分片的數(shù)據(jù)生成返回結(jié)果
在對(duì)Mysql進(jìn)行分庫(kù)分表的時(shí)候,經(jīng)常會(huì)遇到一個(gè)問(wèn)題:如果查詢的數(shù)據(jù)分散在多張表中,因?yàn)樯婕暗浇M合多種表的數(shù)據(jù),將會(huì)非常麻煩;對(duì)于有些分頁(yè)場(chǎng)景,更是一個(gè)災(zāi)難,所以對(duì)Mysql分庫(kù)分表的時(shí)候經(jīng)常會(huì)基于查詢維度來(lái)盡量避免跨表查詢的場(chǎng)景。
ElasticSearch也是分布式的,當(dāng)數(shù)據(jù)分散與多個(gè)節(jié)點(diǎn)或者分片上時(shí),他是如何解決數(shù)據(jù)聚合問(wèn)題的呢?另外,搜索基本都需要排序,如何解決排序問(wèn)題呢?
2.ES整體流程
假設(shè)有N個(gè)分片,數(shù)據(jù)可能分散在這N個(gè)分片上,ES搜索時(shí),整體操作過(guò)程是:
S1: 客戶端將會(huì)同時(shí)向N個(gè)分片發(fā)起搜索請(qǐng)求。
S2: 這N個(gè)分片基于本分片的內(nèi)容獨(dú)立完成搜索,然后將符合條件的結(jié)果全部返回。
S3: 客戶端將返回的結(jié)果進(jìn)行重新排序和排名,最后返回給用戶。
有經(jīng)驗(yàn)的開發(fā)很容易看出來(lái),這里有兩個(gè)問(wèn)題:
數(shù)量問(wèn)題。假設(shè)每次返回10條記錄,那么這N個(gè)分片獨(dú)立執(zhí)行查詢以后,每個(gè)分片最多都會(huì)返回10條數(shù)據(jù)給客戶端,然后客戶端在進(jìn)行排序返回給用戶。這個(gè)過(guò)程中返回的數(shù)據(jù)量(最大是10*N)會(huì)遠(yuǎn)大于用戶請(qǐng)求需要的數(shù)據(jù)量。
排名問(wèn)題。計(jì)算分值使用的詞頻和文檔頻率等信息都是基于自己分片的數(shù)據(jù)進(jìn)行的,不同分片中這些數(shù)據(jù)不同,直接導(dǎo)致各個(gè)分片算出來(lái)的分?jǐn)?shù)不具有統(tǒng)一參考性,影響排名準(zhǔn)確性。正確的做法是基于整體的詞頻、逆向文檔頻率等信息來(lái)算分?jǐn)?shù)。
3.查詢方式
ElasticSearch查詢的時(shí)候可以指定搜索類型: QUERY_AND_FEATCH、QUERY_THEN_FETCH(默認(rèn)的搜索方式)、DFS_QUERY_THEN_FEATCH、DFS_QUERY_AND_FEATCH。
1)QUERY_AND_FEATCH**
向索引的所有分片(shard)都發(fā)出查詢請(qǐng)求,各分片返回的時(shí)候把元素文檔(document)和計(jì)算后的排名信息一起返回。
這種搜索方式是最快的,只需要去shard查詢一次,但是各個(gè)shard返回的結(jié)果的數(shù)量之和可能是用戶要求的size的n倍。
2)QUERY_THEN_FETCH
先向所有的shard發(fā)出請(qǐng)求,各分片只返回排序和排名相關(guān)的信息(注意,不包括文檔document),然后按照各分片返回的分?jǐn)?shù)進(jìn)行重新排序和排名,取前size個(gè)文檔;接著去相關(guān)的shard取document。
這種方式返回的document與用戶要求的size是相等的。
3)DFS_QUERY_AND_FEATCH
在進(jìn)行真正的查詢之前,先把各個(gè)分片的詞頻和文檔頻率收集一下,然后進(jìn)行詞搜索的時(shí)候,各分片依據(jù)全局的詞頻率和文檔頻率進(jìn)行搜索和排名。
接著按照QUERY_AND_FEATCH的方式查詢。
4)DFS_QUERY_THEN_FEATCH
和上面一種方式一樣,也是先收集詞頻和文檔頻率,然后再按照QUERY_THEN_FEATC的方式查詢。
這種查詢要前后交互三次,速度最慢,但是排名最準(zhǔn)確。
二、相關(guān)度搜索問(wèn)題
1.問(wèn)題:ES是如何將相關(guān)度高的內(nèi)容能放在前面的?
在原理篇我們知道,當(dāng)將一個(gè)文檔保存到ElasticSearch會(huì)根據(jù)分詞的結(jié)果創(chuàng)建倒排索引,這種結(jié)構(gòu)是零散的,即每一個(gè)Term都會(huì)對(duì)應(yīng)Posting List。查詢的時(shí)候也是先經(jīng)過(guò)分詞,然后根據(jù)倒排索引查詢。
這里就有一個(gè)問(wèn)題,ElasticSearch是如何將匹配度最高的內(nèi)容放在前面的?如下圖所示,匹配效果最好的內(nèi)容放到了返回結(jié)果的最前面。

2.相關(guān)度
Lucene 使用布爾模型(Boolean model)查找匹配文檔,并使用權(quán)重來(lái)實(shí)現(xiàn)相關(guān)度搜索。
1)布爾模型
就是在查詢中使用?AND、OR、NOT(即與或非)來(lái)匹配文檔。
2)權(quán)重
權(quán)重由三個(gè)因素決定:詞頻、逆向文檔頻率、字段長(zhǎng)度歸一值
詞頻
指的是詞在文檔中出現(xiàn)的頻度是多少,頻度越高,權(quán)重越高。
詞頻=該詞在文檔中出現(xiàn)次數(shù)的平方根。
逆向文檔頻率
指的是詞在集合所有文檔里出現(xiàn)的頻率是多少,頻次越高,權(quán)重越低。
逆向文檔頻率=索引中文檔數(shù)量除以所有包含該詞的文檔數(shù),然后求其對(duì)數(shù)。
字段長(zhǎng)度歸一值
指的是字段的長(zhǎng)度是多少,字段越短,字段的權(quán)重越高 。
字段長(zhǎng)度歸一值 = 字段中詞數(shù)平方根的倒數(shù)。
3)向量空間模型
通常我們都是搜索多個(gè)字段,這樣就需要合并多詞權(quán)重,這個(gè)由向量空間模型實(shí)現(xiàn)。
具體合并過(guò)程基本都是數(shù)學(xué)上的算法,沒有詳細(xì)研究,有興趣的小伙伴可以到網(wǎng)上找一下。
3.相關(guān)度搜索
ES其實(shí)就是基于相關(guān)度的算法來(lái)計(jì)算分?jǐn)?shù),將分?jǐn)?shù)大的放在前面。