golang-构建搜索引擎微服务riot
需求
内容型网站,比如论坛、知识库或者文档查询等,均需要根据用户输入的内容,搜索匹配的文档。
这时我们可以搭建一些高性能的搜索服务,来给主站提供“搜索”功能支持。
使用golang写的开源搜索引擎 riot (riot是在wukong的基础上开发的,wukong现在更新维护基本是停滞状态)吸引了我们的目光,高性能、可扩展、支持中文搜索。
实现
环境准备
首先需要安装golang,版本是1.8以上(ubuntu现在推荐的是1.6版本,因此需要从golang的官网下载,然后配置环境变量即可)
安装riot的依赖包
- go get “github.com/shirou/gopsutil”
- go get "github.com/go-ego/gpy"
安装riot
- go get -u github.com/go-ego/riot
- go get -u github.com/go-ego/re
roit的工作原理
引擎中处理用户请求、分词、索引和排序分别由不同的协程(goroutines)完成。
1. 主协程,用于收发用户请求 2. 分词器(segmenter)协程,负责分词 3. 索引器(indexer)协程,负责建立和查找索引表 4. 排序器(ranker)协程,负责对文档评分排序
索引流程
当一个将文档(document)加入索引的请求进来以后,主协程会通过一个信道(channel)将要分词的文本发送给某个分词协程,该协程将文本分词后通过另一个信道发送给一个索引器协程。索引器协程建立从搜索键(search keyword)到文档的反向索引(inverted index),反向索引表保存在内存中方便快速调用。
搜索流程
主协程接到用户请求,将请求短语在主协程内分词,然后通过信道发送给索引器,索引器查找每个搜索键对应的文档然后进行逻辑操作(归并求交集)得到一个精简的文档列表,此列表通过信道传递给排序器,排序器对文档进行评分(scoring)、筛选和排序,然后将排好序的文档通过指定的信道发送给主协程,主协程将结果返回给用户。
分词、索引和排序都有多个协程完成,中间结果保存在信道缓冲队列以避免阻塞。为了提高搜索的并发度降低延迟,riot 引擎将文档做了裂分(裂分数目可以由用户指定),索引和排序请求会发送到所有裂分上并行处理,结果在主协程进行二次归并排序。
上面就是riot 引擎的大致原理。任何完整的搜索系统都包括四个部分, 文档抓取 、 索引 、 搜索 和 显示 。
简单使用
package main import ( "log" "github.com/go-ego/riot/engine" "github.com/go-ego/riot/types" ) var ( // searcher is coroutine safe searcher = engine.Engine{} ) func main() { // Init searcher searcher.Init(types.EngineInitOptions{ Using: 4, SegmenterDict: "./dict/dictionary.txt"}) defer searcher.Close() // Add the document to the index, docId starts at 1 searcher.IndexDocument(1, types.DocIndexData{Content: "Google Is Experimenting With Virtual Reality Advertising"}, false) searcher.IndexDocument(2, types.DocIndexData{Content: "Google accidentally pushed Bluetooth update for Home speaker early"}, false) searcher.IndexDocument(3, types.DocIndexData{Content: "Google is testing another Search results layout with rounded cards, new colors, and the 4 mysterious colored dots again"}, false) // Wait for the index to refresh searcher.FlushIndex() // The search output format is found in the types.SearchResponse structure log.Print(searcher.Search(types.SearchRequest{Text: "google testing"})) } //输出结果: //2017/10/24 15:14:29 载入gse词典 ./dict/dictionary.txt //2017/10/24 15:14:31 gse词典载入完毕 //2017/10/24 15:14:31 Check virtualMemory...Total: 12539645952, Free:7705378816, UsedPercent:11.799818% //2017/10/24 15:14:31 {[google testing] [{3 Google is testing another Search results layout with rounded cards, new colors, and the 4 mysterious colored dots again <nil> <nil> [4.7] [] []}] false 1}
使用该引擎,需要将数据格式化后存储到riot,然后通过接口查询即可。
性能与扩展
性能数据请参考 https://github.com/go-ego/riot/blob/master/docs/zh/benchmarking.md
riot支持持久化存储,如果需要分布式搜索,需要将索引与数据分块,做二次开发