NoSQL在MongoDB中达成聚合函数

乘机组织发出的数量爆炸性增进,从GB到TB,从TB到PB,古板的数据库已经不能够透过垂直扩充来治本如此之大额。守旧格局囤积和管理多少的老本将会随着数据量拉长而人人皆知增添。这使得好多团组织都在搜索一种经济的解决方案,举例NoSQL数据库,它提供了所需的数目存款和储蓄和管理本领、扩充性和资本效能。NoSQL数据库不使用SQL作为查询语言。那种数据库有八种差异的体系,比方文书档案结构存款和储蓄、键值结构存款和储蓄、图结构、对象数据库等等。

我们在本文中利用的NoSQL是MongoDB,它是1种开源的文档数据库系统,开垦语言为C++。它提供了1种高效的面向文书档案的积攒结构,同时帮助通过MapReduce先后来处理所蕴藏的文书档案;它的扩充性很好,而且辅助电动分区。Mapreduce能够用来贯彻多少聚合。它的多少以BSON(二进制JSON)格式存款和储蓄,在蕴藏结构上支撑动态schema,并且同意动态查询。和大切诺基DBMS的SQL查询不一致,Mongo查询语言以JSON表示。

MongoDB提供了3个汇集框架,当中囊括常用成效,比方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 函数

SUM

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;
}});

AVERAGE

db.system.js.save( { _id : "Avg" ,
value : function(key,values)
{
    var total = Sum(key,values);
    var mean = total/values.length;
    return mean;
}});

MAX

