2013-05-16 3 views
3

Vue d'ensembleQuelle est la meilleure façon de stocker la liste d'amis Facebook d'un utilisateur dans ma base de données?

Je crée un site Web Ruby on Rails qui utilise Facebook pour vous connecter.

Pour chaque utilisateur, j'ai une entrée de base de données qui stocke son ID utilisateur Facebook avec d'autres informations de base.

J'utilise aussi la gemme Koala afin de récupérer le friendlist d'un utilisateur de Facebook, mais je ne suis pas certain de la façon dont je stocker ces données ...

Option 1

Je pouvais stocker un hachage sérialisé dans la table User les amis de l'utilisateur, si je voulais afficher une liste de tous les utilisateur courant amis, je pouvais saisir ce hachage et faire quelque chose le long des lignes de SELECT FROM Users WHERE facebook_user_id IN hash

Chaque fois que la l'utilisateur se connecte, je pourrais mettre à jour ce f ield pour stocker la dernière liste d'amis.

Option 2

Je pourrais créer une table d'amis et d'information d'amitié magasin ici, où un utilisateur a beaucoup d'amis. Il y aurait donc une rangée pour chaque amitié, (User1 et User2 colonnes). Ensuite, pour afficher une liste des de l'utilisateur actuel amis que je pouvais faire quelque chose comme SELECT User2 FROM Friends WHERE User1 = current_user

Cela semble être la meilleure option pour moi, mais ...

Il a l'inconvénient qu'il y aurait de lignes ... S'il y avait 100 000 utilisateurs, chacun avec 100 amis, c'est maintenant 10 000 000 lignes dans la table des amis. Cela signifie aussi que chaque fois que l'utilisateur se connecte, je dois faire une boucle sur sa liste d'amis Facebook retournée en utilisant Koala et créer un enregistrement ami si quelqu'un sur sa liste d'amis est dans ma table Utilisateur et qu'il n'y a pas de correspondance correspondante. entrée dans la table des amis. Cela semble être lent si un utilisateur a 1000 amis Facebook?

J'apprécierais toute indication sur la meilleure façon d'atteindre cet objectif.

Toutes mes excuses pour la question mal formulée, je vais essayer de la reformuler et de l'organiser sous peu.

Merci pour toute aide à l'avance.

Répondre

2

Si vous avez besoin de stocker beaucoup de données, vous devez stocker beaucoup de données. Si vous êtes comme la plupart, vous ne rencontrerez probablement pas ce problème plus tôt que vous avez l'argent pour le résoudre. En d'autres termes, vous supposez probablement que vous aurez plus de trafic et de données que vous n'en aurez, au moins à court terme. Donc je doute que ce soit un problème, même si c'est un bon signe que vous y pensez maintenant plutôt que plus tard. Comme je l'ai mentionné dans mon commentaire ci-dessous, la solution la plus simple est d'avoir une table de cravate avec une ligne pour chaque côté de la relation d'ami (un has_many :friends, through: :facebook_friend_relationships, class_name: 'FacebookFriend' sur FacebookFriend, selon la conception mentionnée ci-dessous). Mais votre question semblait porter sur la façon de réduire le nombre d'enregistrements, c'est ce que répondra le reste de la réponse.

Si vous devez stocker dans la base de données et vous êtes sûr que vous aurez absolument tous les utilisateurs de FB sur la planète qui vont sur votre site parce que c'est génial, mais ils ne seront pas tous touchés en même temps, sont limitées dans le stockage, vous pouvez utiliser un algorithme LRU (supprimer les enregistrements les moins récemment utilisés) éventuellement avec une expiration temporisée également. Vous pouvez simplement avoir un travail cron qui fait une requête sur la base de données puis supprime les anciens/inutilisés pour cela. Ce ne serait pas parfait, mais ce serait une solution simple.

