成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

「譯」 MapReduce in MongoDB

ConardLi / 2889人閱讀

摘要:在第行中,我們會(huì)從集合取得結(jié)果并顯示它。的邏輯在中,我們要以性別作為,然后以作為。年齡是用來(lái)做計(jì)算用的,而名字只是用來(lái)顯示給人看的。我們要檢查所有和性別相關(guān)的年齡,找到年齡最大和最小的用戶。

在這篇文章里面,我們會(huì)演示如何在 MongoDB 中使用 MapReduce 操作。
我們會(huì)用 dummy-json 這個(gè)包來(lái)生成一些虛假的數(shù)據(jù),然后用 Mongojs

如果想要快速看到結(jié)果,可以到 這里 里看看。

什么是 MongoDB ?

MongoDB 是一個(gè) NoSQL 數(shù)據(jù)庫(kù),不像 MySQL 、MSSQL 和 Oracle DB 那樣,MongoDB 使用集合(collections) 來(lái)代替表(tables)。同時(shí),它用集合中的文檔(documents)來(lái)代替表中的行(rows)。還有最好的一點(diǎn)是,所有文檔都保存成 JSON 格式!你可以到這里學(xué)更多關(guān)于 MongoDB 的知識(shí)。

你可以從 這里 下載安裝 MongoDB。

如果以前沒(méi)用過(guò) MongoDB,那么你可以記住下面這些命令:

Command Result
mongod 啟動(dòng) MongoDB 服務(wù)
mongo 進(jìn)入 MongoDB Shell
show dbs 顯示所有數(shù)據(jù)庫(kù)列表
use 進(jìn)入指定的數(shù)據(jù)庫(kù)
show collections 進(jìn)入數(shù)據(jù)庫(kù)之后,顯示該數(shù)據(jù)庫(kù)中所有的集合
db.collectionName.find() 顯示該集合中所有文檔
db.collectionName.findOne() 顯示該集合中第一個(gè)文檔
db.collectionName.find().pretty() 顯示漂亮的 JSON 格式
db.collectionName.insert({key: value}) 插入一條新的記錄
db.collectionName.update({ condition: value}, {$set: {key: value}}, {upsert: true}) 會(huì)更新指定的文檔,設(shè)置指定的值。如果 upserttrue,當(dāng)沒(méi)有找到匹配的文檔時(shí),會(huì)創(chuàng)建一條新的記錄
db.collectionName.remove({}) 移除集合中的所有文檔
db.collectionName.remove({key: value}) 移除集合中匹配到的文檔
什么是 MapReduce ?

弄清楚 MapReduce 是如何運(yùn)作的是非常重要的,如果對(duì) MapReduce 過(guò)程不了解的話,你在運(yùn)行 MapReduce 時(shí)很可能得不到你想要的結(jié)果。

從 mongodb.org 上的解析:

Map-reduce 是一種數(shù)據(jù)處理范例,用于將大量的數(shù)據(jù)變成有用的聚合結(jié)果。 對(duì)于 map-reduce 操作,MongoDB 提供了 mapReduce 的數(shù)據(jù)庫(kù)命令。

在這非常簡(jiǎn)單的術(shù)語(yǔ)里面,mapReduce 命令接受兩個(gè)基本的輸入:mapper 函數(shù)和 reducer 函數(shù)。

Mapper 是一個(gè)匹配數(shù)據(jù)的過(guò)程,它會(huì)在集合中查詢我們想要處理的字段,然后根據(jù)我們指定的 key 去分組,再把這些 key-value 對(duì)交給 reducer 函數(shù),由它來(lái)處理這些匹配到的數(shù)據(jù)。

我們來(lái)看看下面這些數(shù)據(jù):

[
  { name: foo, price: 9 },
  { name: foo, price: 12 },
  { name: bar, price: 8 },
  { name: baz, price: 3 },
  { name: baz, price: 5 }
]

