mongodb高级教程(mapReduce、全文搜索和正则表达式用法详解)

上一篇我们讨论了创建高级索引、限制索引和ObjectId结构,本章我们一起来学习mongodb里面的一些高级用法:mapReduce和全文搜索。
一、mapReduce命令Map-reduce用于将大量数据压缩成有用的聚合结果,map-reduce操作使用mapReduce命令,该命令通常用于处理大型数据集。
下面是基本mapReduce命令的语法:

>db.collection.mapReduce( function() {emit(key,value); },//map方法 function(key,values) {return reduceFunction}, {//reduce方法 out: collection, query: document, sort: document, limit: number } )

map-reduce函数首先查询集合,然后将结果文档映射为发出键-值对,然后根据具有多个值的键对减少键-值对。
在上面的语法中:
  • map是一个javascript函数,它用一个键映射一个值并发出一个键-值对
  • reduce是一个javascript函数,它减少或分组具有相同键的所有文档
  • out指定map-reduce查询结果的位置
  • query指定用于选择文档的可选选择条件
  • sort指定可选的排序条件
  • limit指定要返回的可选文档的最大数量
使用mapReduce
考虑以下存储用户帖子的文档结构,该文档存储用户的user_name和post的状态。
{ "post_text": "La Oreja De Van Gogh", "user_name": "V", "status":"active" }

我们将在posts集合上使用mapReduce函数来选择所有活动的post,根据user_name对它们进行分组,然后使用以下代码计算每个用户的post数量
>db.posts.mapReduce( function() { emit(this.user_id,1); }, function(key, values) {return Array.sum(values)}, { query:{status:"active"}, out:"post_total" } )

上面的mapReduce查询输出以下结果
{ "result" : "post_total", "timeMillis" : 9, "counts" : { "input" : 4, "emit" : 4, "reduce" : 2, "output" : 2 }, "ok" : 1, }

结果显示总共有4个文档匹配查询(status:“active”),map函数发出4个键值对的文档,最后reduce函数将具有相同键的映射文档分组为2个。
要查看此mapReduce查询的结果,请使用find操作符:
>db.posts.mapReduce( function() { emit(this.user_id,1); }, function(key, values) {return Array.sum(values)}, { query:{status:"active"}, out:"post_total" } ).find()

上面的查询给出了以下结果,表明用户A和B都有两个处于活动状态的帖子:
{ "_id" : "A", "value" : 2 } { "_id" : "B", "value" : 2 }

以类似的方式,MapReduce查询可用于构造大型复杂的聚合查询,自定义Javascript函数的使用充分利用了MapReduce的灵活性和强大功能。
二、全文搜索MongoDB从2.4版开始支持使用文本索引来搜索字符串内容。文本搜索使用词干分析技术,通过删除词干分析停止词(如英语中的a、an、The等)来查找字符串字段中的指定单词,MongoDB支持大约15种语言。
1、启用全文搜索
文本搜索最初是一个实验性的特性,但从2.6版开始,默认启用了该配置。不过如果你使用的是以前的MongoDB版本,则必须使用以下代码启用全文搜索:
>db.adminCommand({setParameter:true,textSearchEnabled:true})

2、创建全文索引
考虑以下post集合中的文档,其中包含post文本及其标记:
{ "post_text": "Mi Casa", "tags": [ "mongodb", "database" ] }

我们将在post_text字段上创建一个文本索引,这样我们就可以在帖子的文本中进行搜索:
>db.posts.ensureIndex({post_text:"text"})

3、使用全文索引
现在我们已经在post_text字段上创建了文本索引,我们将搜索文本中包含Casa这个单词的所有文章。
>db.posts.find({$text:{$search:"Casa"}})

如果你正在使用旧版本的MongoDB,你必须使用以下命令:
>db.posts.runCommand("text",{search:" Casa "})

与普通搜索相比,使用文本搜索大大提高了搜索效率。
4、删除全文索引
要删除现有的文本索引,首先使用以下查询查找索引的名称:
>db.posts.getIndexes()

在从上述查询中获得索引名称之后,运行以下命令。这里的post_text_text是索引的名称。
>db.posts.dropIndex("post_text_text")

三、正则表达式正则表达式在所有语言中都经常用于搜索任何字符串中的模式或单词,MongoDB还提供使用$regex操作符进行字符串模式匹配的正则表达式功能。MongoDB使用PCRE (Perl兼容的正则表达式)作为正则表达式语言。
与文本搜索不同,我们不需要进行任何配置或命令来使用正则表达式。考虑以下post集合下的文档结构,其中包含post文本及其标记:
{ "post_text": "La casa", "tags": [ "mongodb", "database" ] }

1、使用正则表达式
下面的regex查询将搜索其中包含字符串casa的所有文章:
>db.posts.find({post_text:{$regex:"casa"}})

同样的查询也可以写成:
>db.posts.find({post_text:/casa/})

2、使用不区分大小写的正则表达式
为了使搜索不区分大小写,我们使用$options参数,其值为$i。下面的命令将查找单词casa的字符串,而不管它是小的还是大写的:
>db.posts.find({post_text:{$regex:"casa",$options:"$i"}})

3、对数组元素使用regex
我们也可以在数组字段上使用regex的概念。当我们实现标记的功能时,这一点尤其重要,因而如果你想搜索所有以casa开头的标记的文章,你可以使用以下代码:
>db.posts.find({tags:{$regex:"casa"}})

4、优化正则表达式查询
(1)如果文档字段被索引,那么查询将使用索引值来匹配正则表达式。与扫描整个集合的正则表达式相比搜索效率更快。
【mongodb高级教程(mapReduce、全文搜索和正则表达式用法详解)】(2)如果正则表达式是前缀表达式,则所有匹配项都意味着以某个字符串字符开始。如果regex表达式是^cac,那么查询只能搜索那些以cac开头的字符串。

    推荐阅读