Рубрики
Без рубрики

Факты MongoDB: Молниеносная агрегация

Автор оригинала: Vlad Mihalcea.

В моем предыдущем посте я продемонстрировал , как быстро вы можете вставить 50 миллионов записей о событиях времени с помощью MongoDB. На этот раз мы будем использовать все эти данные для проведения наших агрегационных тестов.

Вот как выглядит запись о событии времени:

{
        "_id" : ObjectId("529a2a988cccdb538932d31f"),
        "created_on" : ISODate("2012-05-02T06:08:47.835Z"),
        "value" : 0.9270193106494844
}

Помимо индекса первичного ключа по умолчанию “_id”, мы также создали его для поля “created_on”, так что это все наши индексы:

[
        {
                "v" : 1,
                "key" : {
                        "_id" : 1
                },
                "ns" : "random.randomData",
                "name" : "_id_"
        },
        {
                "v" : 1,
                "key" : {
                        "created_on" : 1
                },
                "ns" : "random.randomData",
                "name" : "created_on_1"
        }
]

Теперь давайте используем все 50 миллионов записей для построения ежедневного отчета, подсчитывая, сколько событий было сгенерировано за день, включая минимальное, максимальное и среднее значение за этот конкретный день.

Вот как выглядит наш сценарий:

var start = new Date();
var dataSet = db.randomData.aggregate([
    {
        $group: {
                "_id": { 
                    "year" : {
                        $year : "$created_on"
                    }, 
                    "dayOfYear" : {
                        $dayOfYear : "$created_on"
                    }
                }, 
                "count": { 
                    $sum: 1 
                }, 
                "avg": { 
                    $avg: "$value" 
                }, 
                "min": { 
                    $min: "$value" 
                }, 
                "max": { 
                    $max: "$value" 
                }       
            }
    },
    {
        $sort: {
            "_id.year" : 1, 
            "_id.dayOfYear" : 1
        }   
    }
]);
if(dataSet.result != null && dataSet.result.length > 0) {
    print("Aggregated:" + dataSet.result.length + " days.");    
    db.dailyReport.insert(dataSet.result);
}
var end = new Date();
print("Aggregation took:" + (end.getTime() - start.getTime())/1000 + "s");

После объединения всех данных результаты сохраняются в новой коллекции ежедневных отчетов. Давайте запустим сценарий и посмотрим, что мы получим:

D:\wrk\vladmihalcea\mongodb-facts\aggregator\timeseries>mongo random aggregate_daily_report.js
MongoDB shell version: 2.4.6
connecting to: random
Aggregated:367 days.
Aggregation took:129.052s

Итак, за 129 секунд нам удалось построить наш отчет по всем этим данным. Давайте проверим новую коллекцию и посмотрим наши ежедневные отчеты.

{
        "_id" : {
                "year" : 2012,
                "dayOfYear" : 1
        },
        "count" : 137244,
        "avg" : 0.5009360724400802,
        "min" : 0.0000013632234185934067,
        "max" : 0.9999953350052238
}
{
        "_id" : {
                "year" : 2012,
                "dayOfYear" : 2
        },
        "count" : 136224,
        "avg" : 0.49982110975583033,
        "min" : 0.0000023238826543092728,
        "max" : 0.9999841095414013
}

Поскольку мы сгенерировали наши значения, связанные с событием времени, с помощью Math.random (), среднее, минимальное и максимальное значения-это то, что мы в любом случае ожидали. Что действительно интересно, так это то, как быстро MongoDB удалось собрать все эти данные со скоростью 387440 документов в секунду.

Будучи в восторге от этого результата, давайте теперь проверим, как быстро мы можем случайным образом выбрать одночасовой отчет. Сначала мы сопоставляем записи за один час, затем группируем и сортируем, чтобы, наконец, отобразить результаты в оболочке Mongo.

var minDate = new Date(2012, 0, 1, 0, 0, 0, 0);
var maxDate = new Date(2013, 0, 1, 0, 0, 0, 0);
var delta = maxDate.getTime() - minDate.getTime();
var fromDate = new Date(minDate.getTime() + Math.random() * delta);
fromDate.setHours(0, 0, 0, 0);
var toDate = new Date(fromDate.getTime() + 60 * 60 * 1000);

print("Aggregating from " + fromDate + " to " + toDate);

var start = new Date();

var dataSet = db.randomData.aggregate([
    {
        $match: {
            "created_on" : {
                $gte: fromDate, 
                $lt : toDate    
            }
        }
    },
    {
        $group: {
                "_id": { 
                    "year" : {
                        $year : "$created_on"
                    }, 
                    "dayOfYear" : {
                        $dayOfYear : "$created_on"
                    },
                    "hour" : {
                        $hour : "$created_on"
                    }
                }, 
                "count": { 
                    $sum: 1 
                }, 
                "avg": { 
                    $avg: "$value" 
                }, 
                "min": { 
                    $min: "$value" 
                }, 
                "max": { 
                    $max: "$value" 
                }       
            }
    },
    {
        $sort: {
            "_id.year" : 1, 
            "_id.dayOfYear" : 1,
            "_id.hour" : 1
        }   
    }
]);
if(dataSet.result != null && dataSet.result.length > 0) {
    dataSet.result.forEach(function(document)  {
        printjson(document);
    });
}
var end = new Date();
print("Aggregation took:" + (end.getTime() - start.getTime())/1000 + "s");

Запустив этот скрипт, мы получим следующий результат:

D:\wrk\vladmihalcea\mongodb-facts\aggregator\timeseries>mongo random aggregate_hour_report.js
MongoDB shell version: 2.4.6
connecting to: random
Aggregating from Mon Jul 16 2012 00:00:00 GMT+0300 (GTB Daylight Time) to Mon Jul 16 2012 01:00:00 GMT+0300 (GTB Daylight Time)
{
        "_id" : {
                "year" : 2012,
                "dayOfYear" : 197,
                "hour" : 21
        },
        "count" : 5808,
        "avg" : 0.5015344015735451,
        "min" : 0.00005716201849281788,
        "max" : 0.9998941225931048
}
Aggregation took:0.209s

Это происходит так быстро, что мне даже не нужно предварительно рассчитывать отчеты по часам, что означает, что я мог бы легко генерировать их по требованию во время выполнения.

Платформа агрегации MongoDB чрезвычайно полезна, и ее производительность не может остаться незамеченной. То, что я показал вам, было всего лишь простыми примерами, которые не требовали никакой дополнительной оптимизации, стремясь продемонстрировать готовую производительность MongoDB.

Код доступен на GitHub .