我們想要計(jì)算出相同名字下的所需要的價(jià)錢。我們將會(huì)用這個(gè)數(shù)據(jù)通過(guò) Mapper 和 Reducer 去獲得結(jié)果。

當(dāng)我們讓 Mapper 去處理上面的數(shù)據(jù)時(shí),會(huì)生成如下的結(jié)果:

Key Value
foo [9,12]
bar [8]
baz [3,5]

看到了嗎?它用相同的 key 去分組數(shù)據(jù)。在我們的例子中,是用 name 分組。這些結(jié)果會(huì)發(fā)送到 Reducer 中。

現(xiàn)在,在 reducer 中,我們會(huì)得到上面表格中的第一行數(shù)據(jù),然后迭代這些數(shù)據(jù)然后把它們加起來(lái),這就是第一行數(shù)據(jù)的總和。然后 reducer 會(huì)對(duì)第二行數(shù)據(jù)做同樣的事情,直到所有行被處理完。

最終的輸出結(jié)果如下:

Name Total
foo 21
bar 8
baz 8

現(xiàn)在你明白為什么 Mapper 會(huì)叫 Mapper 了吧 ! (因?yàn)樗鼤?huì)創(chuàng)建一份數(shù)據(jù)的映射)
也明白了為什么 Reducer 會(huì)叫 Reducer 了吧 ! (因?yàn)樗鼤?huì)把 Mapper 生成的數(shù)據(jù)歸納成一個(gè)簡(jiǎn)單的形式)

如果你運(yùn)行一些例子,你就會(huì)知道它是怎么工作的拉。你也可以從官方文檔 中了解更多細(xì)節(jié)。

創(chuàng)建一個(gè)項(xiàng)目

正如上文所說(shuō),我們可以在 mongo shell 中直接查詢和看到輸出結(jié)果。但是,為了讓教程更加豐富,我們會(huì)構(gòu)建一個(gè) Nodejs 項(xiàng)目,在里面運(yùn)行我們之前的任務(wù)。

Mongojs

我們會(huì)用 mongojs 去實(shí)現(xiàn)我們的 MapReduce。你可以用同樣的代碼跑在 mongo shell 里面,會(huì)看到同樣的結(jié)果。

Dummy-json

我們會(huì)用 dummy-json 去創(chuàng)建一些虛假的數(shù)據(jù)。你可以在 這里 找到更多的信息。然后我們會(huì)在這些虛假數(shù)據(jù)上面運(yùn)行 MapReduce 命令,生成一些有意義的結(jié)果。

我們開始吧!

首先,你要安裝 Nodejs,你可以看看 這里。然后你要?jiǎng)?chuàng)建一個(gè)叫 mongoDBMapReduce 的目錄。我們將會(huì)創(chuàng)建 package.json 文件來(lái)保存項(xiàng)目的詳細(xì)信息。

運(yùn)行 npm init 然后填入你喜歡的東西,創(chuàng)建完 package.json 后,我們要添加項(xiàng)目的依賴。
運(yùn)行 npm i mongojs dummy-json --save-dev ,然后等幾分鐘之后,我們項(xiàng)目的依賴就安裝好了。

生成虛假數(shù)據(jù)

下一步,我們要用 dummy-json 模塊來(lái)生成虛假數(shù)據(jù)。
在項(xiàng)目的根目錄創(chuàng)建一個(gè)名叫 dataGen.js 的文件,我們會(huì)把數(shù)據(jù)生成的邏輯保存到一個(gè)獨(dú)立的文件里面。如果以后需要添加更多的數(shù)據(jù),你可以運(yùn)行這個(gè)文件。

把下面的內(nèi)容復(fù)制到 dataGen.js 里面:

var mongojs = require("mongojs");
var db = mongojs("mapReduceDB", ["sourceData"]);
var fs = require("fs");
var dummyjson = require("dummy-json");
 
