之前的文章分析过,接受索引请求处理的代码在segmenter_worker.go里:

  1. func (engine *Engine) segmenterWorker() {
  2. for {
  3. request := <-engine.segmenterChannel //关键
  4.  
  5. tokensMap := make(map[string][]int)
  6. numTokens := 0
  7. if !engine.initOptions.NotUsingSegmenter && request.data.Content != "" {
  8. // 当文档正文不为空时,优先从内容分词中得到关键词
  9. segments := engine.segmenter.Segment([]byte(request.data.Content))
  10. for _, segment := range segments {
  11. token := segment.Token().Text()
  12. if !engine.stopTokens.IsStopToken(token) {
  13. tokensMap[token] = append(tokensMap[token], segment.Start())
  14. }
  15. }
  16. numTokens = len(segments)
  17. } else {
  18. // 否则载入用户输入的关键词
  19. for _, t := range request.data.Tokens {
  20. if !engine.stopTokens.IsStopToken(t.Text) {
  21. tokensMap[t.Text] = t.Locations
  22. }
  23. }
  24. numTokens = len(request.data.Tokens)
  25. }
  26.  
  27. // 加入非分词的文档标签
  28. for _, label := range request.data.Labels {
  29. if !engine.initOptions.NotUsingSegmenter {
  30. if !engine.stopTokens.IsStopToken(label) {
  31. tokensMap[label] = []int{}
  32. }
  33. } else {
  34. tokensMap[label] = []int{}
  35. }
  36. }
  37.  
  38. indexerRequest := indexerAddDocumentRequest{
  39. document: &types.DocumentIndex{
  40. DocId: request.docId,
  41. TokenLength: float32(numTokens),
  42. Keywords: make([]types.KeywordIndex, len(tokensMap)),
  43. },
  44. }
  45. iTokens := 0
  46. for k, v := range tokensMap {
  47. indexerRequest.document.Keywords[iTokens] = types.KeywordIndex{
  48. Text: k,
  49. // 非分词标注的词频设置为0,不参与tf-idf计算
  50. Frequency: float32(len(v)),
  51. Starts: v}
  52. iTokens++
  53. }
  54.  
  55. var dealDocInfoChan = make(chan bool, 1)
  56.  
  57. indexerRequest.dealDocInfoChan = dealDocInfoChan
  58. engine.indexerAddDocumentChannels[request.shard] <- indexerRequest
  59.  
  60. rankerRequest := rankerAddDocRequest{
  61. docId: request.docId,
  62. fields: request.data.Fields,
  63. dealDocInfoChan: dealDocInfoChan,
  64. }
  65. engine.rankerAddDocChannels[request.shard] <- rankerRequest
  66. }
  67. }

上面代码的作用就是在统计词频和单词位置(注意:tag也是作为搜索的单词,不过其词频是0,而无法参与tf-idf计算),并封装为indexerRequest,发送给engine.indexerAddDocumentChannels[request.shard]

此外,红色部分代码是在为文档评分做准备,engine/ranker_worker.go:

  1. func (engine *Engine) rankerAddDocWorker(shard int) {
  2. for {
  3. request := <-engine.rankerAddDocChannels[shard] //关键
  4. docInfo := engine.rankers[shard].AddDoc(request.docId, request.fields, request.dealDocInfoChan)
  5. // save
  6. if engine.initOptions.UsePersistentStorage {
  7. engine.persistentStorageIndexDocumentChannels[shard] <- persistentStorageIndexDocumentRequest{
  8. typ: "info",
  9. docId: request.docId,
  10. docInfo: docInfo,
  11. }
  12. }
  13. }
  14. }

AddDoc无非就是将docid对应的fields信息存储起来,为搜索结果rank评分用!

  1. // 给某个文档添加评分字段
  2. func (ranker *Ranker) AddDoc(docId uint64, fields interface{}, dealDocInfoChan <-chan bool) *types.DocInfo {
  3. if ranker.initialized == false {
  4. log.Fatal("排序器尚未初始化")
  5. }
  6.  
  7. <-dealDocInfoChan // 等待索引器处理完成
  8.  
  9. ranker.DocInfosShard.Lock()
  10. defer ranker.DocInfosShard.Unlock()
  11. if _, found := ranker.DocInfosShard.DocInfos[docId]; !found {
  12. ranker.DocInfosShard.DocInfos[docId] = new(types.DocInfo)
  13. ranker.DocInfosShard.NumDocuments++
  14. }
  15. ranker.DocInfosShard.DocInfos[docId].Fields = fields
  16. return ranker.DocInfosShard.DocInfos[docId]
  17. }

