一次全文索引编码实践


前端时间要处理一个即时输入提示和查询功能,一开始由于考虑到一个很特殊的需求,做相似度匹配(就是类似abc能匹配acb),所以用数据库的现成办法都不行,用全文索引也不行,因此第一个版本是前同事java版本,计算最深的一个查询一次执行5分钟,赶进度之下弄了第一个c++版本,直接内存缓存,用最简单的stristr等,加上一些预计算等优化手段,这个版本将最深查询做到了30ms左右,但这个版本用在多线程下要处理同步,要处理数据同步等工作,还是比较麻烦的,因此思索之下觉得相似度匹配可去掉,因此又回归数据库方法,自然是全文索引了,但初步用了下mysql的全文索引,基本能满足要求,但用数据库全文索引执行时快时慢,也调整了一些参数,扩大缓存等,结果依旧,关键慢的时候要几秒执行一次,快的时候倒是都能满足要求,这个测试是在本地进行的(win7x64),没有在服务器上测试,不知道在真正的服务器上测试效果是否会好一些。

抱着练练手的目的,尝试了一下自己做分词建反向索引查找等,花了几小时,写了约300行代码,基本实现简单的全文索引,用下来效果还可以,从50万记录建立名称等几个较短字段的全文索引,不限制结果集查询基本在1ms左右,如果限定为一个较小结果集则时间更短,用来做输入即时提示是足够用了。建立方法较简单,就是将单词切分,放在一个map(std::map<std::string, MTTSET, stringicmp>)里面,每个单词映射一个set(recordid,type),recordid为该单词对应的原始记录id,type为记录类型,用来标识word来源于什么类型的字段,根据recordid和type可定位原始记录,查询支持精确匹配模式和StartWith模式,精确匹配容易,直接用map的find即可,StartWith稍麻烦一点,当初选择map也是考虑到它有lower_bound

,用该函数先定位到可能匹配的首位置,然后依次比较,根据结果集的大小需求(类似limit),进行相应次数的计算比较,不限结果集则计算全集,如果是查找多个单词,也可指定结果集是or 关系或and 关系,这个只要对set求并或求交即可,非常简单。

由于是一次简单的练手,也没有考虑更复杂的如搜索短语等需求,因此在set(recordid,type)里面没有定义描述顺序的字段,也没有考虑标准全文索引一般要处理剔除一部分特殊词汇的需求,也没有考虑出现结果集过半等问题,也没有考虑中文分词(我需要查的全是英文)等,也没有考虑索引很大超过内存容量等问题,当然一个完善的全文索引还是较复杂的,但通过这次实践,增强了自己的信心,即使是做一个完善的全文索引,一步步从基本概念开始,要实现它还是可能的,我们虽然不需要重复制造轮子,但具备造轮子的能力熟悉内部实现细节,对用好现成工具还是有很大益处的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值