我正在构建一个推荐系统,在其中使用Firebase来存储和检索有关电影和用户首选项的数据。
每部电影可以具有多个属性,其数据如下所示:
{
"titanic":
{"1997": 1, "english": 1, "dicaprio": 1, "romance": 1, "drama": 1 },
"inception":
{ "2010": 1, "english": 1, "dicaprio": 1, "adventure": 1, "scifi": 1}
...
}
为了提出建议,我的算法需要输入所有数据(电影)并与用户个人资料进行匹配。
但是,在生产模式下,我需要检索超过10,000部电影。尽管该算法可以相对较快地处理此问题,但从Firebase加载数据需要花费大量时间。
我按以下方式检索数据:
firebase.database().ref(moviesRef).on('value', function(snapshot) {
// snapshot.val();
}, function(error){
console.log(error)
});
我想知道您是否对加快速度有任何想法?是否有解决此问题的插件或技术?
我知道反规范化可以帮助拆分数据,但问题是我确实需要所有电影和所有相应的属性。
最佳答案
我的建议是使用Cloud Functions来解决此问题。
解决方案1(理想情况下)
如果您可以每小时/每天/每周计算建议
您可以使用Cloud Functions Cron每天/每周启动一次,并每周/每天为每个用户计算推荐。这样,您可以获得的结果与Spotify每周的播放列表/建议大致相同。
这样做的主要优点是您的用户不必等待所有10,000部电影都被下载,因为这将在每个星期天晚上的云功能中进行,编译25条建议的列表,并保存到用户的数据节点中,您可以在用户访问其个人资料时下载。
您的云函数代码如下所示:
var movies, allUsers;
exports.weekly_job = functions.pubsub.topic('weekly-tick').onPublish((event) => {
getMoviesAndUsers();
});
function getMoviesAndUsers () {
firebase.database().ref(moviesRef).on('value', function(snapshot) {
movies = snapshot.val();
firebase.database().ref(allUsersRef).on('value', function(snapshot) {
allUsers = snapshot.val();
createRecommendations();
});
});
}
function createRecommendations () {
// do something magical with movies and allUsers here.
// then write the recommendations to each user's profiles kind of like
userRef.update({"userRecommendations" : {"reco1" : "Her", "reco2", "Black Mirror"}});
// etc.
}
原谅伪代码。我希望这能给我一个想法。
然后,在您的前端,您将只需要为每个用户获取
userRecommendations
。这样,您可以将带宽和计算从用户设备转移到云功能。就效率而言,在不知道您如何计算建议的情况下,我无法提出任何建议。解决方案2
如果您无法每小时/每天/每周计算建议,并且每次用户访问其建议面板时都必须这样做
然后,您可以在用户每次访问其推荐页面时触发云功能。为此,我使用的一种快速作弊解决方案是将一个值写入用户的个人资料,例如:
{getRecommendations:true}
,一次在页面加载后,然后在云函数中侦听getRecommendations
中的更改。只要您具有这样的结构:userID> getRecommendations:true
并且,如果您具有适当的安全规则,以便每个用户只能写入其路径,则此方法也将为您提供发出请求的正确userID。这样您就知道要为哪个用户计算建议。云功能很可能可以更快地提取10,000条记录并节省用户带宽,最后只能将建议写入用户个人资料。 (类似于上面的解决方案1),您的设置如下所示:
[前端代码]
//on pageload
userProfileRef.update({"getRecommendations" : true});
userRecommendationsRef.on('value', function(snapshot) { gotUserRecos(snapshot.val()); });
[云功能(后端代码)]
exports.userRequestedRecommendations = functions.database.ref('/users/{uid}/getRecommendations').onWrite(event => {
const uid = event.params.uid;
firebase.database().ref(moviesRef).on('value', function(snapshot) {
movies = snapshot.val();
firebase.database().ref(userRefFromUID).on('value', function(snapshot) {
usersMovieTasteInformation = snapshot.val();
// do something magical with movies and user's preferences here.
// then
return userRecommendationsRef.update({"getRecommendations" : {"reco1" : "Her", "reco2", "Black Mirror"}});
});
});
});
由于您的前端将在
userRecommendationsRef
处监听更改,因此一旦完成云功能,您的用户就会看到结果。这可能需要几秒钟,因此请考虑使用加载指示器。P.S 1:我最终使用了比最初预期更多的伪代码,并删除了错误处理等,希望这通常能使您明白这一点。如果有任何不清楚的地方,请发表评论,我很乐意澄清。
附言2:我在为一个客户建立的小型内部服务中使用非常相似的流程,并且愉快地运行了一个多月。
关于firebase - 在Firebase中处理推荐系统的大量数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42753799/