最近在快讯的项目是做一个全文搜索的知识库。本来一开始听到这个要求的时候,头皮有点发麻,因为他要求三层类别层级,然后支持全文搜索。全是我未知的领域。
但是事实证明,压力能给你带来很多意想不到的东西。刚开始接到要求,我第一反应就是谈判,减低要求。奈何和我一组的老哥一直点头说没问题。于是,便开始了这个需求的学习。
全文搜索
全文搜索,听起来好像很高大上,很难搞定。但是其实原理只有两个:关联的模糊搜索(高端点可以利用索引)和中文分词。
关联的模糊搜索以及索引
索引这个,奈何我自己的数据库知识不是特别扎实,所以看了挺多资料之后也没特别搞懂。今天在具体实现的时候,发现sequelize在官方文档的实例里用到这样一招,让我茅塞顿开。
大致的意思就是,将满足title
列模糊查询或者content
列模糊查询得到的结果都提取出来。这不就是全文搜索么!!!只是,索引的使用我猜可能会更高效?或者更便捷?但是我相信原理应该就是如此。
索引
虽然没实践成功,但是可以mark一下。利用的是mysql的FULLTEXT索引
MYSQL全文搜索通过 MATCH() 函数完成。
在全文索引上进行搜索是不区分大小写的。 下面再看如何实现中文全文检索。 fulltext字段是以词语为单位,词语之间需要用空格隔开,而汉语的句子中各个词语之间并不会用空格隔开,因此我们需要对中文进行分词,这也就是为什么上面需要强词用到中文分词扩展模块。 但是尽管对中文进行分词,MYSQL还是不能通过MATCH来实现中文的全文检索,这需要通过一定的方法来进行转换,一个比较简单实用的方法是采用下面这个函数(当然还有更好的),它将中文进行了urlencode转换。
将转换过后的内容保存至事先定义好的fulltext字段。同样,在查询的时候也需要将查询的关键词进行同样方法的转换。
中文分词
一开始查的文档,实在有点凶残。一直在教如何建立一个中文分词的算法,看到我头皮发麻。但是这是node啊!不找模块算什么。于是便遇到了它node-segment
直接解决了我最麻烦的问题,自动分词。大概的代码贴上:
之后剩下的问题就是如何将所有结果组合起来而已了~~~
后记
在写完后,又断断续续地发现仅仅如此处理分词,可能没办法达到全文搜索优化的效果。例如,假设用户要搜索的就是”深圳大学体质测试通知”。而在数据库中正好也躺着这么一个标题命名的文章,本来是100%匹配的结果的。然而,由于我引入的分词模块的影响,这段文字被分成了"深圳""大学""体质""测试""通知"
这几段文字,由此可见,它将会匹配到一些莫名其妙的东西然后才匹配到我们想要的结果。这不得不说是十分影响体验的。暂时想到的解决办法就是先将字段分词,分词完毕后再将原字段插入到数组的第一个位置上去unshift()
。提高文本的命中率。
还有一个点就是,因地制宜地制定适合的字典。例如’深圳大学’,明显这个字段在深大是不需要分割,或者说不能分割的。然而,因为使用的是通用词典,所以在这些地方会显得特别的鸡肋。想到的解决办法就是记录用户的使用习惯,最后因地制宜地编写更适合的字典文件。例如用户输入’体侧’,我们可以自动补全为’体质测试’。
分词是全文搜索最重要的环节,所以远远不是几行代码就可以处理完毕的。可以更加深入地探究如何提高搜索结果的匹配度。