在MongoDB中实现聚合函数 (转)
随着组织产生的数据爆炸性增长,从GB到TB,从TB到PB,传统的数据库已经无法通过垂直扩展来管理如此之大数据。传统方法存储和处理数据的成本将会随着数据量增长而显著增加。这使得很多组织都在寻找一种经济的解决方案,比如NoSQL数据库,它提供了所需的数据存储和处理能力、扩展性和成本效率。NoSQL数据库不使用SQL作为查询语言。这种数据库有多种不同的类型,比如文档结构存储、键值结构存储、图结构、对象数据库等等。
我们在本文中使用的NoSQL是MongoDB,它是一种开源的文档数据库系统,开发语言为C++。它提供了一种高效的面向文档的存储结构,同时支持通过MapReduce程序来处理所存储的文档;它的扩展性很好,而且支持自动分区。Mapreduce可以用来实现数据聚合。它的数据以BSON(二进制JSON)格式存储,在存储结构上支持动态schema,并且允许动态查询。和RDBMS的SQL查询不同,Mongo查询语言以JSON表示。
MongoDB提供了一个聚合框架,其中包括常用功能,比如count、distinct和group。然而更多的高级聚合函数,比如sum、average、max、min、variance(方差)和standard deviation(标准差)等需要通过MapReduce来实现。
这篇文章描述了在MongoDB存储的文档上使用MapReduce来实现通用的聚合函数,如sum、average、max、min、variance和standard deviation;聚合的典型应用包括销售数据的业务报表,比如将各地区的数据分组后计算销售总和、财务报表等。
我们从本文示例应用所需软件的安装开始。
软件安装
首先在本地机器上安装并设置MongoDB服务。
- 从Mongo网站上下载MongoDB,解压到本地目录,比如C:>Mongo
- 在上一个文件夹内创建数据目录。比如:C:\Mongo\Data
- 如果数据文件存放在其他地方,那么在用mongod.exe命令启动MongoDB时,需要在命令行加参数—-dbpath
- 启动服务
- MongoDB提供了两种方式:mongod.exe以后台进程启动;mongo.exe启动命令行界面,可做管理操作。这两个可执行文件都位于Mongo\bin目录下;
- 进入Mongo安装目录的bin目录下,比如:C:> cd Mongo\bin
有两种启动方式,如下:
mongod.exe –dbpath C:\Mongo\data
或者
mongod.exe –config mongodb.config
mongodb.config是Mongo\bin目录下的配置文件,需要在此配置文件中指定数据目录(比如,dbpath= C:\Mongo\Data)的位置。
连接到MongoDB,到这一步,mongo后台服务已经启动,可以通过http://localhost:27017查看。 MongoDB启动运行后,我们接下来看它的聚合函数。
实现聚合函数
在关系数据库中,我们可以在数值型字段上执行包含预定义聚合函数的SQL语句,比如,SUM()、COUNT()、MAX()和MIN()。但是在MongoDB中,需要通过MapReduce功能来实现聚合以及批处理,它跟SQL里用来实现聚合的GROUP BY从句比较类似。下一节将描述关系数据库中SQL方式实现的聚合和相应的通过MongoDB提供的MapReduce实现的聚合。
为了讨论这个主题,我们考虑如下所示的Sales表,它以MongoDB中的反范式形式呈现。
Sales表
|
# |
列名 |
数据类型 |
|
1 |
OrderId |
INTEGER |
|
2 |
OrderDate |
STRING |
|
3 |
Quantity |
INTEGER |
|
4 |
SalesAmt |
DOUBLE |
|
5 |
Profit |
DOUBLE |
|
6 |
CustomerName |
STRING |
|
7 |
City |
STRING |
|
8 |
State |
STRING |
|
9 |
ZipCode |
STRING |
|
10 |
Region |
STRING |
|
11 |
ProductId |
INTEGER |
|
12 |
ProductCategory |
STRING |
|
13 |
ProductSubCategory |
STRING |
|
14 |
ProductName |
STRING |
|
15 |
ShipDate |
STRING |
基于SQL和MapReduce的实现
我们提供了一个查询的样例集,这些查询使用聚合函数、过滤条件和分组从句,及其等效的MapReduce实现,即MongoDB实现SQL中GROUP BY的等效方式。在MongoDB存储的文档上执行聚合操作非常有用,这种方式的一个限制是聚合函数(比如,SUM、AVG、MIN、MAX)需要通过mapper和reducer函数来定制化实现。
MongoDB没有原生态的用户自定义函数(UDFs)支持。但是它允许使用db.system.js.save命令来创建并保存JavaScript函数,JavaScript函数可以在MapReduce中复用。下表是一些常用的聚合函数的实现。稍后,我们会讨论这些函数在MapReduce任务中的使用。
| 聚合函数 |
Javascript 函数 |
|
|
db.system.js.save( { _id : "Sum" ,
|
|
|
db.system.js.save( { _id : "Avg" ,
|
|
|
db.system.js.save( { _id : "Max" ,
|
|
|
db.system.js.save( { _id : "Min" ,
|
|
|
db.system.js.save( { _id : "Variance" ,
|
|
|
db.system.js.save( { _id : "Standard_Deviation"
|
SQL和MapReduce脚本在四种不同的用例场景中实现聚合函数的代码片段如下表所示。
1.各地区的平均订单量
下面的查询是用来获取不同地区的平均订单量。
|
SQL Query |
MapReduce Functions |
|
|
db.sales.runCommand( |
|
|
map:function() |
|
|
reduce:function(key,values) |
|
|
|
|
|
// Group By is handled by the emit(keys, values) |
out : { inline : 1 } });
|
2.产品的分类销售总额
下面的查询是用来获取产品的分类销售额,根据产品类别的层级分组。在下面例子中,不同的产品类别作为个体维度,它们也可以被称为更复杂的基于层次的维度。
|
SQL 查询 |
MapReduce 函数 |
|
|
db.sales.runCommand( |
|
|
map:function() |
|
|
reduce:function(key,values) |
|
|
|
|
|
// Group By is handled by the emit(keys, values) |
out : { inline : 1 } });
|
3. 一种产品的最大利润
下面的查询是用来获取一个给定产品基于过滤条件的最大利润。
|
SQL查询 |
MapReduce 函数 |
|
|
db.sales.runCommand( |
|
|
map:function() |
|
|
reduce:function(key,values) |
|
|
|
|
|
// WHERE condition implementation is provided in |
|
|
// Group By is handled by the emit(keys, values) |
out : { inline : 1 } });
|
4. 总量、总销售额、平均利润
这个场景的需求是计算订单的总数、总销售额和平均利润,订单ID在1到10之间,发货时间在2011年的1月1日到12月31日之间。下面的查询是用来执行多个聚合,比如,在指定年份以及指定的不同区域和产品类别范围里订单的总数、总销售额和平均利润。
|
SQL 查询 |
MapReduce 函数 |
|
|
db.sales.runCommand( |
|
|
map:function() |
|
|
reduce:function(key,values) |
|
|
|
|
|
|
|
|
query : {
|
|
|
// Group By is handled by the emit(keys, values) |
|
|
limit : 3, |
out : { inline : 1 } });
|
既然我们已经看了在不同业务场景下的聚合函数的代码示例,接下来我们准备来测试这些函数。
测试聚合函数
MongoDB的MapReduce功能通过数据库命令来调用。Map和Reduce函数在前面章节里已经使用JavaScript实现。下面是执行MapReduce函数的语法。
db.runCommand(
{ mapreduce : <collection>,
map : <mapfunction>,
reduce : <reducefunction>
[, query : <query filter object>]
[, sort : <sorts the input objects using this key. Useful for
|
下面是用来保存聚合函数并在MapReduce中使用的命令。
启动Mongo命令行并设置表
- 确保Mongo后台进程在运行,然后执行mongo.exe启动Mongo命令行。
- 使用命令切换数据库:use mydb
- 使用命令查看Sales表的内容:db.sales.find()
find命令的输出如下:
{ "_id" : ObjectId("4f7be0d3e37b457077c4b13e"), "_class" : "com.infosys.mongo.Sales", "orderId" : 1, "orderDate" : "26/03/2011",
"quantity" : 20, "salesAmt" : 200, "profit" : 150, "customerName" : "CUST1", "productCategory" : "IT", "productSubCategory" : "software",
"productName" : "Grad", "productId" : 1 }
{ "_id" : ObjectId("4f7be0d3e37b457077c4b13f"), "_class" : "com.infosys.mongo.Sales", "orderId" : 2, "orderDate" : "23/05/2011",
"quantity" : 30, "salesAmt" : 200, "profit" : 40, "customerName" : "CUST2", "productCategory" : "IT", "productSubCategory" : "hardware",
"productName" : "HIM", "productId" : 1 }
{ "_id" : ObjectId("4f7be0d3e37b457077c4b140"), "_class" : "com.infosys.mongo.Sales", "orderId" : 3, "orderDate" : "22/09/2011",
"quantity" : 40, "salesAmt" : 200, "profit" : 80, "customerName" : "CUST1", "productCategory" : "BT", "productSubCategory" : "services",
"productName" : "VOCI", "productId" : 2 }
{ "_id" : ObjectId("4f7be0d3e37b457077c4b141"), "_class" : "com.infosys.mongo.Sales", "orderId" : 4, "orderDate" : "21/10/2011",
"quantity" : 30, "salesAmt" : 200, "profit" : 20, "customerName" : "CUST3", "productCategory" : "BT", "productSubCategory" : "hardware",
"productName" : "CRUD", "productId" : 2 }
{ "_id" : ObjectId("4f7be0d3e37b457077c4b142"), "_class" : "com.infosys.mongo.Sales", "orderId" : 5, "orderDate" : "21/06/2011",
"quantity" : 50, "salesAmt" : 200, "profit" : 20, "customerName" : "CUST3", "productCategory" : "BT", "productSubCategory" : "hardware",
"productName" : "CRUD", "productId" : 1 }
创建并保存聚合函数
- 通过MongoDB命令行窗口执行如下命令:
> db.system.js.save( { _id : "Sum" ,
value : function(key,values)
{
var total = 0;
for(var i = 0; i < values.length; i++)
total += values[i];
return total;
}});
- 在示例表Sales表上执行MapReduce程序
> db.sales.runCommand(
{
mapreduce : "sales" ,
map:function()
{
emit(
{key0:this.ProductCategory,
key1:this.ProductSubCategory,
key2:this.ProductName},
this.SalesAmt);
},
reduce:function(key,values)
{
var result = Sum(key, values);
return result;
}
out : { inline : 1 } });
输出如下:
"results" : [
{
"_id" : {
"key0" : "BT",
"key1" : "hardware",
"key2" : "CRUD"
},
"value" : 400
},
{
"_id" : {
"key0" : "BT",
"key1" : "services",
"key2" : "VOCI"
},
"value" : 200
},
{
"_id" : {
"key0" : "IT",
"key1" : "hardware",
"key2" : "HIM"
},
"value" : 200
}, {
"_id" : {
"key0" : "IT",
"key1" : "software",
"key2" : "Grad"
},
"value" : 200
}
],
"timeMillis" : 1,
"timing" : {
"mapTime" : NumberLong(1),
"emitLoop" : 1,
"total" : 1
},
"counts" : {
"input" : 5,
"emit" : 5,
"output" : 4
},
"ok" : 1
总结
MongoDB提供了面向文档的存储结构,可以很容易扩展支持TB级数据。同时也提供了Map Reduce功能,可以通过批处理方式使用类SQL函数来实现数据聚合。在这篇文章中,我们描述了安装MongoDB并使用MapReduce特性执行聚合函数的过程,也提供了简单SQL聚合的MapReduce示例实现。在MongoDB中,更复杂的聚合函数也可以通过使用MapReduce功能实现。
原文链接:http://www.infoq.com/articles/implementing-aggregation-functions-in-mongodb
在MongoDB中实现聚合函数 (转)的更多相关文章
- 在MongoDB中实现聚合函数
在MongoDB中实现聚合函数 随着组织产生的数据爆炸性增长,从GB到TB,从TB到PB,传统的数据库已经无法通过垂直扩展来管理如此之大数据.传统方法存储和处理数据的成本将会随着数据量增长而显著增加. ...
- C#代码 利用MongoDB中Group聚合函数查询
例子: public static void getUserRFM(DateTime beginTime, DateTime endTime) { MongoDat ...
- C#代码利用MongoDB中Group聚合函数查询
例子: public static void getUserRFM(DateTime beginTime, DateTime endTime) { MongoDat ...
- Mysql中使用聚合函数对null值的处理
平时因为对于数据库研习的不深,所以在面试的时候问了一些平常遇到过的问题居然没法很肯定地回答出来,实在让自己很恼怒! 这次让我记忆深刻的一个问题是: 在mysql中使用聚合函数的时候比如avg(t),t ...
- MongoDB中的聚合操作
根据MongoDB的文档描述,在MongoDB的聚合操作中,有以下五个聚合命令. 其中,count.distinct和group会提供很基本的功能,至于其他的高级聚合功能(sum.average.ma ...
- sqlserver中的聚合函数
聚合函数:就是按照一定的规则将多行(Row)数据汇总成一行的函数,对数据进行汇总前,还可以按特定的列(coloumn)将数据进行分组(group by)再汇总,然后按照再次给定的条件进行筛选 一:Co ...
- 关于mysql中使用聚合函数结果集为空,仍显示size为1,所有元素为Null问题的解决办法
转自:https://www.2cto.com/database/201806/757632.html 1.不使用聚合函数sql: select * from sys_role_data a left ...
- MySQL中的聚合函数
创建student表 CREATE TABLE IF NOT EXISTS `student` ( `id` int(4) unsigned NOT NULL AUTO_INCREMENT, `nam ...
- SQL中的聚合函数
聚合函数是对一组值执行计算并返回单一的值的函数,它经常与SELECT语句的GROUP BY子句一同使用,SQL SERVER 中具体的聚合函数如下:1. AVG 返回指定组中的平均值,空值被忽略. 例 ...
随机推荐
- phpstorm xdebug 碰到很神奇的一件事
早上配置好了,且正常运行了,然后没有退出phpstorm, 结果到了下午,配置消失了, 还好稳住了阵脚,然后配置了,就好了. 很重要一点,在调试观看源代码的时候,一定要浅薄,然后深入,不然累死,得不偿 ...
- ios开发者证书 签发者无效
2月14日以后,由于苹果更新安全证书:会导致本机制作的所有开发者证书无效: 钥匙串里的开发者证书无法使用 解决方式: 重新下载苹果公司的安全证书,并安装 1: 先在钥匙串里搜索到老的证书,如果有,请先 ...
- 例题:打印正三角形。两层for循环,难点明白行与列的关系
while (true) { string s = "★";//s代表五角星 string t = ...
- MySQL for Windows 解压缩版配置安装
1.MySQL安装文件分为两种,一种是msi格式的,一种是zip格式的.如果是msi格式的可以直接点击安装,按照它给出的安装提示进行安装(相信大家的英文可以看懂英文提示),一般MySQL将会安装在C: ...
- 如何查看IIS并发连接数【转】
转http://wangfeng5271.blog.163.com/blog/static/4817444420128242123740/ 如果要查看IIS连接数,最简单方便的方法是通过“网站统计”来 ...
- MVC之URL路由
注册路由规则集合 一个 Web 应用具有一个全局的路由表,该路由表通过 System. Web.Routing.RouteTable的静态只读属性 Routes 表示,该属性返回一个类型为 Syste ...
- Response返回JSON数据到前台页面
转自博文:<Response JSON数据返回>http://blog.csdn.net/anialy/article/details/8665471 简述: 在servlet填充Resp ...
- node 日志管理log4js
node 日志管理log4js 一.默认的控制台输出 我们使用express框架时,开发模式用node或者supervisor启动nodejs应用时,控制台都是显示如下的日志. GET /css/bo ...
- Dapper使用
公司的项目使用了Dapper做数据库连接处理,感觉不错,自己研究一下怎么用. 在网上找了找资料对Dapper都比较推崇.主要是两个方面,一个是连接速度很快,一个是代码开源且简单,只有一个SqlMapp ...
- 一个QMLListView的例子--
一般人不知道怎么去过滤ListView里面的数据,下面是一个转载的文章:http://imaginativethinking.ca/use-qt-quicks-delegatemodelgroup/ ...