firebase - 在Firebase中处理推荐系统的大量数据

标签 firebase database-design firebase-realtime-database recommendation-engine nosql

我正在构建一个推荐系统,在其中使用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/

相关文章:

database - 为什么实际上需要多个数据库?

java - Firebase 数据库监听器返回空值

javascript - 使用 Firebase 单击多个对话时无法禁用监听器

ios - viewDidLoad,是否只调用一次?

firebase - 收到太多连接时会抛出什么 API 错误?

mysql - 在数据库负载下以安全的方式替换sql View

sql - 我怎样才能编写一个程序来获得级别 i 到 j 或像这样的树?

Firebase实时数据库Flutter流永不返回问题

java - 如何提高 RecyclerView 和 Firebase 搜索的性能?

swift - 事件指示器不会完成操作