对MongoDB中的数据进行搜索(1)

由于大量的数据使用MongoDB作为数据库进行存储,现在需要对外提供文本搜索功能,在实践工程中,调研并尝试了多种方案,在本文中做个记录。

1、使用正则表达式

即使用find("textField":/搜索文本/}的方式对文本字段进行包含匹配。

这种方法的好处在于不需要进行额外的操作,现在常用的MongoDB服务器版本都能够支持,非常方便。

但是同时,缺点也非常明显,每次搜索必须遍历所有的数据,消耗的时间与数据量成正比,且基本无法进行优化。在大数据量情况下每次搜索小号的时间太长,可能无法接受。

 

2、分词存储

基本的步骤如下:

1、使用分词引擎对目标文本字段,例如textField进行分词

2、将分词的结果的每个词按照数组的形式存储在一个新的字段,例如searchField中

3、对searchField建立索引

4、搜索时,对请求串进行同样的分词,并将分词结果作为参数进行find({ searchField: {$all: splittedTextArray} })

这种方法的好处在于,适用于各个版本的MongoDB,同时基于索引和MongoDB对于数组的专门优化,在一定数据量的情况下速度也还可以

如果要使用这种方法,需要在新数据入库时进行处理

功能上比较简单,很多搜索常用的需求无法实现,效率也比不上专业的搜索引擎。可以作为一种无法增加组件时的参考方案。

 

3、使用MongoDB自带的文本搜索功能

MongoDB在较早的版本中就已经将文本搜索功能作为实验性功能加入,当时需要使用runCommand作为系统命令进行调用。

在后来的版本中作为正式的功能引入,直接就可以使用find({"$text":{"$search":"搜索文本"})进行搜索

在搜索之前,需要对文本字段建立索引:

db.coll.createIndex( { textField: "text" } )

对于一个集合,只能建立一个索引,但是一个索引中可以包含多个字段

文本搜索的参数有如下几个:

$search: <string>,
$language: <string>,
$caseSensitive: <boolean>,
$diacriticSensitive: <boolean> 

$search后面的关键词可以有多个,并且可以使用一些符号表示与或非的关系

使用$caseSensitive设置是否区分大小写,$language指示搜索的语言类型

$diacriticSensitive设置是否区别发音符号,例如,CAFÉ于Café是同一语义,只是重音不一样。

并且在结果中,可以使用{score:{$meta:"textScore"}来获得相似度

 

不过,只有在Mongodb 3.2之后的企业版中才开始加入了对中文的支持,之前或者社区的版本在建立全文索引时会自动过滤中文字符。

在Mongodb 3.2企业版中,对中文建立全文索引后,默认使用的是与英文同样的分词规则,即以空格与符号作为词与词之间分隔的界限。

所以,当使用“福尔摩斯”作为搜索词时,无法搜索到“福尔摩斯探案全集”,只能搜索到类似“福尔摩斯(1)”之类的结果

如果想解决这种情况,可以有两种方法:

一、在存储文本时,自行先对该文本进行分词处理,将需要搜索的文本加上空格即可

二、为MongoDB添加中文分词的支持

MongoDB企业版集成了基础技术Rosette 语义平台(RLP)根据语言来进行正规化、分词、断句、词干和分词。所以,可以使用RLP来实现对中文分词的支持。

如果想在MongoDB中使用RLP,MongoDB需要一个RLP基础语义组件的许可证。具体如何获得RLP的许可证,需要联系basistech公司。

当从basistech公司的邮件中获取了RLP证书文件(rlp-license.xml)后,解压拷贝到对应的目录中

<BT_ROOT>/rlp/rlp/licenses

然后使用参数指定该目录,重启MongoDB即可

--basisTechRootDirectory=<BT_ROOT>

 

posted @ 2017-03-26 23:14  ruizhang3  阅读(5296)  评论(0编辑  收藏  举报