Architecture de base de données pour système "Badge" et critères arbitraires (MySQL / PHP)

Quickie-Question:

Pour résumer, je suis un peu confus quant à la façon dont je concevrais une telle base de données qui permet la création indéfinie de règles de badge sans nécessiter de modifications structurelles aux tables utilisateur existantes dans la base de données.

Mémoriser le titre du Badge, les critères, etc. À quoi ressemblerait cette Table?

  • badge_id (1)
  • badge_title (10k Badge)
  • badge_image (10k.jpg)
  • badge_criteria ([messages] >= 10000)
    ...

Haleine-Question:

Je voudrais implémenter un système de badge sur mes propres projets personnels, mais je cherche un peu de conseil sur la meilleure façon de faire une telle chose. J'ai lu quelques-unes des questions ici sur les systèmes de badge, mais je ne vois pas l'architecture de base de données attirer beaucoup d'attention.

Les Badges basés sur des Points utilisateur (hypothétique "Badge 10k") semblent assez simples. Tout événement qui affecte la réputation des utilisateurs (upvotes, downvotes, answer-accepted, etc.) invoquerait une méthode pour examiner la nouvelle réputation des utilisateurs et potentiellement attribuer un badge.

Ce système semble assez simple, mais à quoi cela ressemble-t - il en tant que base de données pour l'administrateur qui veut créer d'innombrables badges avec peu d'effort sur la route-dont certains peuvent être basés sur des critères différents, et pas simplement la réputation de l'utilisateur.

La réputation de L'utilisateur est probablement une valeur dans l'enregistrement de l'utilisateur lui-même. Mais idéalement, ne voudriez-vous pas éviter d'ajouter de nouveaux champs à la table utilisateur lorsque vous créez de nouveaux badges? Par exemple, le badge "Edited 100 Entries" - vous ne créeriez pas une nouvelle colonne "entries_edited" dans la Table des utilisateurs, n'est-ce pas? Et puis incrémenter cela après chaque entrée-édité...

Des indices?

Archive Stackoverflow:


Remarque: Je ne demande pas comment associer les badges aux utilisateurs. Je ne demande pas comment attribuer des badges (cela sera fait par programme)

47
demandé sur Community 2009-06-26 17:44:31

7 réponses

Étant donné que les critères de badge peuvent être arbitrairement complexes, Je ne pense pas que vous puissiez les stocker dans une table de base de données décomposée en éléments de données "simples". Essayer d'écrire un "moteur de règles" capable de gérer des critères arbitrairement complexes va vous emmener sur le chemin de la réécriture de tous les outils que vous avez dans votre langage de programmation.

Si vous savez à l'avance que vous voulez que les badges soient limités à certains champs (c'est-à-dire que les badges ne sont basés que sur la réputation ou le nombre de modifications ou quelque chose), alors vous pouvez les stocker dans une table simple comme:

ReputationBadgeCriteria
  BadgeId
  BadgeName
  MinReputation

Alternativement, vous pouvez utiliser une sorte de DSL pour écrire vos "règles" mais vous devez également créer un analyseur pour analyser les règles lorsque vous les lisez ainsi que quelque chose pour exécuter ces règles. Selon la complexité que vous voulez dans votre DSL, cela peut ne pas être une tâche triviale. Cela ressemble au chemin que vous allez dans votre question avec une colonne de critères (probablement du texte brut) qui a quelque chose comme "[Réputation] > 1000 " ou "[Messages] > 5 " dedans. Vous devez toujours analyser et exécuter ces règles et la complexité d'écrire quelque chose pour le faire dépend de la complexité que vous voulez que ces règles soient.

Je vous recommande de lire ces Daily WTF articles pour plus d'informations sur les raisons pour lesquelles cette approche conduit à la douleur.

23
répondu David Archer 2009-06-26 14:17:47

Selon la distance que vous voulez aller avec, votre schéma peut devenir assez compliqué. Il me semble que les éléments de base que vous devez suivre sont:

Badges awarded
Points earned

Assez simple jusqu'à présent, mais vous voulez être en mesure de créer dynamiquement de nouveaux badges et de nouvelles catégories de points. Les récompenses de Badge dépendront du gain de points dans une ou plusieurs catégories de points qui totaliseraient un certain montant. Vous devez donc suivre la relation entre les catégories de points (et les points gagnés) et badges:

Point categories
Badge categories

La clé serait donc votre table de points utilisateur, qui relierait aux catégories de points, qui relient aux badges. Les utilisateurs gagnent des points dans une catégorie particulière, ce qui contribuerait à gagner des points vers un ou plusieurs badges.

badges:
badge_id
badge_name
required_points
....

point_categories:
point_id
category_name
weighting (optional)
...

point_groups:
badge_id
point_id
weighting (optional)
...

user_points:
user_id
point_id
points
...

user_badges:
user_id
badge_id
points_earned
badge_awarded (yes/no)
...

