Инструменты пользователя

Инструменты сайта


dev:mongodb:ispolzovanie_skvoznogo_schjotchika_v_mapreduce

Использование сквозного счётчика в mapReduce

Описание

Иногда при использовании mapReduce требуется создать сквозную нумерацию записей, причём не хочется сначала гнать все записи на клиент, а потом обновлять их на сервере в отсортированном виде. Пример такой необходимости - создание таблицы рекордов какой-нибудь игры, когда надо отсортировать игроков по очкам и назначить каждому его место в таблице для последующей выборки. Но стантартная реализация mapReduce не позволяет такого сделать.

Решение

На помощь приходит JavaScript - будем хранить текущее значение счётчика непосредственно в данных объекта соединения.

Вариант для MongoDB < v1.5

Заметьте, что необходимо добавление функции finalize, иначе при повторном использовании данного соединения счётчик не обнулится.

f_map = function() {
    if (typeof db.top_idx != 'number') db.top_idx = 0;
    emit(this._id, { 'username': this.username, 'score': this.score, 'top_idx': db.top_idx++ });
}
 
f_reduce = function(k, va) {
    return va[0];
}
 
f_finalize = function(k, v) {
    db.top_idx = 0;
    return v;
}
 
db.runCommand({ 'mapreduce': 'Users', 'map': f_map, 'reduce': f_reduce, 'finalize': f_finalize, 'sort': { 'score': -1 }, 'out': 'Top' });

Вариант для MongoDB >= v1.5

В новой версии счётчик можно обнулять непосредственно перед выполнением mapReduce, поэтому функция finalize становится не нужна.

f_map = function() {
    emit(this._id, { 'username': this.username, 'score': this.score, 'top_idx': db.top_idx++ });
}
 
f_reduce = function(k, va) {
    return va[0];
}
 
db.eval('db.top_idx = 0');
db.runCommand({ 'mapreduce': 'Users', 'map': f_map, 'reduce': f_reduce, 'sort': { 'score': -1 }, 'out': 'Top' });

Результат

Допустим, мы имеем коллекцию Users со следующими данными:

{ "_id": ObjectId("4bf6127031018ee4da1d404c"), "username": "Всегда Третий", "score": 114457 }
{ "_id": ObjectId("4bf6127331018ee4da1d404d"), "username": "Всегда Первый", "score": 234756 }
{ "_id": ObjectId("4bf6127031018ee4da1d404e"), "username": "Иногда Второй", "score": 123745 }

После выполнения запроса mapReduce получим такую коллекцию Top:

{ "_id": ObjectId("4bf6127331018ee4da1d404d"), "value": { "username": "Всегда Первый", "score": 234756, "top_idx": 1 } }
{ "_id": ObjectId("4bf6127031018ee4da1d404e"), "value": { "username": "Иногда Второй", "score": 123745, "top_idx": 2 } }
{ "_id": ObjectId("4bf6127031018ee4da1d404c"), "value": { "username": "Всегда Третий", "score": 114457, "top_idx": 3 } }

И получить позицию в таблице рекордов на какого-либо игрока легче лёгкого:

db.Top.find({ '_id': ObjectId("4bf6127031018ee4da1d404e") }, { 'top_idx': 1, 'score': 1 });

Дискуссия

Enter your comment
 
dev/mongodb/ispolzovanie_skvoznogo_schjotchika_v_mapreduce.txt · Последние изменения: 18.11.2010 10:14 (внешнее изменение)

Инструменты страницы