所以我有这个问题。我使用节点js + mongoose,尝试向用户推荐一部电影。背后的数学是很简单的,你检查其他用户对一部电影的评价,找出与你相似的人,然后你用它来预测某部电影的评分。你对所有的电影都这样做,然后推荐那些预测评分最高的电影。在我的数据库中,我已经获得了100 K的收视率,有1,6k部电影和大约950名用户(从电影中获得了数据集)。我有一个打分的模型,它有电影,标题,价值和用户。使用下面的代码,我可以预测一部电影,但是,当我试图使用循环来预测所有的1,k6电影时,我得到了这个msg“致命错误: CALL_AND_RETRY_LAST分配失败-内存中的进程”。我想我实现的方式占用了太多的内存。这也需要很多时间。大约3-4秒来预测一部电影,这意味着大约100分钟来预测所有的1,6k电影。有人对改进有什么建议吗?我对nodejs非常陌生,这种异步环境让我感到不舒服。这是我的代码:
Rating.find({title:"Batman Forever (1995)"}, function(err,rating){
if (err) throw err;
var tempSimilarValues = [];
var count = 0;
Rating.find({user: userV}, function(err,result) {
var tempMovieV;
var tempRatingArrayV = [];
var tempMovieArrayV = [];
while (result.length>0) {
tempMovieV=result.pop();
tempMovieArrayV.push(tempMovieV.movieid);
tempRatingArrayV.push(tempMovieV.value);
}
//calculating averageRatingV
var ratingV;
var avarageRatingV=0;
var countV=0;
for(ratingV in tempRatingArrayV){
countV++;
avarageRatingV=avarageRatingV+tempRatingArrayV[ratingV];
}
avarageRatingV=avarageRatingV/countV;
rating.forEach(function(obj){
Rating.find({user: obj.user}, function(err,result2) {
var tempRatingArray = [];
var tempMovieArray = [];
var tempMovie;
var tempAverage=0;
var ammount = result2.length
while (result2.length>0) {
tempMovie=result2.pop();
tempMovieArray.push(tempMovie.movieid);
tempAverage=tempAverage+tempMovie.value
tempRatingArray.push(tempMovie.value);
}
var averageU=tempAverage/ammount;
var similar = calSim(tempRatingArrayV,tempRatingArray, tempMovieArrayV, tempMovieArray);
if(obj.user!=userV){
tempSimilarValues.push([similar,obj.user,obj.value,averageU]);
}
count++;
if(count == rating.length){
tempSimilarValues.sort(function (a,b){
if (a[0] > b[0]) {
return -1;
}
if (a[0] < b[0]) {
return 1;
}
// a must be equal to b
return 0;
});
var similarValues=tempSimilarValues.slice(0,k);
var similarity;
var teller=0;
var nevner=0;
for (similarity in similarValues){
teller=teller+similarValues[similarity][0]*(similarValues[similarity][2]-similarValues[similarity][3]);
nevner = nevner + similarValues[similarity][0];
}
var pred = avarageRatingV + teller/nevner;
console.log(pred);
}
})
})
})
})发布于 2015-11-06 10:07:08
使用回调来嵌套多个方法的代码将使您最终使用回滚地狱。处理场景的一个更好的方法是使用异步库,特别是它的系列()和瀑布()方法。
为了举例说明这一点,使用类似的简短示例执行类似的多次回调操作,以查找属于用户的评级(代码一),查找属于某个标题的一些评级(代码2),计算平均评等(代码3),然后计算预测等级最高的评等(代码4):
codeOne(function(a){
codeTwo(function(b){
codeThree(function(c){
codeFour(function(d){
// Final callback code
})
})
})
})应用系列方法以串联方式运行函数的任务数组,每个函数运行一次之前的函数已经完成。如果本系列中的任何函数将错误传递给回调函数,则不再运行函数,并立即使用错误值调用回调。否则,回调将在任务完成时接收结果数组。
async.series([
function(callback){
// code one
callback(null, 'one')
},
function(callback){
// code two
callback(null, 'two')
},
function(callback){
// code three
callback(null, 'three')
},
function(callback){
// code four
callback(null, 'four')
}],
// optional callback
function(err, results){
// results is ['one', 'two', 'three', 'four']
// final callback code
}
)应用瀑布方法以串联方式运行函数的任务数组,每个方法将其结果传递给数组中的下一个。但是,如果任何任务将错误传递给它们自己的回调,则不会执行下一个函数,并且将立即使用错误调用主回调。
async.waterfall([
function(callback){
// code one
callback(null, 'one', 'two')
},
function(arg1, arg2, callback){
// arg1 is equals 'one' and arg2 is 'two'
// code three
callback(null, 'three')
},
function(arg1, callback){
// arg1 is 'three'
// code four
callback(null, 'four');
}], function (err, result) {
// result is 'four'
}
)在您的示例代码中,建议将其重构为使用瀑布方法。下面是我关于使用异步库实现逻辑的说明,而不是100%肯定您正在尝试实现的目标,因此这可能不起作用,但您可能会得到这样的概念:
async.waterfall([
function(callback){
// code one - calculate the average rating for user
Rating.find({user: userV}, function(err,result) {
if (err) callback(err);
var ratingV,
avarageRatingV = 0,
countV = 0,
tempRatingArray = result.map(function(rating){
return rating.value;
}),
tempMovieArrayV = result.map(function(rating){
return rating.movieid;
});
//calculating averageRatingV
for(ratingV in tempRatingArrayV){
countV++;
avarageRatingV = avarageRatingV + tempRatingArrayV[ratingV];
}
avarageRatingV=avarageRatingV/countV;
callback(null, avarageRatingV, tempRatingArrayV, tempMovieArrayV);
})
},
function(arg1, arg2, arg3, callback){
// arg1 equals averageRatingV
// arg2 equals tempRatingArrayV
// arg3 equals tempMovieArrayV
// code to return the users for "Batman Forever (1995)" movie ratings
Rating.find({ title: "Batman Forever (1995)" }, function(err, ratings){
if (err) callback(err);
var users = ratings.map(function(r){ return r.user; });
callback(null, arg1, arg2, arg3, users);
});
},
function(arg1, arg2, arg3, arg4, callback){
// arg1 is averageRatingV,
// arg2 equals tempRatingArrayV,
// arg3 equals tempMovieArrayVis ratings
// arg4 is the users array for "Batman Forever (1995)" movie ratings
// code to return
Rating.find({"user": { "$in": arg4 }}, function(err, result) {
// do the necessary calculations here
callback(null, result);
});
}], function (err, result) {
// final result
}
)https://stackoverflow.com/questions/33558275
复制相似问题