var helpers = {
  gender: function() {
    return ""+ Math.random() > 0.5 ? "male" : "female";
  },
  dob : function() {
    var start = new Date(1900, 0, 1),
        end = new Date();
        return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
    },
  hobbies : function () {
    var hobbysList = []; 
    hobbysList[0] = [];
    hobbysList[0][0] = ["Acrobatics", "Meditation", "Music"];
    hobbysList[0][1] = ["Acrobatics", "Photography", "Papier-Mache"];
    hobbysList[0][2] = [ "Papier-Mache"];
    return hobbysList[0][Math.floor(Math.random() * hobbysList[0].length)];
  }
};
 
console.log("Begin Parsing >>");
 
var template = fs.readFileSync("schema.hbs", {encoding: "utf8"});
var result = dummyjson.parse(template, {helpers: helpers});
 
console.log("Begin Database Insert >>");
 
db.sourceData.remove(function (argument) {
    console.log("DB Cleanup Completd");
});
 
db.sourceData.insert(JSON.parse(result), function (err, docs) {
    console.log("DB Insert Completed");
});

第1-4行,我們引入了所有依賴。
第2行,我們創(chuàng)建了一個(gè)叫 mapReduceDB 的數(shù)據(jù)庫(kù)。在數(shù)據(jù)庫(kù)里面,創(chuàng)建了一個(gè)叫 sourceData 的集合。

第6-23行,是 Handlebar 的 helper。你可以到 dummy-json 中了解更多信息。

第27-28行,我們讀取了 schema.hbs 文件 (我們接著會(huì)創(chuàng)建這個(gè)文件),然后把它解析成 JSON。

第32行,在插入新數(shù)據(jù)之前,我們要先把舊數(shù)據(jù)清除掉。如果你想保留舊數(shù)據(jù),把這部分注釋掉就好了。

第36行,把生成的數(shù)據(jù)插入數(shù)據(jù)庫(kù)。

接著,我們要在項(xiàng)目根目錄創(chuàng)建一個(gè)叫 schema.hbs 的文件。這里面會(huì)包括 JSON 文檔的結(jié)構(gòu)。把下面的內(nèi)容復(fù)制到文件里面:

[
    {{#repeat 9999}}
    {
      "id": {{index}},
      "name": "{{firstName}} {{lastName}}",
      "email": "{{email}}",
      "work": "{{company}}",
      "dob" : "{{dob}}",
      "age": {{number 1 99}},
      "gender" : "{{gender}}",
      "salary" : {{number 999 99999}},
      "hobbies" : "{{hobbies}}"
    }
    {{/repeat}}
]

注意 第2行,我們會(huì)生成 9999 個(gè)文檔。

打開一個(gè)新的終端,運(yùn)行 mongod,啟動(dòng) MongoDB 服務(wù)。然后回到原來(lái)的終端,運(yùn)行 node dataGen.js。

如果一切正常,會(huì)顯示如下結(jié)果:

$ node dataGen.js
Begin Parsing >>
Begin Database Insert >>
DB Cleanup Completed
DB Insert Completed

然后按 ctrl + c 殺掉 Node 程序。要驗(yàn)證是否插入成功,我們可以打開一個(gè)新的終端,運(yùn)行 mongo 命令進(jìn)入 mongo shell。

> use mapReduceDB
> db.sourceData.findOne()
{
    "id": 0,
    "name": "Leanne Flinn",
    "email": "[email protected]",
    "work": "Unilogic",
    "dob": "Sun Mar 14 1909 12:45:53 GTM+0530 (LST)",
    "age": 27,
    "gender": "male",
    "salary": 16660,
    "hobbies": "Acrobatics,Photography,Papier-Mache",
    "_id": Object("57579f702fa6c7651e504fe2")
}
> db.sourceData.count()
9999
有意義的數(shù)據(jù)

現(xiàn)在我們有 9999 個(gè)虛假用戶的數(shù)據(jù),讓我們?cè)囍褦?shù)據(jù)變得有意義

例子1:計(jì)算男女?dāng)?shù)量

首先,在項(xiàng)目根目錄創(chuàng)建一個(gè) example1.js 的文件,我們要進(jìn)行 MapReduce 操作,去計(jì)算男女的數(shù)量。

