尝试使用MongoDB玩弄大数据

那是什么?

关于MongoDB

・MongoDB属于所谓的NoSQL数据库,而不是关系型数据库RDBMS。

是指处理大数据的那个人吧。

用类似于JSON的格式表达被称为“文档”的结构化数据,并将这些文档集合作为“集合”进行管理。

简而言之,这是一个将唯一哈希值和JSON组合在一起形成的关联数组。

虽然无法像关系型数据库一样高效地执行复杂的连接操作,但可以快速地进行数据的添加、更新、删除和查询。

太棒了。

Mongo这个名字来源于英语中的“humongous”,意思是“巨大的”。

笑了。

关于大数据

这个术语表示着一个非常庞大且复杂的数据集合,以至于无法使用现有的数据库管理工具和传统的数据处理应用程序来处理。

简而言之,有大量的数据。

立即安装

brew install mongodb

为了在登录时启动MongoDB,执行以下操作:
ln -sfv /usr/local/opt/mongodb/*.plist ~/Library/LaunchAgents
然后立即加载MongoDB:
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist

安装本体。
还要进行启动时的设置,要注意哦。

ln -sfv /usr/local/opt/mongodb/*.plist ~/Library/LaunchAgents
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist

按照被告知的方式,执行咒语。

mongo -version

MongoDB的shell版本为3.2.0。

安装完成了。太棒了!

适当地尝试流动数据

根据我的调查,似乎可以使用JavaScript轻松地操作mongo。
在一个合适的位置创建一个js文件,首先尝试插入一些无关紧要的数据。

cd
mkdir mongo
vi create.js

这样做。

for (var i = 0; i < 100; ++i) {
  db.test.save({
    hoge : "hoge" + i
  });
}

请随便写一个与“insert分”相当的内容。

mongo --quiet localhost/test create.js

在MongoDB中插入这个东西。只有大约100个条目,所以会瞬间完成。

mongoDB上で見てみる

mongo

mongoにアクセス。

db.test.find()

{ “_id” : ObjectId(“56a3111fcaf1a738f31cfce7”), “hoge” : “hoge0” }
{ “_id” : ObjectId(“56a3111fcaf1a738f31cfce8”), “hoge” : “hoge1” }
{ “_id” : ObjectId(“56a3111fcaf1a738f31cfce9”), “hoge” : “hoge2″ }

(”_id” : ObjectId(“56a3111fcaf1a738f31cfce7”), “hoge” : “hoge0″)
(”_id” : ObjectId(“56a3111fcaf1a738f31cfce8”), “hoge” : “hoge1″)
(”_id” : ObjectId(“56a3111fcaf1a738f31cfce9”), “hoge” : “hoge2″)

哦!!进来了!
但是如果是这种数据,没有什么可以操作的,所以就随便想象起来玩吧。

db.test.drop()

这次做的东西,由于不再使用,就删掉吧。

适当的模拟和数据设计

模拟(幻想)

我可怜的我,被要求对某个神秘公司的购买历史数据进行过去五年的汇总和调查。
听说这家公司的用户大约只有1000人左右,但日志记录却达到了大约1000万条。
这些虚构世界的居民真是各种怪异。

我编写了一个根据妄想创建日志数据的脚本。

const LOGS = 10000000;
const MAX_USER_ID = 1000;
const UNIXTIME_YEAR = 31536000;
const MAX_PURCHASE_PRICE = 10000;

function getRandomNumber(max) {
    return Math.floor(Math.random() * (max + 1));
}

var date = new Date();
function getRandomUnixTime(offset) {
    return Math.floor(date.getTime() / 1000) - getRandomNumber(offset);
}

for (var i = 0; i < LOGS; ++i) {
    db.purchaseLog.save({
        user_id        : getRandomNumber(MAX_USER_ID),
        purchase_price : getRandomNumber(MAX_PURCHASE_PRICE),
        purchase_at    : getRandomUnixTime(UNIXTIME_YEAR * 5),
    }); 
}

我认为不需要对代码进行解释。
正如我之前所述的想法。

mongo --quiet localhost/test create.js

因为之前只有大约100个数据,所以能够一下子处理完毕。
但这次有1000万个数据,虽然比关系数据库管理系统(RDBMS)快,但还是需要相应的时间。
希望能够快点结束。

准备弄的事情。

成功插入了1千万条数据,没有发生任何崩溃情况。顺便说一下,我的苹果电脑(4G内存)花了1小时7分23秒的时间。

我会立即查看已经制作好的数据。

db.test.find()

本地 0.000GB
测试 0.404GB

即使放入了1000万条数据,JSON文件本身的大小也很小,大约为400MB左右。

db.test.find()

{ “_id” : ObjectId(“56a31a2d201cdb2f439ca4ae”), “user_id” : 655, “purchase_price” : 9357, “purchase_at” : 1438883196 }
{ “_id” : ObjectId(“56a31a2e201cdb2f439ca4af”), “user_id” : 816, “purchase_price” : 6915, “purchase_at” : 1380445364 }
{ “_id” : ObjectId(“56a31a2e201cdb2f439ca4b0”), “user_id” : 851, “purchase_price” : 4786, “purchase_at” : 1382838307 }

{ “_id” : ObjectId(“56a31a2d201cdb2f439ca4ae”), “用户ID” : 655, “购买价格” : 9357, “购买时间” : 1438883196 }
{ “_id” : ObjectId(“56a31a2e201cdb2f439ca4af”), “用户ID” : 816, “购买价格” : 6915, “购买时间” : 1380445364 }
{ “_id” : ObjectId(“56a31a2e201cdb2f439ca4b0”), “用户ID” : 851, “购买价格” : 4786, “购买时间” : 1382838307 }

我确认了一下数据,如预期的那样。
虽然可以继续处理这样,但有点麻烦,所以我会写个包装器。

随意地准备适用于弄的JavaScript。

var results = db.purchaseLog.find({user_id:100});

//  suck
function formatDate(unixtime) {
    var date = new Date(unixtime * 1000);
    date.setTime(date.getTime() + (60 * 60 * 1000));
    var zeroPadding = function(num) {
        return ("0" + num).slice(-2);
    }
    var year = date.getFullYear();
    var month = zeroPadding(date.getMonth() + 1);
    var day = zeroPadding(date.getDate());
    var hour = zeroPadding(date.getHours());
    var min = zeroPadding(date.getMinutes());
    var sec = zeroPadding(date.getSeconds());
    return year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec;
}

var counter = 0;
results.forEach(function(result) {
    ++counter;
    print("id: " + result.user_id + "\t\t" + "price: " + result.purchase_price + "\t" + "date: " + formatDate(result.purchase_at));
});
print(counter);

大事な所は、一番上の行だけです。
db.purchaseLog.find(…) の所が、SQLのクエリ部分です。
サンプルで、単にuser_idが100番の人を抽出してみました。
後は表示に必要な処理を書いただけです。

注意点としては、データの取得条件は、特殊な場合を除いてfind()部分で取得するようにして下さい。
いくら早くてもforEach部分で処理してしまうと、パフォーマンスが落ちます。

后来,JavaScript的日期操作真的很烦人。

实际运行

mongo --quiet localhost/test find.js

编号:100 价格:9617 日期:2012年08月20日 16:42:24
编号:100 价格:5410 日期:2014年12月11日 17:48:45
编号:100 价格:1506 日期:2011年05月30日 11:18:03

处理结果出来的时间大约只需三秒,真是迅速,速度太快了。
要在关系型数据库中处理的话,可能需要超过一分钟的时间吧。
试着改变一些条件进行调整,就会发现无论怎样都非常迅捷。

总结

比我想象的要快

弄10,000,000件的数据时,速度非常快,让我感到惊讶。在这个例子中,我没有被强制等待10秒以上才执行JavaScript。

关系型数据库管理系统(RDBMS)给我留下了“主数据先生”的印象,而NoSQL则给我留下了“事务数据大哥”的印象。

一般的にビックデータと言われる、膨大なデータを扱う事に興味を持った方は
一度弄ってみてはどうでしょうか。

世界将会发生变化。

顺便提一句

db.purchaseLog.aggregate([
    { $group: { _id: "$user_id", total: { $sum: "$purchase_price" }}},
    { $sort:  { total: 1}}
]).forEach(function(result) {
    print("id: " + result._id + "\t\t" + "totalPrice: " + result.total);
});

…编号:795 价格:51749038

在过去的五年中,最常使用的人。
当条件变得复杂时,嵌套就变得不太易读了。我想用yml进行编写。

这段代码通过按照id进行分组并计算每个人的总金额后进行排序,但是运行速度为14秒。
哇哦!!

结束。