悟空分词的搜索和排序源码分析之——搜索

简介:

转自:http://blog.codeg.cn/2016/02/02/wukong-source-code-reading/

搜索过程分析

下面我们来分析一下搜索的过程。首先构造一个SearchRequest对象。一般情况下只需提供SearchRequest.Text即可。

type SearchRequest struct {
	// 搜索的短语(必须是UTF-8格式),会被分词
	// 当值为空字符串时关键词会从下面的Tokens读入
	Text string // 关键词(必须是UTF-8格式),当Text不为空时优先使用Text // 通常你不需要自己指定关键词,除非你运行自己的分词程序 Tokens []string // 文档标签(必须是UTF-8格式),标签不存在文档文本中,但也属于搜索键的一种 Labels []string // 当不为nil时,仅从这些DocIds包含的键中搜索(忽略值) DocIds map[uint64]bool // 排序选项 RankOptions *RankOptions // 超时,单位毫秒(千分之一秒)。此值小于等于零时不设超时。 // 搜索超时的情况下仍有可能返回部分排序结果。 Timeout int // 设为true时仅统计搜索到的文档个数,不返回具体的文档 CountDocsOnly bool // 不排序,对于可在引擎外部(比如客户端)排序情况适用 // 对返回文档很多的情况打开此选项可以有效节省时间 Orderless bool } 

从本文一开始那段示例代码的搜索语句读起:searcher.Search(types.SearchRequest{Text:"百度中国"})。进入到 Search 函数内部,其逻辑如下:

设置一些搜索选项

例如排序选项RankOptions, 分数计算条件ScoringCriteria等等

将搜索词进行分词

	// 收集关键词
	tokens := []string{}
	if request.Text != "" {
		querySegments := engine.segmenter.Segment([]byte(request.Text)) for _, s := range querySegments { token := s.Token().Text() if !engine.stopTokens.IsStopToken(token) { tokens = append(tokens, s.Token().Text()) } } } else { for _, t := range request.Tokens { tokens = append(tokens, t) } } 

这里的”百度中国”会分词得到两个词:百度 和中国

向索引器发送查找请求

	// 建立排序器返回的通信通道
	rankerReturnChannel := make(
		chan rankerReturnRequest, engine.initOptions.NumShards)

	// 生成查找请求
	lookupRequest := indexerLookupRequest{
		countDocsOnly:       request.CountDocsOnly,
		tokens:              tokens,
		labels:              request.Labels,
		docIds:              request.DocIds,
		options:             rankOptions,
		rankerReturnChannel: rankerReturnChannel,
		orderless:           request.Orderless,
	}

	// 向索引器发送查找请求 for shard := 0; shard < engine.initOptions.NumShards; shard++ { engine.indexerLookupChannels[shard] <- lookupRequest } 

这里是否可以进行优化? 1) 只向特定的shard分发请求,避免无谓的indexer查找过程。2)rankerReturnChannel是否不用每次都创建新的?

读取索引器的返回结果然后排序

上面已经建立了结果的返回通道rankerReturnChannel,直接从个channel中读取返回数据,并加入到数组rankOutput中。 注意,如果设置了超时,就在超时之前能读取多少就读多少。 然后调用排序算法进行排序。排序算法直接调用Golang自带的sort包的排序算法。

下面我们深入到索引器,看看索引器是如何进行搜索的。其核心代码在这里func (engine *Engine) indexerLookupWorker(shard int),它的主逻辑是一个死循环,不断的从engine.indexerLookupChannels[shard]读取搜索请求。

针对每一个搜索请求,会将请求分发到索引器去,调用func (indexer *Indexer) Lookup(tokens []string, labels []string, docIds map[uint64]bool, countDocsOnly bool) (docs []types.IndexedDocument, numDocs int)方法。其主要逻辑如下:

  1. 将分词和标签合并在一起进行搜索
  2. 合并搜索到的docId,并进行初步排序,将docId大的排在前面(实际上是认为docId越大,时间越近,时效性越好)
  3. 然后进行排序,BM25算法
  4. 最后返回数据
















本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/bonelee/p/6341334.html,如需转载请自行联系原作者


相关文章
|
人工智能 关系型数据库 分布式数据库
沉浸式学习PostgreSQL|PolarDB 16: 植入通义千问大模型+文本向量化模型, 让数据库具备AI能力
本文将带领大家来体验一下如何将“千问大模型+文本向量化模型”植入到PG|PolarDB中, 让数据库具备AI能力.
25785 21
沉浸式学习PostgreSQL|PolarDB 16: 植入通义千问大模型+文本向量化模型, 让数据库具备AI能力
|
7月前
|
人工智能 自然语言处理 搜索推荐
高性价比| OpenSearch 智能问答版开箱即用 DeepSeek-R1
OpenSearch LLM智能问答版基于DeepSeek-R1一分钟搭建RAG系统。
1386 11
高性价比| OpenSearch 智能问答版开箱即用 DeepSeek-R1
|
11月前
|
数据安全/隐私保护
jupyterlab远程服务器配置
jupyterlab远程服务器配置
323 0
|
安全 网络安全 数据安全/隐私保护
装机安全:从细节做起,构建安全无忧的数字基石
装机安全是构建安全无忧的数字基石的重要保障。从装机前的准备到硬件组装、系统设置、软件安装及后期维护等各个环节都需要我们高度重视并采取相应的安全措施。只有从细节做起,才能确保计算机的稳定运行和数据的安全可靠。希望本文能为广大计算机用户提供有益的参考和借鉴,共同营造一个更加安全、便捷的数字环境。
|
存储 安全 算法
数字堡垒之下:网络安全漏洞、加密技术与安全意识的三维防线
在数字化时代的浪潮中,网络安全成为保护信息资产的重要屏障。本文深入探讨了网络安全的三大支柱:网络漏洞的识别与防范、加密技术的应用与挑战、以及培养安全意识的必要性。通过分析最新的统计数据和案例研究,本文揭示了网络攻击的常见模式、加密技术的发展趋势,并强调了提升个人与企业的安全意识在预防网络威胁中的核心作用。旨在为读者提供一套综合的网络安全知识框架,以应对日益复杂的网络威胁环境。
|
存储 Cloud Native 安全
【云原生】云计算初识
【1月更文挑战第18天】【云原生】云计算初识
|
消息中间件 弹性计算 关系型数据库
使用EDA架构部署在线外卖订单系统
本实验将使用消息系统构建超级外卖订单,通过订单流转及处理阐述如何在多环境,复杂场景下使用消息做订单解耦,业务分发等。
|
NoSQL Redis C++
cpp_redis (Windows C++ Redis客户端静态库,C++11实现)源码编译及使用
cpp_redis (Windows C++ Redis客户端静态库,C++11实现)源码编译及使用
1436 0
|
前端开发 安全 JavaScript
Sitecore SXA让开发速度成倍加快?
如果你决定搭建Sitecore DXP平台,肯定是绕不开Sitecore SXA的。它是Sitecore推出的一款加速器,旨在让团队更快的搭建网站。它能让代码更好遵循 Sitecore 的页面结构、消除生产障碍,更轻松的构建页面,更好地服务于搜索引擎优化等
196 1
|
自然语言处理 分布式计算 搜索推荐
专题实战 | 如何快速构建高质量电商行业搜索?
本文详细介绍如何快速接入智能开放搜索(OpenSearch)电商行业增强版,助力企业实现高质量搜索效果,提升业务转化率及用户产品体验!
2152 1