MongoDB,正则表达式查询在索引字段上的性能

58

我想在一个包含50K个账户的MongoDB集合中,通过名字查找账户。

通常的方法是:使用字符串查找。

db.accounts.find({ name: 'Jon Skeet' })  // indexes help improve performance!

正则表达式怎么样?这是一个昂贵的操作吗?

db.accounts.find( { name: /Jon Skeet/ }) // worry! how indexes work with regex?

编辑:

根据WiredPrairie的说法:
MongoDB使用正则表达式的前缀来查找索引(例如:/^prefix.*/):


db.accounts.find( { name: /^Jon Skeet/ })  // indexes will help!'

MongoDB $regex


7
@dirkk,我希望能够获得更多经验和解释,并且我也想分享这个问题。请帮我翻译。 - damphat
3
正则表达式要使用索引,必须像文档中所示使用锚点:http://docs.mongodb.org/manual/reference/operator/regex/。 - WiredPrairie
可能是重复的问题:如何使用“like”查询mongodb?(https://dev59.com/8XA75IYBdhLWcg3wboUz) - WiredPrairie
在StackOverflow上已经有许多非常相似的问题得到了解答。 - WiredPrairie
1
@WiredPrairie 我想专注于性能,而不是如何进行查询。 - damphat
显示剩余2条评论
2个回答

60

根据文档,实际上:

如果字段存在索引,则MongoDB将正则表达式与索引中的值进行匹配,这可能比集合扫描更快。如果正则表达式是“前缀表达式”,则可以进一步优化,这意味着所有潜在匹配项都以相同的字符串开头。这使得MongoDB可以从该前缀构造一个“范围”,并仅针对落在该范围内的索引值进行匹配。

http://docs.mongodb.org/manual/reference/operator/query/regex/#index-use

换句话说:

对于正则表达式 /Jon Skeet/ ,Mongo会全面扫描索引中的键,然后获取匹配的文档,这可能比集合扫描更快。

对于正则表达式 /^Jon Skeet/ ,Mongo只会扫描以该正则表达式开头的范围,从而提高速度。


1
如果有立即匹配(例如:匹配字母“a”)则正则表达式可以正常工作。但是,如果我匹配一个完整的单词,则结果需要更长时间(例如:“angular”)。这是在600万个文档中进行的,有没有办法加快这些查询速度?对于8个或更多字符,它们需要19-30秒左右,但对于1-2个字符,它们会立即返回。 - chovy
1
@chovy,我认为MongoDB不是在文本中搜索字符串出现的最佳工具 - 我建议看看ElasticSearch或任何其他全文搜索引擎。 - heroin

13

如果仍有人对搜索性能有疑虑,即使搜索一个句子中的单词(不一定在字符串的开头 ^ 或结尾 $),也有一种方法可以优化正则表达式搜索。

该字段应该具有文本索引。

db.someCollection.createIndex({ someField: "text" })

在执行普通搜索后,查询应该仅使用正则表达式。

db.someCollection.find({ $and: 
  [
    { $text: { $search: "someWord" }}, 
    { someField: { $elemMatch: {$regex: /test/ig, $regex: /other/ig}}}
  ]
})

这确保了正则表达式只运行在最初普通搜索的结果上,由于该字段上存在索引,因此搜索速度应该相当快。 这可能会对搜索性能产生巨大影响,具体取决于集合的大小。


1
感谢您的输入。不过,我仍然需要处理两个搜索条件。一个是整个单词,另一个是单词的一部分。 - Revol89
如果您不是在搜索完整单词,这并不会真正起作用。如果您按文本索引搜索,“some”将返回空值。 - FINDarkside
这个有更新了吗? - Alex Totolici
对于任何无法理解其背后逻辑的人:https://medium.com/statuscode/how-to-speed-up-mongodb-regex-queries-by-a-factor-of-up-to-10-73995435c606 - Waleed Ahmad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接