Votre interface "admin" permettrait à quelqu'un de créer un nouveau badge et de choisir les catégories de points nécessaires pour obtenir ce badge (point_groups). Chaque fois qu'un utilisateur gagne des points (user_points), vous mettez à jour la table user_points, puis déterminez quels badges ces points pourraient contribuer à (point_groups). Vous recompilez ensuite les points pour les badges qui ont été affectés par les points gagnés et mettez à jour la table user_badges avec le point_earned. Ensuite, vérifiez le champ points_earned dans user_badges contre les required_points dans la table badges.

Vous pouvez obtenir beaucoup plus fantaisiste en attribuant des poids différents à différentes catégories de points, ou même des poids différents pour les catégories de points pour des badges particuliers. Mais cette configuration serait permettre un nombre illimité de badges et de catégories de points à créer et à gérer assez facilement sans changer les structures de tables.

Si ce n'est pas tout à fait ce que vous cherchez, alors je pense que je devrais au moins obtenir un vote ou deux pour beaucoup de frappe.

19
répondu Brent Baisley 2009-06-26 15:12:29

Vous devez suivre vos utilisateurs uniques dans une table et les badges uniques dans une autre, puis créer une table de références croisées pour les relier.

Un utilisateur peut avoir plusieurs badges et un badge peut avoir de nombreux utilisateurs.

create table users (
id int,
name varchar
)

create table badges (
id int,
badge_name varchar
)


create table user_badges_xref (
user_id int,
badge_id int
)

Les statistiques qui peuvent affecter si un utilisateur gagne un badge sont suivies dans le cadre de l'administration du site. donc, quelque chose comme une réponse acceptée serait dans un schéma qui concerne les questions et les réponses. pour afficher la réponse et le propriétaire de la réponse, il y aurait une relation avec la table utilisateur et des déclencheurs qui vérifieraient les conditions de badge chaque fois qu'une modification était apportée.

Je ne demande pas comment attribuer des badges. Je demande comment stocker les critères dans la base de données.

Si vous souhaitez stocker l'opération logique nécessaire pour déterminer si un badge est gagné dans un champ quelque part?

Je pense être d'accord avec l'autre affiche que les critères devraient faire partie de la logique métier. Cette logique peut être sur l'application côté ou dans un déclencheur. Je pense que c'est une question de style.

Si vous étiez vraiment marié à l'idée de stocker les critères dans un champ, je le stockerais en SQL paramétré et l'exécuterais dynamiquement.

Donc, ce genre de chose serait dans votre champ de critères:

select "Badge Earned"
from all_posts 
where user_id = @user_id
having count(*) > 10000
5
répondu Bob Probst 2009-06-26 14:37:46

Je ne créerais pas d'incrément pour le badge d'édition. Je pense que vous devriez avoir un travail en arrière-plan et compter() le nombre de post édité pour les membres qui n'ont pas encore le badge d'édition. Lorsque vous voyez que le nombre est sur la plage que vous voulez, vous ajoutez une entrée dans la base de données qui indiquent que l'Utilisateur a le badge.

Je pense que c'est à peu près la même chose pour les autres badges. Essayez de limiter le nombre d'écriture et n'écrivez pas directement le nombre d'informations de badge dans le table utilisateur. Utilisez une table qui contiendra des informations de badge et les liera à la table utilisateur.

3
répondu Patrick Desjardins 2009-06-26 13:50:56

Je m'excuse d'être bref.

Pour implémenter un système comme celui-ci, je pourrais créer une table qui stocke les noms de procédure stockés ou les requêtes réelles qui seraient utilisées pour déterminer si un utilisateur particulier a gagné un badge.

badge_criteria
badge_key int
badge_criteria varchar(max)

Vous pouvez extraire et exécuter les requêtes pour les badges que l'utilisateur n'a pas gagnés de votre niveau intermédiaire, mais vous n'auriez pas à apporter de code ou de modifications structurelles pour ajouter de nouveaux badges à l'avenir.

3
répondu Christian Pena 2009-06-26 14:47:01

Je l'aborde comme ceci: Créer une table pour stocker tous les badges, et avoir une colonne Référence une fonction qui est exécutée pour voir si le badge est attribué. De cette façon, la table reste simple et la logique pour déterminer les badges peut être conservée dans le code, où elle est la mieux adaptée.

Avec cette méthode, les exigences de badge pourraient également être liées ensemble, pour former des dépendances plus complexes. Par exemple, l'utilisateur doit recevoir trois badges distincts et spécifiques dans un certain délai afin de obtenez ce badge.

3
répondu Tapefreak 2011-08-02 21:29:51

Cela va être presque impossible à faire dans la base de données-l'attribution des badges devrait être faite dans votre logique métier dans l'application. De cette façon, vous avez toutes les données existantes dont vous avez besoin (modifications, visites, réputation, etc.) et il peut être traité comme bon vous semble.

Mise à jour:

Si par critères vous entendez des règles qui déterminent si et comment le badge est attribué, alors ce n'est pas quelque chose qui devrait être stocké dans la base de données. Ce serait presque impossible à tester et maintenir.

Si vous voulez dire, par exemple, stocker le "nombre de modifications", il n'y a aucun moyen de modifier une table ou une procédure stockée pour inclure ces données si vous en avez besoin.

2
répondu John Rasch 2009-06-26 14:01:20