Vous pouvez également archiver des données plus anciennes plutôt que de les jeter. Ainsi, les données fréquemment utilisées peuvent rester dans la table des utilisateurs actifs, et vous pouvez ensuite décharger des données plus anciennes vers une autre table ou même une autre base de données (et vous pourriez voir les gemmes apartment et second_base pour cela). Cependant, une fois que vous aurez atteint la taille voulue, vous examinerez probablement un certain nombre d'autres solutions architecturales qui ont beaucoup moins à voir avec les modèles/associations ActiveRecord ou la conception de schémas. Bien qu'il soit rentable de planifier à l'avance, je ne m'inquiéterais pas trop à ce sujet jusqu'à ce que vous soyez sûr que l'application aura assez d'utilisateurs pour investir le temps dans cela. Même si ActiveRecord a une certaine mise en cache, vous pouvez simplement éviter la base de données et mettre en cache vos amis en mémoire au début pour plus de rapidité, surtout si vous n'avez pas encore beaucoup d'utilisateurs, ce que vous n'avez probablement pas encore. Si vous pensez que vous manquerez de mémoire en raison du nombre élevé d'utilisateurs, LRU pourrait être une bonne option ici aussi, et lru_redux semble intéressant. Encore une fois, vous voudrez peut-être chronométrer le cache aussi expire et re-obtient des amis lorsque le cache expire. Même le simple stockage des résultats dans la session d'utilisateur peut être adéquat, c'est-à-dire dans la méthode d'action du contrôleur, il suffit de faire @friends ||= Something.find_friends(fb_user_id), et ce dernier est ce que la plupart des gens pourraient faire en premier lorsque vous commencez.

Si vous utilisez ActiveRecord, dans votre requête dans le contrôleur (ou sur l'association dans le modèle), utilisez include: pour éviter les requêtes n + 1. Cela va accélérer les choses.

Pour la conception du schéma, peut-être:

  • utilisateur - table des utilisateurs avec e-mail et informations authN. Regardez la gemme de Devise.
  • FacebookUser - informations sur l'utilisateur de Facebook.
  • FacebookFriendRelationship - un modèle de lien avec (id et) deux colonnes, un pour un identifiant FacebookUser et un pour l'autre.

En séparant les informations authN (utilisateur) à partir des données FB (FacebookUser et FacebookFriendRelationship), vous le rendre plus facile d'avoir d'autres comptes de médias sociaux, etc. chacun des informations spécifiques à ces comptes dans d'autres tableaux.

La complexité vient dans la relation de FacebookUser avec des amis si l'objectif est de minimiser les lignes dans la table de relations. Pour la moitié du nombre de lignes, vous avez une seule ligne pour une relation où l'ID de FacebookUser peut être dans une colonne de clé étrangère. Soit l'utilisateur a un ami ou est un ami, donc vous pouvez avoir deux associations has_many :through sur FacebookFriend qui utilisent chacune une clé étrangère différente dans FacebookFriendRelationship. Ou vous pouvez faire HABTM sans le modèle et utiliser les options foreign_key et association_foreign_key dans chaque association. De toute façon, vous pouvez ajouter une méthode pour ajouter les deux associations ensemble (parce qu'elles sont des tableaux). Au lieu de cela, vous pouvez utiliser SQL personnalisé dans un seul has_many si vous n'avez pas besoin d'utiliser ActiveRecord pour supprimer les associations normalement. Cependant, selon vos commentaires, je pense que vous voulez éviter cette complexité, et je suis d'accord avec vous, sauf si vous devez vraiment limiter le nombre de lignes de relations. Cependant, ce n'est pas le nombre de rangées de tables de cravates qui va manger les données, mais toutes les informations utilisateur que vous gardez dans la table FacebookFriends.

+0

Merci pour votre réponse.Tu as raison de n'avoir jamais autant d'utilisateurs, je voulais juste apprendre la meilleure façon de faire les choses. Si je vais avec le schéma que vous avez suggéré, chaque fois que l'utilisateur se connecte, je dois mettre à jour la table des relations pour créer des amitiés pour tous les amis de l'utilisateur qui se sont inscrits à mon site depuis leur dernière visite. Cela nécessiterait de boucler leur liste d'amis et d'essayer de trouver un utilisateur dans ma base de données, et s'il en existe un, créez une nouvelle entrée de relation s'il n'y en a pas déjà une. Est-ce la façon la plus efficace de faire les choses? Cela semble assez inefficace. – woodstock365

+0

Votre objectif semblait être d'avoir moins d'enregistrements (par exemple de 10.000.000 lignes dans la question), donc avoir une seule ligne pour chaque relation contre un enregistrement pour chaque direction de la même relation serait la moitié du nombre de lignes (donc serait 5,000,000). Mais, si cela ne vous dérange pas d'avoir éventuellement des lignes en double pour chaque relation, cela semblerait être une meilleure solution pour vos besoins actuels. –

+0

En outre, vous n'êtes pas (ou du moins ne devriez pas) faire la boucle dans le contrôleur pour obtenir chaque ami. Votre requête est et la base de données est (espérons-le) bonne à cela. Pour éviter les requêtes n + 1 comme celles auxquelles vous faites allusion, utilisez l'option ': include' pour vous assurer que les requêtes AR ne demandent qu'une seule requête par type de modèle pour une recherche unique. Vous pouvez encore optimiser cela, mais au début, vous n'en aurez probablement pas besoin. –

Questions connexes