Je développe actuellement une demande pour permettre aux étudiants de gérer leurs cours et je ne sais pas vraiment comment concevoir la base de données pour une fonctionnalité spécifique. Le client veut, beaucoup comme Facebook, que lorsqu'un étudiant affiche la liste des personnes actuellement dans un cours spécifique, les personnes ayant les cours les plus mutuels avec l'utilisateur connecté sont affichées en premier. Presque identique à la fonctionnalité Facebook "Suggestions d'amis" avec un filtre supplémentaire. P>
En tant que fonctionnalité supplémentaire, j'aimerais ajouter une fonction de recherche permettant aux étudiants de rechercher un autre et d'afficher d'abord dans les résultats de la recherche les personnes ayant des cours les plus mutuels avec l'utilisateur connecté. P>
J'utilise actuellement MySQL, je prévois d'utiliser Cassandra pour d'autres fonctionnalités et j'utilise également Memcached pour la mise en cache de résultat et Sphinx pour la recherche. P>
Merci. P>
- p>
L'application est développée à Python, BTW P>
Et j'ai oublié de mentionner que l'approche standard (à l'aide d'une belle requête MySQL pour calculer tout cela avec une commande par clause) Est-ce que Wayyyys est trop lent. Ainsi, car les lectures sont beaucoup plus fréquentes que les lectures, j'aimerais que la majeure partie de la logique ait lieu une fois, lorsque la relation utilise le cours <-> est ajoutée. P>
J'ai pensé à la mise à jour d'un compteur de "cours mutuels" spécifique à un tuple (utilisateur, cours) qui sera augmenté pour tous les utilisateurs d'un cours lorsque l'utilisateur connecté rejoint un nouveau cours (ou diminué quand il le quitte). p>
3 Réponses :
Dites que vous avez une table nommée Dites que vous avez 2 utilisateurs, 20 et 50. P> Quand 20 ajoute 50 à l'âge d'amis, l'application ajoute une nouvelle ligne: p> et lorsque 50 confirme l'amitié, vous ajoutez une autre ligne avec des valeurs commuté: p> Lorsque vous souhaitez trouver des amis mutuels entre 20 et 50, simplement: p> utilisateurs code> et la clé principale est
userid code>. Ensuite, vous avez une table appelée
amis code> avec 2 colonnes appelées
userid code> (pk) et
amicalUserid code>.
Oh oui merci. Ça marche. Mais ce n'est certainement pas une solution viable, pour les problèmes de performance. Même si cette demande est faite lorsqu'une nouvelle relation a lieu pour calculer et stocker les résultats, ce serait une manière trop lente avec une jolie grande table.
Cela a l'air bien, mais pourquoi ne trouvez-vous pas les amis mutuels et les stocker dans une autre table afin que vous n'ayez pas à faire les calculs encore et encore, il suffit de lancer un travail qui mettrait à jour les amis mutuels chaque fois que l'utilisateur fait une nouvelle connexion.
Si vous avez déjà votre solution, mais le problème est juste la vitesse de cette requête, essayez de le faire plus tôt. Lorsque les amitiés d'un utilisateur changent, retentissez un travail qui calcule ces choses et stocke tous les résultats. Ne vous disputez pas à la suite d'une demande lorsque vous avez besoin du résultat si rapidement. Faire des choses aussi chères qu'une seule fois et les faire avant qu'une demande soit jamais faite. P>
Ainsi, lorsqu'une nouvelle relation est ajoutée, faites ce que je pensais: mettre à jour un compteur pour des relations mutuelles (à Cassandra) pour chaque utilisateur déjà dans le cours. Lors de l'affichage des résultats, prenez simplement les données de Cassandra, affichez les résultats tels qu'ils viennent (déjà commandés) et affichent d'autres utilisateurs (sans relation) après ... - Ma seule préoccupation serait toujours une performance. Ce ne serait-il pas une énorme surcharge lorsqu'il s'agit d'un parcours avec des milliers de personnes?
Dépend de si vous le faites "pour x dans Y: updateateql (newvalue)" ou "Compteur de mise à jour = compteur + 1 où ...". Le premier va frapper les frais généraux du réseau. La seconde devrait être assez rapide.
Ouais. Si vous avez terminé dans SQL, je suis totalement d'accord avec vous. Mais le problème de la performance est toujours (un peu) vivant. Si je parle d'un parcours avec 100 000 personnes (oui, il y a!), Ne serait pas la requête SELECT U.ID à partir des utilisateurs u interne joindre relation r on (u.id == r.user_id_1 ou u .Id == r.user_id_2) Commandez par R.Mutual_counter Limiter ... Code> Soyez un peu cher? Si j'utilise Cassandra, je peux stocker déjà des données commandées. Mais autant que je sache, je dois faire boucler les relations manuellement: /
Ou peut-être (ne pas diminuer le temps nécessaire, mais améliorer l'expérience utilisateur) en déléguant ce travail à d'autres serveurs, par exemple avec Gearman?
Je briserais cela comme (2) des requêtes et je trouverais l'intersection dans Python: puis trouve l'intersection dans Python.
Ensuite, vous pouvez laisser la base de données faire la mise en cache, etc ... sans aucune jointure pour ralentir les choses. P> p>
Que voulez-vous dire des gens avec les amis les plus mutuels? Vous voulez dire trouver un autre utilisateur qui a autant d'amis que la personne qui se connecte actuellement? Vous devrez également dire quelle langue vous développez. Cela ressemble à des éléments Web, mais MySQL peut être utilisé pour des applications autonomes. Et nous devons toujours savoir si c'est PHP / ASP / JS ou une autre langue.
Oui, tu me crois bien. L'application est développée à Python, mais vraiment, je serais confronté au même problème exact avec une autre langue. Je ne m'attends pas à ce que les gens m'aident avec du code, mais avec des idées structurelles :)
La mise en œuvre de «amis mutuels» serait quelque peu différente de la mise en œuvre d'une fonctionnalité «de cours la plus mutuelle». Le premier n'a besoin que d'un seul type d'entité (personne) et d'une relation "est un ami avec". Ce dernier a eu deux entités (étudiant, cours) et relation entre étudiant et cours à partir desquelles des relations entre étudiants devraient être extrapolées.
Oui, je vois que ce sera différent. Mais la logique derrière la couverture aura probablement beaucoup en commun. Comment ont-ils réussi à avoir autant de performances avec des centaines d'utilisateurs de millions et probablement des milliards de relations entre eux.
J'ai lu dans quelques endroits qui disent qu'il serait peut-être préférable de tirer des données de SQL non achoué et que la table de comparaison aboutit à votre code. Je peux voir la logique si vous n'avez qu'une petite quantité de CPU pour la DB et une grande quantité pour votre serveur Web.
C'est ce que je ferais. Mais ici, je parle d'une énorme base de données (vraiment) et d'obtenir 10.000 entrées à afficher seulement 10 est un gaspillage fantastique de mémoire et de la CPU. Et si je viens de chercher 10, la base de données fera toujours le travail. L'idéal serait en fait de disposer des données déjà commandées dans la base de données. Comme avec Cassandra.
Êtes-vous sûr de ne pas accélérer la base de données avec des indices soigneusement choisis? Ce type de choses devrait être facile pour tout serveur de base de données, même avec 100 000 étudiants.
Il y a des index et ils sont utilisés pour la clause de jointure, si je fais confiance à la commande Explique. Le problème est que cette solution n'est pas vraiment évolutive. Aujourd'hui, il peut être viable avec 100 000 personnes. Mais demain, avec quelques millions d'utilisateurs?
Souhaitez-vous savoir comment vous avez finalement fait cela et de préférence un lien vers votre application? Merci.
Hey. Je ne peux pas lier à ma demande principalement parce que c'est interne. Mais j'ai enfin utilisé Elasticsearch à cet effet: lorsqu'un étudiant rejoint ou laisse un cours, je stocke dans Elasticsearch la liste de tous les cours de cet utilisateur. Lorsque vous recherchez des amis mutuels, je viens d'exécuter une requête sur les utilisateurs, passant comme paramètre qui la liste et la commande par score, tout simplement. Compte tenu du très faible nombre de cours et par utilisateur, il fonctionne rapidement et peut être mis en cache. Cela me donne également un moteur de recherche riche en fonctionnalités en même temps. Nous sommes heureux avec cette solution.