Monary在MongoDB上执行高性能列查询

Monar的Python项目详细描述


简介

MongoDB是一个面向文档的数据库,为快速访问记录而组织 (或行)数据。在对大型数据集进行分析时,通常 希望它采用面向列的格式。数据列可以是 作为数学载体的思想,存在着丰富的技术。 收集有关以矢量形式存储的数据的统计信息。

对于small-to-medium大小的集合,可以实现几个 现代个人计算机存储器中的数据列。例如,100的数组 百万个双精度数字消耗8亿字节,约0.75 GB。 对于更大的问题,仍然有可能实现很大一部分 或处理多段数据。(非常大的问题 需要更强大的武器,例如map/reduce。)

使用python从mongodb中提取列数据相当简单。在 pymongo,collection.find()生成字典对象序列。 在处理数以百万计的记录时,诀窍不是保存这些 记忆中的字典,因为它们往往很大。幸运的是,很容易 加载数据时将其移到数组中。

首先,让我们创建350万行测试数据:

#!/usr/bin/env pythonimportrandomimportpymongoNUM_BATCHES=3500BATCH_SIZE=1000# 3500 batches * 1000 per batch = 3.5 million recordsc=pymongo.MongoClient()collection=c.mydb.collectionforiinxrange(NUM_BATCHES):stuff=[]forjinxrange(BATCH_SIZE):record=dict(x1=random.uniform(0,1),x2=random.uniform(0,2),x3=random.uniform(0,3),x4=random.uniform(0,4),x5=random.uniform(0,5))stuff.append(record)collection.insert(stuff)

下面是一个使用numpy数组的示例:

#!/usr/bin/env pythonimportnumpyimportpymongoc=pymongo.MongoClient()collection=c.mydb.collectionnum=collection.count()arrays=[numpy.zeros(num)foriinrange(5)]fori,recordinenumerate(collection.find()):forxinrange(5):arrays[x][i]=record["x%i"%x+1]forarrayinarrays:# prove that we did something...printnumpy.mean(array)

有350万条记录,这个查询在一个ec2大型实例上需要85秒 运行Ubuntu10.1064位,在MacBookPro(2.66GHz)上运行88秒 Intel Core 2 Duo,8 GB内存)。

考虑到它们加载了200000多个值,这些计时可能看起来令人印象深刻 每秒。然而,仔细研究发现,大部分时间 pymongo在读取每个查询结果并转换bson结果时花费 一本Python字典。(如果您观察cpu的使用情况,您将看到python是 使用90%或更多的CPU。)

一元

如果我们绕过pymongo,就有可能从查询中获得(更多)更快的速度 司机。为了证明这一点,我开发了monary,一个简单的c库和 附带使用mongodb c驱动程序的python包装器。代码是 旨在接受所需字段的列表,并准确加载这些字段 从bson结果进入一些提供的阵列存储。

下面是使用monary进行相同查询的示例:

#!/usr/bin/env pythonfrommonaryimportMonaryimportnumpywithMonary("127.0.0.1")asmonary:arrays=monary.query("mydb",# database name"collection",# collection name{},# query spec["x1","x2","x3","x4","x5"],# field names (in Mongo record)["float64"]*5# Monary field types (see below))forarrayinarrays:# prove that we did something...printnumpy.mean(array)

Monary能够在4秒内执行相同的查询,速度大约为 每秒400万个值(快20倍!)这里有一个关于 这个单点查询与pymongo比较:

  • Pymongo插件–EC2:102 S–Mac:76 S
  • Pymongo查询–ec2:85秒–mac:88秒
  • 一元查询–ec2:5.4秒–mac:3.8秒

当然,这个测试创造了一些相当理想的环境: 查询集合中的每个记录时,这些记录只包含 查询的数据(加上objectid),并且数据库正在本地运行。这个 如果使用远程服务器,如果记录更大, 或者如果只查询记录的一个子集(需要 扫描记录或使用索引)。

Monary现在知道以下类型:

  • id(mongo的12字节objectid)
  • 国际8
  • 国际16
  • Int32
  • Int64
  • 浮动32
  • 浮点64
  • 布尔
  • 日期(存储为Int64,自纪元起的毫秒)

Monary的源代码可以在BitBucket上找到。其中包括 MongoC驱动程序,需要编译和安装,可以完成 通过附带的“setup.py”文件。(安装脚本可以工作,但是 有点粗糙。任何来自distutils大师的帮助都将是巨大的 谢谢!)要从python运行monary,需要有pymongo和 安装了numpy包。

Monary正在慢慢地获得功能(包括最近增加的 更多数字类型和日期类型)。这里有一些计划好的未来 改进:

  • 支持字符串/二进制类型

    (我希望开发monary来支持大多数bson的合理映射 在阵列存储器上键入。)

  • 支持获取嵌套字段(例如“x.y”)

  • 删除对pymongo和numpy的依赖关系(可能)

    (当前必须安装这些程序才能使用Monary。)

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java Apache Flink外部Jar   创建和强制转换对象数组时发生java错误   Java,添加数组   具有相同包结构和类的java JAR   java Jenkins未能构建Maven项目   java为什么一个forloop比另一个更快,尽管它们做的“一样”?   servlets在将“/”站点迁移到Java EE包时处理contextpath引用   无法解析java MavReplugin:2.21或其某个依赖项   泛型如何编写比较器来泛化Java中的两种类型的对象?   java Android Emulator未在netbeans上加载   多线程Java使用线程对数组中的数字求和:在同步块中使用新变量作为锁:差异   java如何在JSP/servlet中设置<input>标记的值?