wukong引擎源码分析之索引——part 3 文档评分 无非就是将docid对应的fields信息存储起来,为搜索结果rank评分用的更多相关文章

  1. wukong引擎源码分析之索引——part 2 持久化 直接set(key,docID数组)在kv存储里

    前面说过,接收indexerRequest的代码在index_worker.go里: func (engine *Engine) indexerAddDocumentWorker(shard int) ...

  2. wukong引擎源码分析之索引——part 1 倒排列表本质是有序数组存储

    searcher.IndexDocument(0, types.DocumentIndexData{Content: "此次百度收购将成中国互联网最大并购"}) engine.go ...

  3. wukong引擎源码分析之搜索——docid有序的数组里二分归并求交集,如果用跳表的话,在插入索引时会更快

    searcher.Search(types.SearchRequest{Text: "百度中国"}) // 查找满足搜索条件的文档,此函数线程安全 func (engine *En ...

  4. Spark源码分析 – 汇总索引

    http://jerryshao.me/categories.html#architecture-ref http://blog.csdn.net/pelick/article/details/172 ...

  5. 源码分析 Kafka 消息发送流程(文末附流程图)

    温馨提示:本文基于 Kafka 2.2.1 版本.本文主要是以源码的手段一步一步探究消息发送流程,如果对源码不感兴趣,可以直接跳到文末查看消息发送流程图与消息发送本地缓存存储结构. 从上文 初识 Ka ...

  6. 转:Irrlicht 0.1引擎源码分析与研究(一)

    目录(?)[-] 主要技术特性 引擎概览 Irrlicht的窗口管理   Irrlicht引擎主要是由一个名叫Nikolaus Gebhardt奥地利人所设计,是sourceforge上的一个开源项目 ...

  7. bleve搜索引擎源码分析之索引——mapping真复杂啊

    接下来看看下面index部分的源码实现: data := struct { Name string Des string }{ Name: "hello world this is bone ...

  8. bleve搜索引擎源码分析之索引——mapping和lucene一样,也有_all

    例子: package main import ( "fmt" "github.com/blevesearch/bleve" ) func main() { / ...

  9. lua源码分析 伪索引

    Lua 提供了一个 注册表, 这是一个预定义出来的表, 可以用来保存任何 C 代码想保存的 Lua 值. 这个表可以用有效伪索引 LUA_REGISTRYINDEX 来定位. 任何 C 库都可以在这张 ...

随机推荐

  1. msp430入门学习41

    msp430的其他九 msp430入门学习

  2. SGU 107 数学题

    题意:求平方后末尾9个数是987654321的数个数. 之前做此题,竟然愚蠢到用计算器 在哪里算,还加笔算,SB啊!不知道先打印一下吗! #include<iostream> #inclu ...

  3. django cookie session操作

    Cookie是什么? cookie说的直白点就是保存在用户浏览器端的一个键值对,举个例子,你现在登录了京东商城,你把浏览器关闭之后,你再打开京东,你还是可以对你的账户继续操作,已经购买的商品,订单都是 ...

  4. 学习技术的三部曲:WHAT、HOW、WHY

    ★第一步:WHAT 所谓的“WHAT”也就是“What is it?”——这是最简单的层次.在这个层次,你要搞清楚某个东东是[什么]样子的?有[什么]用处?有[什么]特性?有[什么]语法?...... ...

  5. codeforces edu40

    H(dp计数) 题意: 有一颗树,最深的点的深度是n,每个深度为i的点都有ai个孩子. 对于1<=k<=2n-2,回答树上有多少点对之间的距离是k,答案对1e9+7取模 n<=500 ...

  6. springboot jetty替换tomcat

    <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring- ...

  7. 新闻:融资600万 他用一套系统优化15大HR工作场景 精简入转调离 月开通214家 | IT桔子

    新闻:融资600万 他用一套系统优化15大HR工作场景 精简入转调离 月开通214家 | IT桔子 功劳说不上

  8. 转: 在CentOS 6.X 上面安装 Python 2.7.X

    转:https://ruiaylin.github.io/2014/12/12/python%20update/ 评注: yum -y update //这个更新太坑了,1120更新包...想死的心都 ...

  9. iOS知识点全梳理-b

    感谢分享 原文链接:http://www.jianshu.com/p/5d2163640e26 序言 目前形势,参加到iOS队伍的人是越来越多,甚至已经到供过于求了.今年,找过工作人可能会更深刻地体会 ...

  10. java:BufferedImage推断图像通道顺序并转RGB/BGR

    一般来说java ImageIO处理读取图像时.通常是RGB或ARGB格式,可是有的时候.我们须要图像是BGR格式. 比方通过JNI将图像矩阵传递给动态库,动态库里用OpenCV来处理矩阵,而用Ope ...