在这篇文章中,我将讨论两种在 mongodb 集合中进行文本搜索的方法之间的区别,并比较它们的复杂性、优缺点。

案例研究

考虑使用帖子集合,其中每个对象都包含标题和内容:

"_id": ObjectId(""),
"title": "PostA",
"content": "This is the content for the first post."
},
{
"_id": ObjectId(""),
"title": "PostB",
"content": "This is a different content for the second post."
}

进入全屏模式 退出全屏模式

我们的目标是搜索一些文本并返回匹配的文档。

使用正则表达式

如果我们想搜索标题,使用普通的查找过滤器会很容易

db.posts.find({title: "PostA"})

如果我们确切地知道标题或使用正则表达式,如果我们知道它的一部分

db.posts.find({title: 'pattern', $options: '<options>'})

但是如果我们想在内容字段中搜索,使用这个

db.posts.find({content: "first"})

将不返回任何内容,因为它将搜索完全匹配。

所以,我们可以在这里使用正则表达式

db.posts.find({content: {$regex: /first/}})

此查询将返回 PostA 文档,因为它的内容包含单词 first。

但这将对 O(n) 进行完整的集合扫描,并且在较大的数据集上性能较差。

使用文本索引

文本索引:它将文本转换为单个单词的数组,并删除所有停用词(is、a、an 等)

让我们在内容字段上创建一个文本索引

db.posts.createIndex({content: "text"})

并且不要忘记指定“文本”以删除不需要的单词并存储关键字。

搜索一个词

db.posts.find({$text: {$search: "first"}})

这将返回 PostA。

为什么我们没有在上述查询中搜索我们的内容? 🤔

由于 mongo 将此索引视为按顺序排列的单词数组,如果您想为此文本索引添加另一个字段,例如,我们可以将标题和内容添加到索引中,它将仅在一个文本下处理它们。

例子

db.posts.createIndex({title: "text", content: "text"})

注意:当已经有另一个文本索引时,我们不能添加另一个文本索引,因此这些下一行是非法的,我们应该立即添加它们,

 db.posts.createIndex({content: "text"})
 db.posts.createIndex({title: "text"})

进入全屏模式 退出全屏模式

好的,现在我们有一个标题和内容的组合索引,所以如果我们使用任何关键字搜索标题或内容,它将返回正确的匹配文档。

这种方法在复杂性方面将非常有效,因为它在可用性方面也使用 indexScan ( O(log(n)) ),而不是在特定字段中搜索,这将在组合的多个字段中进行搜索,这更实用。

使用文本索引排除单词

让我们尝试搜索内容包含“post”关键字的帖子

db.posts.find({$text: {$search: "post"}})

此查询将返回 PostA 和 PostB 文档,但如果我们排除 'first' 关键字,我们只能返回 PostB:

db.posts.find({$text: {$search: "post -first"}})

这将排除内容包含“第一”一词的文档。

结论

最后我们看到使用文本索引更快,更容易,更可取,并且支持关键字排除,但是我们还有一些其他情况,当我们想要搜索子字符串或部分单词匹配时,例如 PostB 中的单词 Post 在这种情况下我们有使用正则表达式。

Logo

MongoDB社区为您提供最前沿的新闻资讯和知识内容

更多推荐