Go 先锋
读完需要
速读仅需 4 分钟
一、分布式搜索引擎简介
(一)概念
分布式搜索引擎通过在多台服务器上分配索引和搜索负载,实现索引和搜索吞吐能力的横向扩展。
主要特征:
索引和搜索负载分布在多台服务器
支持大规模数据和访问量
(二)与集中式搜索引擎区别
集中式搜索引擎在单个节点上完成全部工作,硬件资源限制其扩展能力。
分布式搜索引擎通过分布式计算技术,实现可横向扩展的大规模搜索引擎。
(三)优势
处理更多文档,支持更大访问量
更高的查询吞吐量
更好的容错性
更易于扩展
二、分布式搜索引擎架构
典型分布式搜索引擎由以下组件组成:
(一)索引器
文档分片存储和倒排索引构建。支持增量索引。
(二)查询引擎
接收查询请求,创建查询计划,聚合并返回结果。
(三)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 语言将有机会进一步发挥效能,助力搜索技术产业化进程。分布式搜索引擎也将借助云原生技术,实现更大规模的应用。