在庞大的 mongodb 集合中快速搜索非常稀有的字段

Posted

技术标签:

【中文标题】在庞大的 mongodb 集合中快速搜索非常稀有的字段【英文标题】:quickly search for very rare field in a huge mongodb collection 【发布时间】:2016-12-12 10:13:52 【问题描述】:

我有大约 10 亿个文档的庞大集合,其中很少有文档(少于 200 个)包含某些字段“rare_field”。

我怎样才能尽快找到包含该字段的所有文档?

如果我只是这样做:

collection.find( "rare_field" :  $exists : true )

超时。 这可能需要几天时间才能完成,所以我不确定即使通过查询标志防止超时也会有所帮助,但也许我错了。

我也可以编写一个脚本来检查所有文档,但这会很慢,因为它需要通过网络将所有 10 亿个文档传递到我的服务器,我想要一些不需要任何数据传递的解决方案电线,而且会很快。

注意:这是一个sharded 集合。

我将发布我当前的解决方案作为答案,但我不确定它是否 100% 正确,而且速度没有我想要的那么快。

【问题讨论】:

将此rare-field 放入您的分片查询中!正因为如此,mongo 也会索引这个字段!所以它会很快! 谢谢。这是一次性的事情,所以我在这里并不需要索引。当数据库为空时,这可能是一个很好的解决方案,但是现在索引这个字段会花费很多时间,就像手动浏览所有文档一样(我认为) 你说的时间消耗是对的!所以这完全取决于你的应用程序!另一种方法是将结果保存在缓存中!将结果存储在新集合或 redis 或 smtn 中! 创建sparse index? 【参考方案1】:

如果没有rare-field 上的索引,在最坏的情况下,mongodb 将需要遍历集合中的所有文档。在这种情况下,光标可能会超时,因此您需要为光标添加一个标志以防止它这样做。

在 mongo shell 中,这意味着如下查询:

var cursor = db.collection.find( "rare_field" :  $exists : true ).noCursorTimeout();

如果您担心网络问题或其他问题会在光标填充batchSize匹配文档之前中断查询,那么您确实可以按照您在答案中的建议逐一获取文档,但是您需要按 _id: 1 排序,并使用noCursorTimeout()limit(1),即:

var doc = db.collection.find( "rare_field" :  $exists : true )
            .sort( _id: 1 )
            .limit(1)
            .noCursorTimeout()
            .next();

然后按照您的建议,通过重复查询来检索下一个文档,同时将条件 _id: $gt: doc._id 添加到查询对象。

【讨论】:

【参考方案2】:

一个可能的解决方案是使用findOne 而不是find:

var doc = collection.findOne( "rare_field" :  $exists : true );

然后循环获取下一个:

var doc = collection.findOne( _id :  $gt : doc._id, "rare_field" :  $exists : true );

但是,我不能 100% 确定这些调用是否必须给我按 _id 排序的结果,我也不确定单个 findOne 是否也不会超时。

我担心显式添加 sort(_id : 1) 会强制查询获取所有结果,然后传递第一个结果。

【讨论】:

我认为这不是一个好主意!就像你在做最糟糕的事情一样!你是 mongo 会做和find( "rare_field" : $exists : true ); 一样的事情!但是您将其分成几部分,开销很大! 你的恐惧也解释了为什么你不应该这样做!:)

以上是关于在庞大的 mongodb 集合中快速搜索非常稀有的字段的主要内容,如果未能解决你的问题,请参考以下文章

Mongodb Cursor,如何遍历巨大的集合?

MongoDB 设置的全文搜索选项

使用nodejs在整个集合(mongodb)中搜索

在 MongoDB 中搜索多个集合

可视化管理 MongoDB 文档和集合 [关闭]

使用带有 Python Flask 的 HTML 表单搜索 MongoDB 集合