当前位置: 首页 > news >正文

Golang | 向倒排索引上添加删除文档

syntax = "proto3";package types;message Keyword {string Field = 1; // 属性/类型/名称string Word = 2;  // 关键词
}message Document {string Id = 1; //业务使用的唯一Id,索引上此Id不会重复uint64 IntId = 2; //倒排索引上使用的文档id(业务侧不用管这个字段)uint64 BitsFeature = 3;        //每个bit都表示某种特征的取值repeated Keyword Keywords = 4; //倒排索引的keybytes Bytes = 5;               //业务实体序列化之后的结果
}
// go install github.com/gogo/protobuf/protoc-gen-gogofaster@latest
// protoc --gogofaster_out=./types --proto_path=./types/proto doc.proto
type Document struct {Id          string     `protobuf:"bytes,1,opt,name=Id,proto3" json:"Id,omitempty"`IntId       uint64     `protobuf:"varint,2,opt,name=IntId,proto3" json:"IntId,omitempty"`BitsFeature uint64     `protobuf:"varint,3,opt,name=BitsFeature,proto3" json:"BitsFeature,omitempty"`Keywords    []*Keyword `protobuf:"bytes,4,rep,name=Keywords,proto3" json:"Keywords,omitempty"`Bytes       []byte     `protobuf:"bytes,5,opt,name=Bytes,proto3" json:"Bytes,omitempty"`
}

在这里插入图片描述

import "github.com/atopos31/go-velisearch/types"// 倒排索引统一接口
type IRverseIndexer interface {Add(doc types.Document) // keyword定位到某个value IntId在value的链式结构中确定位置Delete(IntId uint64, keyword *types.Keyword) // onFlag:所有 bits 必须完全匹配 offFlag所有 bits 必须完全不匹配 orFlags:bits 必须匹配 `orFlags` 列表中的所有标志中的至少一个。Search(query *types.TermQuery, onFlag uint64, offFlag uint64, orFlags []uint64) []string
}
import ("runtime""sync""github.com/atopos31/go-velisearch/types""github.com/atopos31/go-velisearch/util""github.com/huandu/skiplist"farmhash "github.com/leemcloughlin/gofarmhash"
)var _ IRverseIndexer = (*SkipListInvertedIndexer)(nil)type SkipListInvertedIndexer struct {table *util.ConcurrentHashMap // 使用分段锁保护的并发安全 map,用于存储倒排索引的数据locks []sync.RWMutex          // 针对相同的 key 进行竞争的锁,避免多个协程Add时数据丢失
}type SkipListValue struct {Id          string // 业务侧的IDBitsFeature uint64 // 文件属性位图
}func NewSkipListInvertedIndexer(docNumEstimate int) *SkipListInvertedIndexer {return &SkipListInvertedIndexer{// 小map数根据机器性能 依据核心数设置table: util.NewConcurrentHashMap(runtime.NumCPU(), docNumEstimate),locks: make([]sync.RWMutex, 1000),}
}func (indexer *SkipListInvertedIndexer) Add(doc types.Document) {for _, keyword := range doc.Keywords {Key := keyword.ToString()lock := indexer.getLock(Key)skipListValue := SkipListValue{Id:          doc.Id,BitsFeature: doc.BitsFeature,}lock.Lock()if value, exist := indexer.table.Get(Key); exist {list := value.(*skiplist.SkipList)list.Set(doc.IntId, skipListValue)} else {list := skiplist.New(skiplist.Uint64)list.Set(doc.IntId, skipListValue)indexer.table.Set(Key, list)}lock.Unlock()}
}func (indexer *SkipListInvertedIndexer) getLock(key string) *sync.RWMutex {n := int(farmhash.Hash32WithSeed([]byte(key), 0))return &indexer.locks[n%len(indexer.locks)]
}func (indexer *SkipListInvertedIndexer) Delete(IntId uint64, keyword *types.Keyword) {Key := keyword.ToString()lock := indexer.getLock(Key)lock.Lock()defer lock.Unlock()if value, exist := indexer.table.Get(Key); exist {list := value.(*skiplist.SkipList)list.Remove(IntId)}
}
func (kw Keyword) ToString() string {if len(kw.Word) > 0 {return kw.Field + "\001" + kw.Word}return ""
}

相关文章:

  • 【PCL】实现CloudCompare的连通域点云聚类功能
  • 机器学习基础——Seaborn使用
  • AI 数据中心 vs 传统数据中心:从硬件架构到网络设计的全面进化
  • Python教程(二)——控制流工具前半部分
  • 常用的性能提升手段--提纲
  • 关于华为高斯数据库出现Invalid or unsupported by client SCRAM mechanisms定位解决的过程
  • 互斥量函数组
  • 谢飞机的Java面试之旅:从Spring Boot到Kubernetes的挑战
  • rockermq多线程消费者配置
  • 【数据可视化-38】基于Plotly得泰坦尼克号数据集的多维度可视化分析
  • 目标跟踪最新文章阅读列表
  • PlatformIO 入门学习笔记(二):开发环境介绍
  • 国标GB28181视频平台EasyGBS打造生产监控智能体系,推动企业数字化升级
  • 2025蓝桥杯省赛网络安全组wp
  • 【Nova UI】十二、打造组件库之按钮组件(上):迈向功能构建的关键一步
  • 准确--如何在自己windows电脑上安装多个nodejs版本,自由切换
  • ES练习册
  • C++ AVL树的实现
  • 《AI大模型应知应会100篇》第38篇:大模型与知识图谱结合的应用模式
  • 【创新实训项目博客】数据库搭建
  • 全过程人民民主研究基地揭牌,为推动我国民主政治建设贡献上海智慧
  • 滨江集团去年营收约691亿元,尚未结算的预收房款1253亿元
  • 核电开闸!国常会核准10台新机组,拉动超2000亿投资,新项目花落谁家?
  • 天津外国语大学原校长修刚突发疾病去世,享年68岁
  • 女儿被偷拍后,一个父亲的战斗
  • 游戏论|迟来的忍者与武士:从《刺客信条:影》论多元话语的争议