前面说过,接收indexerRequest的代码在index_worker.go里:

func (engine *Engine) indexerAddDocumentWorker(shard int) {
for {
request := <-engine.indexerAddDocumentChannels[shard] //关键
addInvertedIndex := engine.indexers[shard].AddDocument(request.document, request.dealDocInfoChan) // 向反向索引表(数组)中加入一个文档
// save
if engine.initOptions.UsePersistentStorage {
for k, v := range addInvertedIndex {
engine.persistentStorageIndexDocumentChannels[shard] <- persistentStorageIndexDocumentRequest{
typ: "index",
keyword: k,
keywordIndices: v,
}
}
} atomic.AddUint64(&engine.numTokenIndexAdded,
uint64(len(request.document.Keywords)))
atomic.AddUint64(&engine.numDocumentsIndexed, )
}

持久化的代码:engine/persistent_storage_worker.go

package engine

import (
"bytes"
"encoding/binary"
"encoding/gob"
"github.com/huichen/wukong/core"
"github.com/huichen/wukong/types"
"sync"
"sync/atomic"
) type persistentStorageIndexDocumentRequest struct {
typ string //"info"or"index" // typ=="info"时,以下两个字段有效
docId uint64
docInfo *types.DocInfo // typ=="index"时,以下两个字段有效
keyword string
keywordIndices *types.KeywordIndices
} func (engine *Engine) persistentStorageIndexDocumentWorker(shard int) {
for {
request := <-engine.persistentStorageIndexDocumentChannels[shard]
switch request.typ {
case "info":
// 得到key
b := make([]byte, )
length := binary.PutUvarint(b, request.docId) // 得到value
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(request.docInfo)
if err != nil {
atomic.AddUint64(&engine.numDocumentsStored, )
return
} // 将key-value写入数据库
engine.dbs[shard][getDB(request.typ)].Set(b[:length], buf.Bytes())
atomic.AddUint64(&engine.numDocumentsStored, ) case "index":
// 得到key
b := []byte(request.keyword) // 得到value
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(request.keywordIndices)
if err != nil {
return
} // 将key-value写入数据库
engine.dbs[shard][getDB(request.typ)].Set(b, buf.Bytes())
}
}
} func (engine *Engine) persistentStorageRemoveDocumentWorker(docId uint64, shard int) {
// 得到key
b := make([]byte, )
length := binary.PutUvarint(b, docId) // 从数据库删除该key
engine.dbs[shard][getDB("info")].Delete(b[:length])
} func (engine *Engine) persistentStorageInitWorker(shard int) {
var finish sync.WaitGroup
finish.Add()
// 恢复docInfo
go func() {
defer finish.Add(-)
engine.dbs[shard][getDB("info")].ForEach(func(k, v []byte) error {
key, value := k, v
// 得到docID
docId, _ := binary.Uvarint(key) // 得到data
buf := bytes.NewReader(value)
dec := gob.NewDecoder(buf)
var data types.DocInfo
err := dec.Decode(&data)
if err == nil {
// 添加索引
core.AddDocInfo(shard, docId, &data)
}
return nil
})
}() // 恢复invertedIndex
go func() {
defer finish.Add(-)
engine.dbs[shard][getDB("index")].ForEach(func(k, v []byte) error {
key, value := k, v
// 得到keyword
keyword := string(key) // 得到data
buf := bytes.NewReader(value)
dec := gob.NewDecoder(buf)
var data types.KeywordIndices
err := dec.Decode(&data)
if err == nil {
// 添加索引
core.AddKeywordIndices(shard, keyword, &data)
}
return nil
})
}()
finish.Wait()
engine.persistentStorageInitChannel <- true
}

可以看到,倒排索引存在DB里是丑陋的,直接set(key, value) 其中,key是倒排列表的关键字,而value是doc id list也就是数组。

如果索引比较多,每次去DB set是非常耗时的,尤其针对同一个keyword有doc id插入时!

总之,wukong对于持久化的做法很丑陋!

wukong引擎源码分析之索引——part 2 持久化 直接set(key,docID数组)在kv存储里的更多相关文章

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

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

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

    之前的文章分析过,接受索引请求处理的代码在segmenter_worker.go里: func (engine *Engine) segmenterWorker() { for { request : ...

  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. bleve搜索引擎源码分析之索引——mapping真复杂啊

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

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

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

  7. lua源码分析 伪索引

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

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

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

  9. 4 weekend110的textinputformat对切片规划的源码分析 + 倒排索引的mr实现 + 多个job在同一个main方法中提交

    好的,现在,来weekend110的textinputformat对切片规划的源码分析, Inputformat默认是textinputformat,一通百通. 这就是今天,weekend110的te ...

随机推荐

  1. Hdu5921 Binary Indexed Tree

    Hdu5921 Binary Indexed Tree 思路 计数问题,题目重点在于二进制下1的次数的统计,很多题解用了数位DP来辅助计算,定义g(i)表示i的二进制中1的个数, $ans = \su ...

  2. Codeforces 667C Reberland Linguistics【DFS】

    一道卡题意的题. 题目链接: http://codeforces.com/problemset/problem/667/C 题意: 一个串可以看成一个长度大于4的根,加上其后面的若干个相邻(in a ...

  3. CentOS 7.5 初始网络配置

    最近刚装完 CentOS 7.5 系统,由于网络不通,导致无法用 yum 命令下载软件,经过了各种折腾,终于搞定了,这里讲解一下 如何设置初始网络. 本案例环境  VmWare 11.0 , 操作系统 ...

  4. KS103超声波测距模块

    max232:电平转换芯片,将电脑的RS-232标准串口(高+12V,低-12V)转换为(高+5V,低0V). 电脑串口(RS -232) => 单片机串口(TTL串口) SIPEX SP323 ...

  5. 二叉树的层次遍历 II

    给定一个二叉树,返回其节点值自底向上的层次遍历. (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 例如:给定二叉树 [3,9,20,null,null,15,7], 3 / \ 9 20 ...

  6. sql-trace-10046-trcsess-and-tkprof

    https://oracle-base.com/articles/misc/sql-trace-10046-trcsess-and-tkprof awr/statspack,sqlprofile,sq ...

  7. 在matlab中对中国地图中的不同省份按照高度进行渲染

    直接上优化后的代码和效果图 colour_totall=128; % 载入地图数据 --各省的多边形数据 shp_data=shaperead('maps/bou2_4p.shp', 'UseGeoC ...

  8. 使用RTL-SDR,从打开一个车门到批量打开车门

    在最近几年,入侵汽车在当代社会的黑客圈中成为热点,很多文章表明汽车产业还有很多东西等待完善,在本篇文章中,我会让你熟悉我一直研究的一些概念,以及如何在网状网络中使用一些便宜的部件渗透远程开门系统. 软 ...

  9. 【Todo】Java的JIT机制

    先是参考了这篇说的不怎么详细的文章<Java的JIT机制>(Link) JIT是just in time,即时编译技术.使用该技术,能够加速java程序的执行速度. 通常javac将程序源 ...

  10. 关于文件与文件系统的压缩与打包命令-Linux(笔记)

    1.gzip : 压缩命令 gzip [-cdtv#] 文件名称 (后缀为.gz) -c :将压缩的数据输出到屏幕上,可通过数据流重定向处理 -d : 解压缩的參数 -v : 能够显示源文件/压缩文件 ...