分佈式搜索引擎,你真的懂嗎?
一、分佈式搜索引擎簡介
(一) 概念
分佈式搜索引擎通過在多臺服務器上分配索引和搜索負載, 實現索引和搜索吞吐能力的橫向擴展。
主要特徵:
索引和搜索負載分佈在多臺服務器
支持大規模數據和訪問量
(二) 與集中式搜索引擎區別
集中式搜索引擎在單個節點上完成全部工作, 硬件資源限制其擴展能力。
分佈式搜索引擎通過分佈式計算技術, 實現可橫向擴展的大規模搜索引擎。
(三) 優勢
處理更多文檔, 支持更大訪問量
更高的查詢吞吐量
更好的容錯性
更易於擴展
二、分佈式搜索引擎架構
典型分佈式搜索引擎由以下組件組成:
(一) 索引器
文檔分片存儲和倒排索引構建。支持增量索引。
(二) 查詢引擎
接收查詢請求, 創建查詢計劃, 聚合並返回結果。
(三)DocServer
文檔服務器。存儲原始文檔, 併爲查詢引擎提供文檔獲取。
(四) 協調節點
協調索引器和查詢引擎節點, 包括文檔分配、擴縮容等。
三、分佈式索引技術
分佈式搜索引擎的核心是將索引分佈到多臺服務器上, 關鍵技術有:
(一) 倒排索引
倒排索引通過詞到文檔列表的映射, 支持快速查詢。
type Index struct {
Fields []string
DocMap map[string][]int //詞到文檔列表映射
}
func IndexDoc(doc *Document) {
index := &Index{}
//分詞
tokens := Tokenize(doc.Content)
//構建倒排索引
for _, token := range tokens {
index.DocMap[token] = append(index.DocMap[token], doc.ID)
}
}
func SearchQuery(query) {
//解析查詢詞
tokens := Tokenize(query)
//交集算法獲取共現文檔
//返回文檔id列表
return IntersecForTokens(index.DocMap, tokens)
}
(二) 中文分詞
中文搜索需要用分詞算法切分句子。
//基於詞典的中文分詞
import "github.com/go-ego/gse"
func Tokenize(text string) []string {
segmenter := gse.New("dict.txt")
// 分詞
tokens := segmenter.Segment([]byte(text))
return tokens
}
(三) 文檔分配
將文檔分佈到不同索引器服務器。常用策略:
Hash 取模: docId % N
一致性 Hash: 動態調整, 平衡負載
主詞項散列: 根據主詞項 Hash 值分配
//一致性hash分配
import "github.com/cch123/elastics/hashring"
var nodes = []string{"server1","server2"...}
ring := hashring.New(nodes)
func DistributeDoc(doc *Document) {
//根據id選擇節點
node = ring.GetNode(doc.id)
//索引文檔
indexDoc(doc, node)
}
四、查詢優化
(一) 緩存
熱點詞頻查詢可緩存在內存, 避免搜索計算。
import "github.com/patrickmn/go-cache"
type QueryCache struct {
cache *cache.Cache //詞到結果緩存
}
//獲取查詢結果
func (c *QueryCache)Search(query) {
if c.cache.Has(query) {
return cache.Get(query)
}
//緩存未命中,搜索索引
result = indexSearch(query)
c.cache.Set(query, result)
return result
}
(二) 查詢重寫
相關查詢可重寫爲通用詞, 擴大命中。
func QueryRewrite(query string) string {
rewriteRules :=map[string]string {
"寶馬" : "汽車",
"招商銀行" : "銀行"
}
if rewrite, ok := rules[query]; ok {
return rewrite
}
return query
}
(三) 相關性排序
匹配詞頻 / 位置和文檔權重相結合, 按相關度排序。
type RankedResult struct {
DocId int
Score float32 //相關度
}
func Rank(results []int, tokens []string) {
scoredList := make([]RankedResult,0)
for _,docId := range results {
score = 0
if frequency[docId][token] > 0 {
score ++
}
//詞出現在標題權重更高
if postion[docId][token] == "title" {
score += 5
}
//文檔自身權重分
score += docWeight[docId]
scored := RankedResult(docId, score)
scoredList = append(scoredList, scored)
}
//按相關度降序排序並返回
sort.Sort(scoredList)
return scoredList
}
五、Go 實現分佈式搜索引擎
Go 語言用於分佈式搜索引擎主要有:
(一) 索引器
倒排索引構建
文檔存儲
定時批量創建新分割索引
(二) 查詢引擎
通過索引器節點聚合查詢結果
結果解析和排序
提供查詢接口服務
(三)Coordinator
文檔分配和路由
負載監控
添加刪除節點
(四)RPC 框架
indexing 和查詢服務通過 RPC 框架暴露, 典型選型:
gRPC: 定製化 RPC, 性能好
Go kit: 組件化 RPC, 易開發
Http REST: 易與其他語言集成
六、Go 實現分佈式搜索引擎案例
Go 生態存在多個成熟分佈式搜索引擎實現。
(一)Bleve
倒排索引爲核心, 支持文本和地理位置查詢。
輕量級文檔存儲
支持地理位置查詢
倒排索引核心算法
// bleve 建立索引示例
import (
"github.com/blevesearch/bleve"
"github.com/blevesearch/bleve/index/upsidedown"
)
// 創建倒排索引實例
mapping := bleve.NewIndexMapping()
index, _ := bleve.New("example.bleve",mapping)
//索引文檔
data := []byte("Bleve builds indexes for text search.")
index.Index(1,data)
// Term查詢
query := bleve.NewTermQuery("Bleve")
request := bleve.NewSearchRequest(query)
result,_:= index.Search(request)
(二)Riot
基於 Lucene 的高可擴展 Go 搜索引擎, 特點:
副本機制保證高可用
文檔自動負載均衡
索引 / 查詢分離
// riot 分佈索引文檔
import (
"github.com/go-ego/riot"
"github.com/go-ego/riot/types"
)
var crawler = riot.New("zh")
crawler.Index(types.DocData{
Id: 1,
Text: "文檔內容",
})
//搜索查詢
import (
"github.com/go-ego/riot"
"github.com/go-ego/riot/types"
)
var searcher = riot.New("zh")
searcher.Search(types.SearchRequest{
Text: "關鍵詞",
RankOpts: &types.RankOpts{
OutputOffset: 5,
},
})
(三)Go-ElasticSearch
Go 客戶端訪問 ElasticSearch 集羣。
// 連接 ElasticSearch
import (
"github.com/olivere/elastic"
)
client, err := elastic.NewClient(elastic.SetURL("http://ip:port"))
// 索引文檔
client.Index().
Index("twitter").
Type("tweet").
Id("1").
BodyJson(tweet).
Do(context.Background())
//搜索
searchResult, err := client.Search().
Index("twitter").
Query(elastic.NewTermQuery("user", "kimchy")).
From(0).Size(10).
Pretty(true).
Do(context.Background())
七、總結
分佈式搜索引擎可以應對更大規模的數據和訪問。Go 語言正逐步成爲構建分佈式搜索引擎的理想選擇。
在未來,Go 語言將有機會進一步發揮效能, 助力搜索技術產業化進程。分佈式搜索引擎也將藉助雲原生技術,實現更大規模的應用。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/ScUrCB5rgNd-DmNH_SKSEQ