前面说过,接收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. 标准C程序设计七---20

    Linux应用             编程深入            语言编程 标准C程序设计七---经典C11程序设计    以下内容为阅读:    <标准C程序设计>(第7版) 作者 ...

  2. R语言入门-画图(二)--heatmap

    一.函数参数: pheatmap参数: treeheight_row #横有多长 treeheight_col #竖有多长 cluster_cols=FLASE #单一方向聚类,也就是只有一边有树状结 ...

  3. 开始学习Objective-C

        加油!     顺便试试这MarsEdit好用不~

  4. Jmeter中处理json

    我们在做http接口测试的时候,返回的数据都是json串,Jmeter中本身是不支持直接处理json串的,如果要获取到返回结果中指定的值,必须要要通过正则表达式来获取到,正则表达式比较麻烦,写错了就获 ...

  5. Eclipse编译无响应

    Eclipse编译无响应 Eclipse进程无响应结束进程后,或电脑直接断电后,重新打开Eclipse偶尔重新编译会卡进度,下面有一种解决方案: 首先找到卡进度的工程的名字,关闭Eclipse,找到该 ...

  6. 使用Reveal 调试iOS应用程序

    Itty Bitty Apps发布了一款实用工具——Reveal,它能够在运行时调试和修改iOS应用程序.Reveal能连接到应用程序,并允许开发者编辑各种用户界面参数,这反过来会立即反应在程序的UI ...

  7. 统计显著性(Statistical significance)

    显著性,又称统计显著性(Statistical significance), 是指零假设为真的情况下拒绝零假设所要承担的风险水平,又叫概率水平,或者显著水平. [1] 显著性的含义是指两个群体的态度之 ...

  8. 【Todo】Java类面试题分析

    Java 面试中的重要话题 多线程,并发及线程基础数据类型转换的基本原则垃圾回收(GC)Java 集合框架数组字符串GOF 设计模式SOLID (单一功能.开闭原则.里氏替换.接口隔离以及依赖反转)设 ...

  9. SQL SELECT TOP, LIMIT, ROWNUM 子句

    SQL SELECT TOP, LIMIT, ROWNUM 子句 SQL SELECT TOP 子句 SELECT TOP 子句用于规定要返回的记录的数目. SELECT TOP 子句对于拥有数千条记 ...

  10. linked-list-cycle-ii——链表,找出开始循环节点

    Given a linked list, return the node where the cycle begins. If there is no cycle, returnnull. Follo ...