【问题标题】:Quickly count the number of objects in bson document快速统计bson文档中的对象数量
【发布时间】:2017-01-09 19:09:15
【问题描述】:

我想计算存储在 mongodb bson 文件中的文档数量,而无需通过 mongo restore 将文件导入数据库。

我能想到的最好的python是

bson_doc = open('./archive.bson','rb')
it = bson.decode_file_iter(bson_doc)
total = sum(1 for _ in it)
print(total)

这在理论上可行,但当 bson 文档很大时,在实践中会很慢。谁有更快的方法来计算 bson 文档中的文档数量而无需进行完整解码?

我目前正在使用 python 2.7 和 pymongo。 https://api.mongodb.com/python/current/api/bson/index.html

【问题讨论】:

标签: python mongodb bson


【解决方案1】:

我手头没有文件可以尝试,但我相信有办法 - 如果您手动解析数据。

source for bson.decode_file_iter(没有文档字符串)是这样的:

_UNPACK_INT = struct.Struct("<i").unpack

def decode_file_iter(file_obj, codec_options=DEFAULT_CODEC_OPTIONS):
    while True:
        # Read size of next object.
        size_data = file_obj.read(4)
        if len(size_data) == 0:
            break  # Finished with file normaly.
        elif len(size_data) != 4:
            raise InvalidBSON("cut off in middle of objsize")
        obj_size = _UNPACK_INT(size_data)[0] - 4
        elements = size_data + file_obj.read(obj_size)
        yield _bson_to_dict(elements, codec_options)

我想,耗时的操作是_bson_to_dict call - 你不需要。

因此,您只需读取文件 - 获取具有下一个文档大小的 int32 值并跳过它。然后数一数你遇到过多少文档。

所以,我相信,这个函数应该可以解决问题:

import struct
import os
from bson.errors import InvalidBSON

def count_file_documents(file_obj):
    """Counts how many documents provided BSON file contains"""
    cnt = 0
    while True:
        # Read size of next object.
        size_data = file_obj.read(4)
        if len(size_data) == 0:
            break  # Finished with file normaly.
        elif len(size_data) != 4:
            raise InvalidBSON("cut off in middle of objsize")
        obj_size = struct.Struct("<i").unpack(size_data)[0] - 4
        # Skip the next obj_size bytes
        file_obj.seek(obj_size, os.SEEK_CUR)
        cnt += 1
    return cnt

(不过,我还没有测试过代码。手头没有 MongoDB。)

【讨论】:

  • 唯一添加到您的功能是“导入结构” - docs.python.org/2/library/struct.html#
  • 是的,还有一些导入(os.SEEK_CURInvalidBSON 例外)。我已经编辑了答案。
  • @user1438162 如果您将struct.Struct("&lt;i").unpack(...) 替换为bson._UNPACK_INT(...)(或将_UNPACK_INT 复制到您自己的代码中以不依赖于“私有”API),您可能会有一些额外的加速。不同之处在于Struct 对象只会被创建一次,这可能会在包含大量小文档的大型 BSON 文件上节省几毫秒。不过,与文件 I/O 成本相比,我相信差异将微不足道。
猜你喜欢
  • 1970-01-01
  • 2012-07-07
  • 2023-02-02
  • 2010-11-02
  • 2016-05-11
  • 1970-01-01
  • 1970-01-01
  • 2016-11-23
相关资源
最近更新 更多