该项目是个一个用于对输入单词进行关联性分析,旨在为用户输入更好的查询建议的智能助手。实现了输入查询词,联想推荐出候选词,返回结果的整个输入助手的流程。本项目分为线下阶段,线上阶段,优化阶段三部分组成。线下部分读取中英文语料库
创建词典
,并根据词典创建倒排索引
;线上部分采用EchoLib框架
搭建服务器,根据请求的查询词,通过字符串分割查找倒排索引
选出候选词,使用最小编辑距离算法
,并创建优先级队列
,用jsoncpp
封装后返回结果给客户端。后期优化则创建磁盘Cache
与内存Cache
,采用LRU缓存淘汰算法
,并创建CacheManager定期更新回写Cache
。
1.首先搭建好线程池,启动线程时都在等待任务队列出任务
2.启动封装好的服务器程序,当客户端发来请求时,将此请求封装成一个任务,加入任务队列,让子线程去完成该任务
读取中英文语料库,存入词典
英文语料库:先使用正则表达式
将标点符号全部转换为空格,通过字符串流
分割单词,再将所有英文字母改为小写,最后存入词典,并记录词频。
中文语料库:使用cppjieba
将中文进行分词,存入词典,并记录词频。
创建倒排索引文件,可以极大的优化查询速度
什么是倒排索引?为什么可以极大的优化查询速度? https://baike.baidu.com/item/%E5%80%92%E6%8E%92%E7%B4%A2%E5%BC%95/11001569?fr=aladdin
倒排索引通俗的来说,我们在一般进行查询的时候,是先查找人名,搜索出对应的身高,体重信息; 倒排索引也就是根据身高信息,或是体重信息,来查找出对应的人名的集合。
首先使用中英文字符串分割算法
,将英文单词分割成单个字母,将中文分割成单个汉字;
创建倒排索引: hashmap<string, set< int > >
<单个字母或单个汉字,该字母或汉字的下标集合>
举例:
1.客户端查找 nike ,那么将其分割成 n , i, k, e,分别查找到所属 n, i, k, e 对应的下标集合
2.客户端查找 中国人, 那么将其分割成 中, 国,人,分别查找所属 中,国,人对应的下标集合
- 客户端发送
查询词
如中国人 - 服务器接收
查询词
中国人 服务器的处理流程如下:
-
先使用
中英文字符串分割算法
,将中国人 分割成 中,国,人; -
再利用
倒排索引
,找到中,国,人 ,所属单词的集合下标,找到所有的候选词,比如 国人, 人,中国; -
使用
最小编辑距离算法
,计算出所有候选词的与查询词的 最小编辑距离, 也就是计算国人,人,中国 与 中国人 之间的最小编辑距离。 -
创建
优先级队列
,优先级为 最小编辑距离 > 单词词频 > 单词字母顺序,取前K个结果。 -
将结果封装为json字符串,返回给客户端
- 客户端接受到返回的结果。
创建磁盘Cache
与 内存Cache
,对于用户已经查找过的单词可以做出快速反应(存储已经封装好的json string类型)。
-
内存Cache:每一个线程都拥有独立的内存Cache,所有的内存Cache都会有一个CacheManager单独管理,并且CacheManager需要定期汇总并更新各个线程的Cache,并写回磁盘Cache。
-
磁盘Cache:内存Cache在初始化时读取磁盘Cache。
-
缓存淘汰算法:
LRU算法
- 创建词典与索引文件
技术亮点:开源cppjieba分词库
,正则表达式
,UTF-8中英文编码处理
,文件流字符串流操作
, Unix目录操作
,单例模式(饿汉)
, 最小编辑距离算法
,优先级队列
- 搭建线程池框架
技术亮点:基于对象线程池设计
,Posix线程类,互斥锁,条件变量
,任务队列
,自动加解锁类
,子线程安全退出机制
,回调函数
, 智能指针unique_ptr
- 搭建服务器框架
技术亮点:基于对象服务器设计
,回调函数
,socket网络编程
,IO多路复用epoll
,eventfd(IO线程与计算线程分离)
,客户端安全退出机制
,智能指针shared_ptr
- 搭建引擎框架
技术亮点:内存Cache与磁盘Cache
,timerfd定时器(全局Cache更新)
,缓存淘汰策略LRU算法
,开源库jsoncpp