我有一个包含userId
,movieId
,movie-categoryId
,reviewId
,movieRating
和reviewDate
列的MovieRatings数据库。
在我的映射器中,我想提取 userId - > (movieId,movieRating)
然后在reducer中我想按用户对所有 movieId,movieRating 对进行分组。
这是我的尝试:
地图功能:
var map = function() {
var values={movieId : this.movieId, movieRating : this.movieRating};
emit(this.userId, values);}
减少功能:
var reduce = function(key,values) {
var ratings = [];
values.forEach(function(V){
var temp = {movieId : V.movieId, movieRating : V.movieRating};
Array.prototype.push.apply(ratings, temp);
});
return {userId : key, ratings : ratings };
}
运行MapReduce :
db.ratings.mapReduce(map, reduce, { out: "map_reduce_step1" })
输出:db.map_reduce_step1.find()
{ "_id" : 1, "value" : { "userId" : 1, "ratings" : [ ] } }
{ "_id" : 2, "value" : { "userId" : 2, "ratings" : [ ] } }
{ "_id" : 3, "value" : { "userId" : 3, "ratings" : [ ] } }
{ "_id" : 4, "value" : { "userId" : 4, "ratings" : [ ] } }
{ "_id" : 5, "value" : { "userId" : 5, "ratings" : [ ] } }
{ "_id" : 6, "value" : { "userId" : 6, "ratings" : [ ] } }
{ "_id" : 7, "value" : { "userId" : 7, "ratings" : [ ] } }
{ "_id" : 8, "value" : { "userId" : 8, "ratings" : [ ] } }
{ "_id" : 9, "value" : { "userId" : 9, "ratings" : [ ] } }
{ "_id" : 10, "value" : { "userId" : 10, "ratings" : [ ] } }
{ "_id" : 11, "value" : { "userId" : 11, "ratings" : [ ] } }
{ "_id" : 12, "value" : { "userId" : 12, "ratings" : [ ] } }
{ "_id" : 13, "value" : { "userId" : 13, "ratings" : [ ] } }
{ "_id" : 14, "value" : { "userId" : 14, "ratings" : [ ] } }
{ "_id" : 15, "value" : { "movieId" : 1, "movieRating" : 3 } }
{ "_id" : 16, "value" : { "userId" : 16, "ratings" : [ ] } }
我没有得到预期的输出。事实上,这个输出对我来说毫无意义!
这是python相当于我在减速器中尝试做的事情(以防万一减速器的目的不清楚):
def reducer_ratings_by_user(self, user_id, itemRatings):
#Group (item, rating) pairs by userID
ratings = []
for movieID, rating in itemRatings:
ratings.append((movieID, rating))
yield user_id, ratings
修改1 @chridam
以下是我真正想要做的概述:
Movies.csv 文件如下所示:
用户id,movieId,电影的categoryId,reviewId,movieRating,REVIEWDATE
1,1,1,1,5,7 /2000分之12
2,1,1,2,5,7 /2000分之12
3,1,1,3,5,7 /2000分之12
4,1,1,4,4,7 /2000分之12
5,1,1,5,4,7 /2000分之12
6,1,1,6,5,7 /2000分之15
1,2,1,7,4,7 /2000分之25
8,1,1,8,4,7 /2000分之28
9,1,1,9,3,8 /2000分之3
...
...
我将其导入mongoDB:
mongoimport --db SomeName --collection ratings --type csv --headerline --file Movies.csv
然后我尝试应用map-reduce函数,如上所述。在那之后,我会通过做一些像以下的事情将它导出回csv:
mongoexport --db SomeName --collection map_reduce_step1 --csv --out movie_ratings_out.csv --fields ...
这个movie_ratings_out.csv
文件应该是:
userId,movieId1,rating1,movieId2,rating2,...
1,1,5,2,4
...
...
因此每一行都包含每个用户的所有(电影,评级)对。
修改2
示例:
db.ratings.find().pretty()
{
"_id" : ObjectId("57f4a0dd9cb74fc4d344a40f"),
"userId" : 4,
"movieId" : 1,
"movie-categoryId" : 1,
"reviewId" : 4,
"movieRating" : 4,
"reviewDate" : "7/12/2000"
}
{
"_id" : ObjectId("57f4a0dd9cb74fc4d344a410"),
"userId" : 5,
"movieId" : 1,
"movie-categoryId" : 1,
"reviewId" : 5,
"movieRating" : 4,
"reviewDate" : "7/12/2000"
}
{
"_id" : ObjectId("57f4a0dd9cb74fc4d344a411"),
"userId" : 4,
"movieId" : 2,
"movie-categoryId" : 1,
"reviewId" : 6,
"movieRating" : 5,
"reviewDate" : "7/15/2000"
}
{
"_id" : ObjectId("57f4a0dd9cb74fc4d344a412"),
"userId" : 4,
"movieId" : 3,
"movie-categoryId" : 1,
"reviewId" : 2,
"movieRating" : 5,
"reviewDate" : "7/12/2000"
}
...
然后MapReduce预期输出json为:
{
"_id" : ....,
"userId" : 4,
"movieList" : [ {
"movieId" : 2
"movieRating" : 5
},
{
"movieId" : 1
"movieRating" : 4
}
...
]
}
{
"_id" : ....,
"userId" : 5,
"movieList" : ...
}
...
答案 0 :(得分:1)
您只需要运行一个汇总管道,该管道由一个汇总文档的 $group
阶段组成。它按指定的标识符表达式对输入文档进行分组,并应用累加器表达式。 $group
管道运算符类似于SQL的GROUP BY
子句。在SQL中,除非使用任何聚合函数,否则不能使用GROUP BY
。同样,您也必须在MongoDB中使用聚合函数。您可以在此处阅读有关聚合函数的更多信息。
您需要创建movieList
数组的累加器运算符为 $push
。
$group
阶段之后的另一个管道是 $project
运算符,用于选择或重塑流中的每个文档,包括,排除或重命名字段,注入计算字段,创建子文档字段,使用数学表达式,日期,字符串和/或逻辑(比较,布尔,控制)表达式 - 类似于您对SQL {{1}所做的操作}子句。
最后一步是 $out
管道,它将汇总管道的结果文档写入集合。它必须是管道中的最后一个阶段。
因此,您可以运行以下聚合操作:
SELECT
使用上面的示例5文档,如果查询db.ratings.aggregate([
{
"$group": {
"_id": "$userId",
"movieList": {
"$push": {
"movieId": "$movieId",
"movieRating": "$movieRating",
}
}
}
},
{
"$project": {
"_id": 0, "userId": "$_id", "movieList": 1
}
},
{ "$out": "movie_ratings_out" }
])
,示例输出将产生:
db.getCollection('movie_ratings_out').find({})