MongoDB 中,全文索引(Full-Text Index)是一种用于支持全文搜索的索引类型。它可以用于在文本数据中执行高效的文本搜索和匹配操作。
全文检索对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。
这个过程类似于通过字典中的检索字表查字的过程。
MongoDB 从 2.4 版本开始支持全文检索,目前支持15种语言的全文索引。
danish
dutch
english
finnish
french
german
hungarian
italian
norwegian
portuguese
romanian
russian
spanish
swedish
turkish
MongoDB 在 2.6 版本以后是默认开启全文索引的,如果你使用之前的版本,你需要使用以下代码来启用全文索引:
db.adminCommand({ setParameter:true, textSearchEnabled:true })
或者使用命令:
mongod --setParameter textSearchEnabled=true
要在 MongoDB 中创建全文索引,需要使用 text 索引类型。可以在集合上使用 createIndex() 方法创建全文索引,指定要索引的字段和索引的类型。例如:
# col 集合数据如下 > db.col.find() { "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 3, "email" : "zhangsan@outlook.com", "sex" : "male" } { "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com lis@163.com ls@gmail.com", "sex" : "female" } { "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 27, "email" : "wangwu@sina.com.cn", "sex" : "male" } { "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 22, "email" : "zhaoliu@gmail.com", "sex" : "female" } { "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com guq@163.com", "sex" : "male" } { "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" } # 在 col 的 email 字段上创建全文索引 > db.col.createIndex({ email:"text" }) { "numIndexesBefore" : 2, "numIndexesAfter" : 3, "createdCollectionAutomatically" : false, "ok" : 1 }
在上面的示例中,name 是要创建全文索引的字段。
一旦创建了全文索引,就可以使用 $text 操作符进行全文搜索。可以在查询中使用 $text 操作符,指定要搜索的关键词。例如:
> db.col.find({ $text:{$search:"163"} }) { "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com guq@163.com", "sex" : "male" } { "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com lis@163.com ls@gmail.com", "sex" : "female" }
上面例子中,163 是要搜索的关键词。
删除已存在的全文索引,可以使用 getIndexes() 命令获取所有的索引信息,例如:
> db.col.getIndexes() [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" }, { "v" : 2, "key" : { "name" : 1, "age" : 1 }, "name" : "name_1_age_1" }, { "v" : 2, "key" : { "_fts" : "text", "_ftsx" : 1 }, "name" : "email_text", "weights" : { "email" : 1 }, "default_language" : "english", "language_override" : "language", "textIndexVersion" : 3 } ]
上面命令的输出中,名为 “email_text” 的就是刚刚创建的全文索引。然后,通过索引名 email_text,执行以下命令来删除索引:
> db.col.dropIndex("email_text") { "nIndexesWas" : 3, "ok" : 1 }
在多个字段上创建文本索引时,还可以使用通配符说明符 $**。使用通配符文本索引,MongoDB 会为包含集合中每个文档的字符串数据的每个字段编制索引。以下示例使用通配符说明符创建文本索引:
# 创建通配符全文索引 > db.col.createIndex( { "$**": "text" } ) { "numIndexesBefore" : 1, "numIndexesAfter" : 2, "createdCollectionAutomatically" : false, "ok" : 1 } # 下面例子证明了在 name 和 email 上面均存在全文索引 > db.col.find({ $text:{$search:"sina"} }) { "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 27, "email" : "wangwu@sina.com.cn", "sex" : "male" } > db.col.find({ $text:{$search:"张三"} }) { "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 3, "email" : "zhangsan@outlook.com", "sex" : "male" }
此索引允许在包含字符串内容的所有字段上进行文本搜索。如果不清楚要包含在文本索引中的哪些字段或用于临时查询,则此类索引对于高度非结构化数据可能很有用。
通配符文本索引是多个字段上的文本索引。因此,您可以在创建索引期间为特定字段指定权重,以控制结果的排名。有关使用权重控制文本搜索结果的更多信息,请参阅使用权重控制搜索结果。
与所有文本索引一样,通配符文本索引可以是复合索引的一部分。 例如,以下内容在字段a和通配符说明符上创建复合索引:
db.col.createIndex( { a: 1, "$**": "text" } )
与所有复合文本索引一样,由于 a 位于文本索引键之前,因此为了使用此索引执行 $text 搜索,查询谓词必须包含 a 的相等匹配条件。
文本索引总是稀疏的,并忽略稀疏选项。如果文档缺少文本索引字段(或者字段为null或空数组),则 MongoDB 不会将文档条目添加到文本索引中。对于插入,MongoDB 插入文档但不添加到文本索引。
对于包含文本索引键和其他类型键的复合索引,只有文本索引字段确定索引是否引用文档。其他键不确定索引是否引用文档。
MongoDB 全文索引有一些限制和特性,其中包括:
默认情况下,全文索引不会包括短词(少于三个字符)和常见词(停用词)。
全文索引使用自然语言文本搜索,支持词根和词形的搜索。
一个集合最多可以有一个文本索引。
文本搜索和提示,如果查询包含 $text 查询表达式,则不能使用hint()。
文本索引和排序,排序操作无法从文本索引获取排序顺序,即使是复合文本索引也是如此。即排序操作不能使用文本索引中的排序。
复合索引,复合索引可以包括文本索引键与升序/降序索引键的组合。但是,这些复合索引具有以下限制:
复合文本索引不能包含任何其他特殊索引类型,例如多键或地理空间索引字段。
如果复合文本索引包括文本索引键之前的键,则执行 $text 搜索时,查询谓词必须包含前面键上的相等匹配条件。
创建复合文本索引时,必须在索引规范文档中相邻地列出所有文本索引键。
ngoDB 还提供了一些高级功能来支持更复杂的全文搜索需求,包括:
使用 $language 操作符指定搜索的语言。
使用 $caseSensitive 操作符指定搜索是否区分大小写。
使用 $diacriticSensitive 操作符指定搜索是否区分重音符号。
例如:
> db.col.find({ $text: { $search: "sina", $language: "en", $caseSensitive: true } }); { "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 27, "email" : "wangwu@sina.com.cn", "sex" : "male" }
在上面的示例中,$language 操作符指定了搜索的语言为英语,$caseSensitive 操作符指定了搜索区分大小写。