J'ai une longue histoire avec les bases de données relationnelles, mais je suis nouveau sur MongoDB et MapReduce, donc, je suis presque positif, je dois être en train de faire quelque chose de mal. Je vais sauter à droite dans la question. Désolé si c'est long.
J'ai une table de base de données dans MySQL qui suit le nombre de membre vues de profil pour chaque jour. Pour les tests il a 10 000 000 de lignes.
CREATE TABLE `profile_views` (
`id` int(10) unsigned NOT NULL auto_increment,
`username` varchar(20) NOT NULL,
`day` date NOT NULL,
`views` int(10) unsigned default '0',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`,`day`),
KEY `day` (`day`)
) ENGINE=InnoDB;
De données typique pourrait ressembler à ceci.
+--------+----------+------------+------+
| id | username | day | hits |
+--------+----------+------------+------+
| 650001 | Joe | 2010-07-10 | 1 |
| 650002 | Jane | 2010-07-10 | 2 |
| 650003 | Jack | 2010-07-10 | 3 |
| 650004 | Jerry | 2010-07-10 | 4 |
+--------+----------+------------+------+
J'ai utiliser cette requête pour obtenir le top 5 des plus consultés de profils depuis 2010-07-16.
SELECT username, SUM(hits)
FROM profile_views
WHERE day > '2010-07-16'
GROUP BY username
ORDER BY hits DESC
LIMIT 5\G
Cette requête se termine en moins d'une minute. Pas mal!
Maintenant, le déplacement sur le monde de MongoDB. - Je configurer un environnement fragmenté à l'aide de 3 serveurs. Serveurs de M, S1 et S2. J'ai utilisé les commandes suivantes pour définir la plate-forme jusqu' (Note: j'ai caché la propriété intellectuelle addys).
S1 => 127.20.90.1
./mongod --fork --shardsvr --port 10000 --dbpath=/data/db --logpath=/data/log
S2 => 127.20.90.7
./mongod --fork --shardsvr --port 10000 --dbpath=/data/db --logpath=/data/log
M => 127.20.4.1
./mongod --fork --configsvr --dbpath=/data/db --logpath=/data/log
./mongos --fork --configdb 127.20.4.1 --chunkSize 1 --logpath=/data/slog
Une fois ceux-ci étaient en place, j'ai sauté sur le serveur M, et a lancé mongo. J'ai lancé les commandes suivantes:
use admin
db.runCommand( { addshard : "127.20.90.1:10000", name: "M1" } );
db.runCommand( { addshard : "127.20.90.7:10000", name: "M2" } );
db.runCommand( { enablesharding : "profiles" } );
db.runCommand( { shardcollection : "profiles.views", key : {day : 1} } );
use profiles
db.views.ensureIndex({ hits: -1 });
J'ai ensuite importé le même 10 000 000 de lignes de MySQL, ce qui m'a donné des documents qui ressemblent à ceci:
{
"_id" : ObjectId("4cb8fc285582125055295600"),
"username" : "Joe",
"day" : "Fri May 21 2010 00:00:00 GMT-0400 (EDT)",
"hits" : 16
}
Maintenant vient la vraie viande et les pommes de terre ici... Ma carte et de réduire les fonctions. De retour sur le serveur M dans la coquille j'ai d'installation de la requête et de l'exécuter comme ça.
use profiles;
var start = new Date(2010, 7, 16);
var map = function() {
emit(this.username, this.hits);
}
var reduce = function(key, values) {
var sum = 0;
for(var i in values) sum += values[i];
return sum;
}
res = db.views.mapReduce(
map,
reduce,
{
query : { day: { $gt: start }}
}
);
Et d'ici l'été j'ai des problèmes. Cette requête a pris plus de 15 minutes! La requête MySQL a pris moins d'une minute. Voici le résultat:
{
"result" : "tmp.mr.mapreduce_1287207199_6",
"shardCounts" : {
"127.20.90.7:10000" : {
"input" : 4917653,
"emit" : 4917653,
"output" : 1105648
},
"127.20.90.1:10000" : {
"input" : 5082347,
"emit" : 5082347,
"output" : 1150547
}
},
"counts" : {
"emit" : NumberLong(10000000),
"input" : NumberLong(10000000),
"output" : NumberLong(2256195)
},
"ok" : 1,
"timeMillis" : 811207,
"timing" : {
"shards" : 651467,
"final" : 159740
},
}
Non seulement at-il jamais de courir, mais les résultats ne semblent même pas être correcte.
db[res.result].find().sort({ hits: -1 }).limit(5);
{ "_id" : "Joe", "value" : 128 }
{ "_id" : "Jane", "value" : 2 }
{ "_id" : "Jerry", "value" : 2 }
{ "_id" : "Jack", "value" : 2 }
{ "_id" : "Jessy", "value" : 3 }
Je sais que ces numéros de valeur devrait être beaucoup plus élevé.
Ma compréhension de l'ensemble du paradigme MapReduce est la tâche de l'exécution de cette requête doivent être répartis entre tous éclat membres, ce qui devrait augmenter les performances. J'ai attendu jusqu'à Mongo a été fait distribuer les documents entre les deux tesson serveurs après l'importation. Chacun avait presque exactement de 5 000 000 de documents lorsque j'ai commencé cette requête.
Donc, je dois être en train de faire quelque chose de mal. Quelqu'un peut-il me donner des pointeurs?
Edit: Quelqu'un sur IRC évoqué l'ajout d'un index sur le champ du jour, mais aussi loin que je peux dire que c'était fait automatiquement par MongoDB.