php是可以做搜索引擎的,这里是用纯php代码,实现百万到千万的数据搜索尝试。
目标,单机能够索引1000万条内容。
更新:目前单机能索引5000万的数据。//2024-5-20
在做这个php搜索功能之前,我也了解过当前的,比如elasticsearch等,一些已经非常成熟搜索软件的基本原理。想了解搜索引擎的流程,可以移步我的其它文章,有详细讲解,这里大致介绍一下我的php搜索引擎基本逻辑。
现在的整个架构包括内容爬取、清洗、入库、索引、搜索。当然,索引功能,是可以单独拿出来的,如果你不想爬取网页,只是想搜索自己的内容,定制改动一下是完全可以的。这些基本流程不多说。
导入数据
爬取网页
可以爬取指定网页,只要把你想爬取的(可能是某一类的)网站链接,放在一个txt文件内,普通笔记本就足够,就可以很轻松地对这些链接进行多线程爬取。只要你的电脑性能达到中等,设置好爬取层数,每次可以爬取到几十万的网页,也不能爬取太深,不然,别人的服务器压力太大。
自定义内容
你也可以在数据库放入你自己想要搜索的内容。
中文分词
php的分词工具也很多,如果你的领域很垂直,那么词库的构建就很重要的。常规分词的基本方法都是正反最大匹配,相对而言,反向最大匹配效果更好一些,或者两者结合取其优。
如果不想使用这些分词工具,也可以进行n-gram切词,设定一个窗口,例如两个字符,然后从字符串的起始位置,开始向后移动,比如“明天会更好”这句话,移动0次,得到“明天”,移动一次,得到“天会”,移动两次,得到“会更”,以此类推。
n-gram方法可以达到“分词的效果”,但是会造成无意义字符串过多,索引数据量非常庞大。这种方法的召回率也不如专业的分词工具,不过,用还是可以用的。
倒排索引
索引压缩存储
当数据比较少时,可以不用太关注数据结构算法,使用简单的存储逻辑就可以达到效果,速度也能保证。当数据达到百万、甚至千万时,就不得不去探索更高效的数据结构了,在高级版本上,我使用了bitmap存储结构。bitmap算法在少量数据时,并没有什么优势,当然也不会比其它算法效率差,当数据及其庞大时,优势瞬间体现出来了,能够很大程度上节约存储空间。
索引压缩存储,还有其他的方式,比如RBM,FOR算法。
这里有一个问题,最后进行多term集合的计算,并集或交集,不还是要加载完整的倒排链到内存?存储阶段可以压缩,缓解磁盘压力,在最后的计算阶段,依然要加载到内存,如果倒排链长度很长,那对内存的要求还是挺高的。不知道这里有没有什么其他优化方案。
增量索引
当数据量越来越大时,每次都更新全部索引,是非常耗时间的,这里加入了增量索引功能,每次只需要更新已经插入的内容的索引即可,随后会将这部分新增索引与主索引合并。
实时索引
如果有实时搜索要求,这里也实现了这个功能。实时索引需要在数据保存的时候,就进行即时的分词、建立索引,就是系统的工作量有点大,毕竟每次插入都进行了索引建立的全流程。我的实时索引的结构跟主索引的结构是一样的,这样利于查询下索引的时候索引数据合并,不过只要能达到效果,具体怎么存储,看自己。
搜索时,这里有两种处理方式:
1,分别读取主索引和实时索引,再分别进行搜索,再合并结果;
2,先把实时索引与主索引合并,再搜索。
实时索引效果:
整个搜索过程不需要任何操作,正常搜索即可,可以达到即插即搜的效果。另外,实时索引是额外的索引文件,当实时索引量达到指定的数值时,可以自动将实时索引数据合并到主索引数据上,然后删除实时索引。不过,开启实时索引会增加处理器负担,毕竟实时处理的过程太多。
搜索召回
这里有几个不得不面对的问题:
- 随着数据量增加,搜索响应时间变慢的问题
- 召回率的问题
- 相关性计算排序问题
对于搜索响应时间变慢的问题
这里的逻辑是,搜到符合的结果即返回。这样在海量数据的情况下,不必计算所有的数据,实际上,数据量过大时,计算所有的数据也是不现实的,除非机器性能够好。当计算结果达到要求时,直接返回搜索结果,这样能保证,即使数据达到了最大承受量(目前至少1000万),也能在很短的时间内返回结果,同时并不影响把最符合的结果找出来。
对于召回率
- 分词细粒度化
在前端分词细粒度化,可以提高召回率,缺点就是有可能结果不那么精确。
- 加入近义词 提高搜索泛化能力
用户的query并不一定都是完整、无错误的,更有可能搜索词与想要搜索的内容区别很大,这时,为了提高召回率,可以进行query改写:
- 加入近义词搜索,比如,用户搜索“马铃薯”,这时可以同时搜索“土豆”,因为两者是一样的意思,这样召回率能够大大提高;
- term纠错,对用户输入的错字/错词/拼音内容,进行纠正,这个技术我还不会。。。
对于相关性计算排序问题
相关性计算能够大幅度提高排序质量,如果只是基于基础的文本匹配方法,例如tf-idf,能达到一定的效果,但远远不够,这时可以向量化,计算内容相似度,用这种方法作为补充。
从多维度进行内容评分,最后进行加权求和,也是一种方法。
细节优化
- 去除停用词
有时候用户是复制一句话进行搜索,文字里面包含很多标点符号、特殊符号,我在测试过程中,发现这些无意义的词、符号,它的倒排链非常长,搜索的时候,造成过多无意义计算,严重拖累搜索速度。显然这些都是干扰,绝大部分符号都是无意义的,如果不剔除,会影响召回效果。去除这些停用词是必须的。
- 多级缓存
为了最大限度保证搜索召回的速度,加入了多级缓存,比如索引聚合结果的缓存,这样,同一个搜索内容第二次出现时,就可以使用已经计算好的结果,直接查询数据库,快速显示到前端页面上。
关于
整个过程不需要安装任何扩展,可直接运行php文件。使用也很简单,本地搭建一个集成环境,源码扔进去,就可以使用了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。