db.system.js.save( { _id : "Max" ,
value : function(key,values)
{
    var maxValue=values[0];
    for(var i=1;i

MIN

db.system.js.save( { _id : "Min" ,
value : function(key,values)
{
    var minValue=values[0];
    for(var i=1;i

VARIANCE

db.system.js.save( { _id : "Variance" ,
value : function(key,values)
{
    var squared_Diff = 0;
    var mean = Avg(key,values);
    for(var i = 0; i < values.length; i++)
    {
        var deviation = values[i] - mean;
        squared_Diff += deviation * deviation;
    }
    var variance = squared_Diff/(values.length);
    return variance;
}});

STD DEVIATION

db.system.js.save( { _id : "Standard_Deviation"
, value : function(key,values)
{
    var variance = Variance(key,values);
    return Math.sqrt(variance);
}});

 

SQL和MapReduce脚本在三种不一致的用例场景中落成聚合函数的代码片段如下表所示。

一.外省点的平均订单量

上边包车型大巴查询是用来获得不一样地点的平均订单量。

SQL Query

MapReduce Functions

SELECT

db.sales.runCommand(
{
mapreduce : "sales" ,

 

City,

State,

Region,

map:function()
{ // emit function handles the group by
        emit( {
        // Key
        city:this.City,
        state:this.State,
        region:this.Region},
        // Values
        this.Quantity);
},

 

AVG(Quantity)

reduce:function(key,values)
{
    var result = Avg(key, values);
    return result;
}

FROM sales

 

GROUP BY City, State, Region

// Group By is handled by the emit(keys, values)
 line in the map() function above
 
out : { inline : 1 } });

二.成品的分类贩卖总额

下边包车型地铁询问是用来获取产品的归类发卖额,依据产品类别的层级分组。在上边例子中,分裂的产品连串作为个体维度,它们也能够被称作更复杂的依附档期的顺序的维度。

SQL 查询

MapReduce 函数

SELECT

db.sales.runCommand(
{
mapreduce : "sales" ,

 

ProductCategory, ProductSubCategory, ProductName,

map:function()
{
        emit(
        // Key
        {key0:this.ProductCategory,
        key1:this.ProductSubCategory,
        key2:this.ProductName},
        // Values
        this.SalesAmt);
},

 

SUM(SalesAmt)

reduce:function(key,values)
{
    var result = Sum(key, values);
    return result;
}

FROM sales

 

GROUP BY ProductCategory, ProductSubCategory, ProductName

// Group By is handled by the emit(keys, values) 
line in the map() function above
 
out : { inline : 1 } });
 

 

叁. 一种产品的最大利益

上面包车型地铁询问是用来得到一个加以产品基于过滤条件的最大利益。

SQL查询

MapReduce 函数

SELECT

db.sales.runCommand(
{
mapreduce : "sales" ,

 

 

ProductId, ProductName,

map:function()
{
    if(this.ProductId==1)
        emit( {
            key0:this.ProductId,
            key1:this.ProductName},
            this.Profit);
},

 

MAX(SalesAmt)

reduce:function(key,values)
{
    var maxValue=Max(key,values);
    return maxValue;
}

FROM sales

 

WHERE ProductId=’1’

// WHERE condition implementation is provided in 
map() function

GROUP BY ProductId, ProductName

// Group By is handled by the emit(keys, values) 
line in the map() function above
 
out : { inline : 1 } });

 

4. 总数、总贩卖额、平均净利益

这些现象的必要是计量订单的总和、总出卖额和平均净利益,订单ID在一到十里头,发货时间在201①年的七月7日到十月一27日里面。下边的查询是用来实施三个聚众,比如,在钦定年份以及钦赐的不等区域和产品种类范围里订单的总的数量、总发卖额和平均净利益。

SQL 查询

MapReduce 函数

SELECT

db.sales.runCommand(
{ mapreduce : "sales" ,

 

 

Region,

ProductCategory,

ProductId,

map:function()
{
    emit( {
        // Keys
        region:this.Region,
        productCategory:this.ProductCategory,
        productid:this.ProductId},

        // Values
        {quantSum:this.Quantity,
        salesSum:this.SalesAmt,
        avgProfit:this.Profit} );
}

 

 

 

Sum(Quantity),

Sum(Sales),

Avg(Profit)

reduce:function(key,values)
{
    var result=
{quantSum:0,salesSum:0,avgProfit:0};
    var count = 0;
    values.forEach(function(value)
    {
        // Calculation of Sum(Quantity)
        result.quantSum += values[i].quantSum;
        // Calculation of Sum(Sales)
        result.salesSum += values[i].salesSum;
        result.avgProfit += values[i].avgProfit;
        count++;
    }
    // Calculation of Avg(Profit)
    result.avgProfit = result.avgProfit / count;
    return result;
},

FROM Sales

 

WHERE

 

Orderid between 1 and 10 AND

Shipdate BETWEEN ‘01/01/2011’ and

‘12/31/2011’

query : {
        "OrderId" : { "$gt" : 1 },
        "OrderId" : { "$lt" : 10 },
        "ShipDate" : { "$gt" : "01/01/2011" },
        "ShipDate" : { "$lt" : "31/12/2011" },
},

GROUP BY

Region, ProductCategory, ProductId

// Group By is handled by the emit(keys, values) 
line in the map() function above

LIMIT 3;

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 
 optimization, like sorting by the emit key for fewer reduces>]

        [, limit : <number of objects to return from collection>]

        [, out : <see output options below>]

        [, keeptemp: <true|false>]

        [, finalize : <finalizefunction>]

        [, scope : <object where fields go into javascript global scope >]

        [, jsMode : true]

        [, verbose : true]

    }

)


Where the Output Options include:

{ replace : "collectionName" }

{ merge : "collectionName"

{ reduce : "collectionName" }

{ inline : 1}

 

 

下边是用来保存聚合函数并在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作用落成。

有关小编

Arun Viswanathan Infosys公司Cloud Center of Excellence (CoE)的技术架构师,该公司在IT和商业咨询服务上位于全球领先的地位。Arun在Java、JavaEE、云计算以及大数据应用架构的定义和实现方面有9年半的工作经验。他现在从事大数据解决方案的设计、开发和咨询。Email: Arun_Viswanathan01@infosys.com.

Shruthi Kumar Infosys公司Cloud Center of Excellence (CoE)的技术分析师,该公司在IT和商业咨询服务上位于全球领先的地位。Shruthi在Java、网格计算、云计算以及大数据应用架构上有5年的工作经验。她现在从事大数据解决方案的开发和咨询。Email: Shruthi_Kumar01@infosys.com.

初稿链接:http://www.infoq.com/articles/implementing-aggregation-functions-in-mongodb

网站地图xml地图