【发布时间】:2016-10-05 07:39:05
【问题描述】:
我有一个包含 userId、movieId、movie-categoryId、reviewId、movieRating 和 reviewDate 列的 MovieRatings 数据库。
在我的映射器中,我想提取 userId -> (movieId, movieRating)
然后在减速器中,我想按用户对所有 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 文件如下所示:
userId,movieId,movie-categoryId,reviewId,movieRating,reviewDate
1,1,1,1,5,7/12/2000
2,1,1,2,5,7/12/2000
3,1,1,3,5,7/12/2000
4,1,1,4,4,7/12/2000
5,1,1,5,4,7/12/2000
6,1,1,6,5,7/15/2000
1,2,1,7,4,7/25/2000
8,1,1,8,4,7/28/2000
9,1,1,9,3,8/3/2000
...
...
我将它导入 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
...
...
所以每一行都包含每个用户的所有 (movie,rating) 对。
编辑 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" : ...
}
...
【问题讨论】:
-
您能否更新您的问题以包含一些示例文档和您的预期输出?我很确定聚合框架可以更好、更有效地处理这个问题。
-
@chridam 检查编辑!
-
我的意思是集合中的文档,即当您执行查询
db.ratings.find()时,可能会选择 5 个文档来制作样本,并向我们展示您对样本聚合操作的预期 JSON 输出。否则,尝试使用上述信息重现问题是徒劳的。您能否使用示例文档和预期的 JSON 输出更新您的问题? -
@chridam 检查编辑 2!
-
嘿@chridam!感谢你的回答。您还可以帮助我指出如何使用 map reduce 函数来做到这一点吗?只是为了练习。
标签: mongodb hadoop mapreduce nosql