MongoDB,通过正则表达式对索引字段的查询性能

Posted

技术标签:

【中文标题】MongoDB,通过正则表达式对索引字段的查询性能【英文标题】:MongoDB, performance of query by regular expression on indexed fields 【发布时间】:2013-07-04 07:39:38 【问题描述】:

我想按名称查找帐户(在 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 使用 RegEx 的 prefix 来查找索引(例如:/^prefix.*/):

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

MongoDB $regex

【问题讨论】:

@dirkk,我想获得更多的经验和解释。我也想分享这个问题。 要使正则表达式使用索引,它必须使用文档中所示的锚点:docs.mongodb.org/manual/reference/operator/regex How to query mongodb with "like"?的可能重复 *** 上已经回答了许多其他非常相似的问题。 @WiredPrairie 我想关注性能而不是如何进行查询。 【参考方案1】:

其实根据文档,

如果字段存在索引,则 MongoDB 匹配正则 针对索引中的值的表达式,这可能比 收藏扫描。如果常规的可以进一步优化 表达式是一个“前缀表达式”,这意味着所有潜在的 匹配以相同的字符串开头。这允许 MongoDB 构建一个 来自该前缀的“范围”,并且仅匹配来自该前缀的那些值 范围内的索引。

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

换句话说:

对于/Jon Skeet/ regex,mongo 会全盘扫描索引中的键,然后获取匹配的文档,这比集合扫描更快。

对于/^Jon Skeet/正则表达式,mongo只会扫描索引中以正则表达式开头的范围,这样会更快。

【讨论】:

如果有直接匹配(即:匹配字母a),则正则表达式可以正常工作。但是如果我匹配一个完整的单词结果需要更长的时间(即:angular)。这是跨越 6M 文档,有没有办法加快这些查询?超过 8 个字符需要 19-30 秒,但会立即返回 1-2 个字符。 @chovy,我认为 MongoDB 不是搜索文本中间出现的字符串的最佳工具 - 我建议查看 ElasticSearch 或任何其他全文搜索引擎。【参考方案2】:

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

该字段应该有一个文本索引

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

只有在先执行普通搜索后,查询才应使用正则表达式

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

这确保了正则表达式仅针对初始的普通搜索的结果运行,由于该字段上的索引,这应该非常快。 它可能会对搜索性能产生巨大影响,具体取决于集合的大小。

【讨论】:

感谢您的意见。不过,我必须处理两个搜索条件。整个单词,然后是单词的一部分。 如果您不搜索完整的单词,这实际上不起作用。如果您按文本索引搜索,“some”将不返回任何内容。

以上是关于MongoDB,通过正则表达式对索引字段的查询性能的主要内容,如果未能解决你的问题,请参考以下文章

mongodb 怎么对多个字段模糊查询

MongoDB 索引和非索引性能

带有索引字段的 MongoDB 正则表达式

MongoDB 索引限制

MongoDB Indexes

MongoDB索引