Mapper 的邏輯

我們只需要讓 Mapper 以性別作為 key,把值作為 1。因?yàn)橐粋€(gè)用戶不是男就是女。所以,Mapper 的輸出會(huì)是下面這樣:

Key Value
Male [1,1,1...]
Female [1,1,1,1,1...]
Reducer 的邏輯

在 Reducer 中,我們會(huì)獲得上面兩行數(shù)據(jù),我們要做的是把每一行中的值求和,表示該性別的總數(shù)。最終的輸出結(jié)果如下:

Key Value
Male 5031
Female 4968
代碼

好了,現(xiàn)在我們可以寫代碼去實(shí)現(xiàn)了。在 example1.js 中,我們要先引入所需要的依賴。

var mongojs = require("mongojs");
var db = mongojs("mapReduceDB", ["sourceData", "example1_results"]);

注意 第2行,第一個(gè)參數(shù)是數(shù)據(jù)庫(kù)的名字,第二個(gè)參數(shù)表示集合的數(shù)組。example1_results 集合用來(lái)保存結(jié)果。

接下來(lái),我們加上 mapper 和 reducer 函數(shù):

var mapper = function () {
    emit(this.gender, 1);
};
 
var reducer = function(gender, count){
    return Array.sum(count);
};

第2行中, this 表示當(dāng)前的文檔,因此 this.gender 會(huì)作為 mapper 的 key,它的值要么是 male,要么是 female。而 emit() 將會(huì)把數(shù)據(jù)發(fā)送到一個(gè)臨時(shí)保存數(shù)據(jù)的地方,作為 mapper 的結(jié)果。

第5行中,我們簡(jiǎn)單地把每個(gè)性別的所有值加起來(lái)。

最后,加上執(zhí)行邏輯:

db.sourceData.mapReduce(
    mapper,
    reducer,
    {
        out : "example1_results"
    }
 );
 
 db.example1_results.find(function (err, docs) {
    if(err) console.log(err);
    console.log(docs);
 });

第5行中,我們?cè)O(shè)置了輸出的集合名。
第9行中,我們會(huì)從 example1_results 集合取得結(jié)果并顯示它。

我們可以在終端運(yùn)行試試:

$ node example1.js
[ { _id: "female", value: 4968 }, { _id: "male": value: 5031 } ]

我的數(shù)量可能和你的不一樣,但男女總數(shù)應(yīng)該是 9999 !

Mongo Shell 代碼

如果你想在 mongo shell 中運(yùn)行上面的例子,你可以粘貼下面這些代碼到終端里面:

mapper = function () {
    emit(this.gender, 1);
};
 
reducer = function(gender, count){
    return Array.sum(count);
};
 
db.sourceData.mapReduce(
    mapper,
    reducer,
    {
        out : "example1_results"
    }
 );
 
 db.example1_results.find()

然后你就會(huì)看到一樣的結(jié)果,很簡(jiǎn)單吧!

例子2:獲取每個(gè)性別中最老和最年輕的人

在項(xiàng)目根目錄創(chuàng)建一個(gè) example2.js 的文件。在這里,我們要把所有用戶根據(jù)性別分組,然后分別找每個(gè)性別中最老和最年輕的用戶。這個(gè)例子比前面的稍微復(fù)雜一點(diǎn)。

Mapper 的邏輯

在 mapper 中,我們要以性別作為 key,然后以 object 作為 value。這個(gè) object 要包含用戶的年齡和名字。年齡是用來(lái)做計(jì)算用的,而名字只是用來(lái)顯示給人看的。

Key Value
Male [{age: 9, name: "John"}, ...]
Female [{age: 19, name: "Rita"}, ...]
Reducer 的邏輯

我們的 reducer 會(huì)比前一個(gè)例子要復(fù)雜一點(diǎn)。我們要檢查所有和性別相關(guān)的年齡,找到年齡最大和最小的用戶。最終的輸出結(jié)果是這樣的:

Key Value
Male {min: {name: "harry", age: 1}, max: {name: "Alex", age: 99} }
Female {min: {name: "Loli", age: 10}, max: {name: "Mary", age: 98} }
代碼

現(xiàn)在打開 example2.js,粘貼下面的內(nèi)容進(jìn)去:

var mongojs = require("mongojs");
var db = mongojs("mapReduceDB", ["sourceData", "example2_results"]);
 
 
var mapper = function () {
    var x = {age : this.age, name : this.name};
    emit(this.gender, {min : x , max : x});
};
 
 
var reducer = function(key, values){
    var res = values[0];
    for (var i = 1; i < values.length; i++) {
        if(values[i].min.age < res.min.age)
            res.min = {name : values[i].min.name, age : values[i].min.age};
        if (values[i].max.age > res.max.age) 
           res.max = {name : values[i].max.name, age : values[i].max.age};
    };
    return res;
};
 
 
db.sourceData.mapReduce(
    mapper,
    reducer,
    {
        out : "example2_results"
    }
 );
 
 db.example2_results.find(function (err, docs) {
    if(err) console.log(err);
    console.log(JSON.stringify(docs));
 });

第6行,我們構(gòu)建了一個(gè) object,把它作為 value 發(fā)送。
第13-18行,我們迭代了所有 object,檢查當(dāng)前的 object 的年齡是否大于或小于前一個(gè) object 的年齡,如果是,就會(huì)更新 res.max 或者 res.min。
在第第27行,我們把結(jié)果輸出到 example2_results 中。

我們可以運(yùn)行一下這個(gè)例子:

$ node example2.js
[ { _id: "female", value: { min: [Object], max: [Object] } },
  { _id: "male", value: { min: [Object], max: [Object] } } ]
例子3:計(jì)算每種興趣愛(ài)好的人數(shù)

在我們最后的例子中,我們會(huì)看看有多少用戶有相同的興趣愛(ài)好。我們?cè)陧?xiàng)目根目錄創(chuàng)建一個(gè)叫 example3.js 的文件。用戶數(shù)據(jù)長(zhǎng)這樣子:

{
    "id": 0,
    "name": "Leanne Flinn",
    "email": "[email protected]",
    "work": "Unilogic",
    "dob": "Sun Mar 14 1909 12:45:53 GTM+0530 (LST)",
    "age": 27,
    "gender": "male",
    "salary": 16660,
    "hobbies": "Acrobatics,Photography,Papier-Mache",
    "_id": Object("57579f702fa6c7651e504fe2")
}

如你所見,每個(gè)用戶的興趣愛(ài)好列表都用逗號(hào)分隔。我們會(huì)找出有多少用戶有表演雜技的愛(ài)好等等。

Mapper 的邏輯

在這個(gè)場(chǎng)景下,我們的 mapper 會(huì)復(fù)雜一點(diǎn)。我們要為每個(gè)用戶的興趣愛(ài)好發(fā)送一個(gè)新的 key-value 對(duì)。這樣,每個(gè)用戶的每個(gè)興趣愛(ài)好都會(huì)觸發(fā)一次計(jì)算。最終我們會(huì)得到如下的結(jié)果:

Key Value
Acrobatics [1,1,1,1,1,1,….]
Meditation [1,1,1,1,1,1,….]
Music [1,1,1,1,1,1,….]
Photography [1,1,1,1,1,1,….]
Papier-Mache [1,1,1,1,1,1,….]
Reducer 的邏輯

在這里,我們只要簡(jiǎn)單地為每種興趣愛(ài)好求和就好了。最終我們會(huì)得到下面的結(jié)果:

Key Value
Acrobatics 6641
Meditation 3338
Music 3338
Photography 3303
Papier-Mache 6661
代碼
var mongojs = require("mongojs");
var db = mongojs("mapReduceDB", ["sourceData", "example3_results"]);
 
 
var mapper = function () {
     var hobbys = this.hobbies.split(",");
      for (i in hobbys) {
        emit(hobbys[i], 1);
    }
};
 
var reducer = function (key, values) {
    var count = 0;
    for (index in values) {
        count += values[index];
    }
 
    return count;
};
 
 
db.sourceData.mapReduce(
    mapper,
    reducer,
    {
        out : "example3_results"
    }
 );
 
 db.example3_results.find(function (err, docs) {
    if(err) console.log(err);
    console.log(docs);
 });

注意第7-9行,我們迭代了每個(gè)興趣愛(ài)好,然后發(fā)送了一次記數(shù)。
第13-18行可以用 Array.sum(values) 來(lái)代替,這樣是另外一種做相同事情的方式。最終我們得到的結(jié)果:

$ node example3.js
[ { _id: "Acrobatics", value: 6641 },
  { _id: "Meditation", value: 3338 },
  { _id: "Music", value: 3338 },
  { _id: "Photography", value: 6661 },
  { _id: "Papier-Mache", value: 3303 } ]

這就是 MongoDB 中運(yùn)行 MapReduce 的方法了。但要記住,有時(shí)候一個(gè)簡(jiǎn)單的查詢就能完成你想要的事情的。

出處

http://scarletsky.github.io/2016/06/12/mapreduce-in-mongodb/

參考資料

MapReduce in MongoDB

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/18854.html

相關(guān)文章

  • MongoDB指南---17、MapReduce

    摘要:操作花費(fèi)的時(shí)間,單位是毫秒。處理完成后,會(huì)自動(dòng)將臨時(shí)集合的名字更改為你指定的集合名,這個(gè)重命名的過(guò)程是原子性的。作用域在這些函數(shù)內(nèi)部是不變的。上一篇文章指南聚合下一篇文章指南聚合命令 上一篇文章:MongoDB指南---16、聚合下一篇文章:MongoDB指南---18、聚合命令 MapReduce是聚合工具中的明星,它非常強(qiáng)大、非常靈活。有些問(wèn)題過(guò)于復(fù)雜,無(wú)法使用聚合框架的查詢語(yǔ)言...

    jonh_felix 評(píng)論0 收藏0
  • MongoDB指南---17、MapReduce

    摘要:操作花費(fèi)的時(shí)間,單位是毫秒。處理完成后,會(huì)自動(dòng)將臨時(shí)集合的名字更改為你指定的集合名,這個(gè)重命名的過(guò)程是原子性的。作用域在這些函數(shù)內(nèi)部是不變的。上一篇文章指南聚合下一篇文章指南聚合命令 上一篇文章:MongoDB指南---16、聚合下一篇文章:MongoDB指南---18、聚合命令 MapReduce是聚合工具中的明星,它非常強(qiáng)大、非常靈活。有些問(wèn)題過(guò)于復(fù)雜,無(wú)法使用聚合框架的查詢語(yǔ)言...

    pubdreamcc 評(píng)論0 收藏0
  • mongoDB高級(jí)篇②】大數(shù)據(jù)聚集運(yùn)算之mapReduce(映射化簡(jiǎn))

    摘要:簡(jiǎn)述從字面上來(lái)理解就是兩個(gè)過(guò)程映射以及化簡(jiǎn)。在映射化簡(jiǎn)的過(guò)程都是每臺(tái)服務(wù)器自己的在運(yùn)算,大量的服務(wù)器同時(shí)來(lái)進(jìn)行運(yùn)算工作,這就是大數(shù)據(jù)基本理念。映射操作輸出了鍵值對(duì)結(jié)果。在中,所有的映射化簡(jiǎn)函數(shù)都是使用編寫,并且運(yùn)行在進(jìn)程中。 簡(jiǎn)述 mapReduce從字面上來(lái)理解就是兩個(gè)過(guò)程:map映射以及reduce化簡(jiǎn)。是一種比較先進(jìn)的大數(shù)據(jù)處理方法,其難度不高,從性能上來(lái)說(shuō)屬于比較暴力的(通過(guò)N...

    madthumb 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<