database design - Arquitectura de base de datos para el sistema "Badge" y los criterios arbitrarios(MySQL/PHP)
database-design (7)
Dado que los criterios de identificación pueden ser arbitrariamente complejos, no creo que pueda almacenarlos en una tabla de base de datos dividida en elementos de datos "simples". Tratar de escribir un "motor de reglas" que pueda manejar criterios arbitrariamente complejos lo llevará por el camino de básicamente reescribir todas las herramientas que tiene en su lenguaje de programación.
Si sabes de antemano que quieres que las insignias se limiten solo a ciertos campos (es decir, las insignias solo se basan en la reputación o el número de ediciones o algo así), puedes almacenarlas en una tabla simple como:
ReputationBadgeCriteria
BadgeId
BadgeName
MinReputation
Alternativamente, podría usar algún tipo de DSL para escribir sus "reglas", pero también tendrá que crear un analizador para analizar las reglas cuando las lea, así como algo para ejecutar estas reglas. Dependiendo de la complejidad que desee en su DSL, esta puede no ser una tarea trivial. Esto se ve como la ruta a seguir en su pregunta con una columna Criterios (presumiblemente texto sin formato) que tiene algo así como "[Reputación]> 1000" o "[Publicaciones]> 5" en él. Todavía tiene que analizar y ejecutar esas reglas y la complejidad de escribir algo para hacerlo depende de cuán complejas sean esas reglas.
Le recomendaría que lea these articles diarios de la WTF para obtener información sobre por qué este enfoque lleva al dolor.
Quickie-Pregunta:
En resumen, estoy un poco confundido sobre cómo diseñaría una base de datos que permita la creación de reglas de credenciales indefinidas sin requerir cambios estructurales en las tablas de usuarios previamente existentes en la base de datos.
Almacenar el título de la insignia, los criterios, etc. ¿Cómo se vería esa tabla?
- badge_id (1)
- badge_title (10K Badge)
- badge_image (10k.jpg)
- badge_criteria ([posts]> = 10000)
...
Winded-Question:
Me gustaría implementar un sistema de distintivos en mis propios proyectos personales, pero estoy buscando un consejo sobre cómo sería mejor hacer tal cosa. He estado leyendo algunas de las preguntas aquí sobre los sistemas de distintivos, pero no veo que la arquitectura de bases de datos reciba mucha atención.
Las insignias que se basan en puntos de usuario (Hipotético "10k Badge") parecen bastante sencillas. Cualquier evento que afecte la reputación de los usuarios (upvotes, downvotes, answer-accepted, etc.) invocaría un método para revisar la nueva reputación de los usuarios y potencialmente otorgar una insignia.
Ese sistema suena bastante directo, pero ¿qué significa eso como una base de datos para el administrador que desea crear innumerables cantidades de insignias con poco esfuerzo en el futuro, algunas de las cuales pueden basarse en diferentes criterios y no simplemente en el usuario? reputación.
La reputación del usuario es probablemente un valor dentro del registro del usuario. Pero idealmente, ¿no le gustaría evitar tener que agregar nuevos campos a la tabla de usuarios cuando crea nuevas insignias? Por ejemplo, la credencial "Edited 100 Entries": no crearía una nueva columna "entries_edited" dentro de la tabla de usuarios, ¿verdad? Y luego incremente eso luego de cada edición de entrada ...
¿Algún consejo?
Archivo Stackoverflow:
- La mejor manera de almacenar los criterios de identificación (no es un duplicado)
- Diseñando un sistema de placa: ¿dónde disparar la lógica de negocios?
Nota: NO estoy preguntando cómo asociar insignias con los usuarios. NO estoy preguntando cómo otorgar insignias (eso se hará programáticamente)
Dependiendo de qué tan lejos quiera ir con él, su esquema puede ser bastante complicado. Me parece que los elementos de base que necesitas rastrear son:
Badges awarded
Points earned
Muy simple hasta ahora, pero desea poder crear dinámicamente nuevas insignias y nuevas categorías de puntos. Los premios de distintivos dependerán de los puntos de ganancia en una o más categorías de puntos que sumarían una cierta cantidad. Por lo tanto, debe seguir la relación entre las categorías de puntos (y los puntos obtenidos) y las insignias:
Point categories
Badge categories
Entonces, la clave sería su tabla de puntos de usuario, que se vincularía a las categorías de puntos, que se vinculan a las insignias. Los usuarios ganan puntos en una categoría particular, lo que contribuiría a ganar puntos para una o más insignias.
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)
...
Su interfaz de "administrador" le permitiría a alguien crear una nueva insignia y elegir qué categorías de puntos se requieren para ganar esa insignia (point_groups). Cada vez que un usuario obtiene puntos (user_points), actualiza la tabla user_points y luego determina a qué insignias podrían contribuir esos puntos (point_groups). A continuación, vuelve a compilar los puntos de las insignias que se vieron afectadas por los puntos obtenidos y actualiza la tabla user_badges con point_earned. Luego, verifique el campo points_earned en user_badges contra los required_points en la tabla de insignias.
Puede obtener mucho más lujo asignando diferentes pesos a diferentes categorías de puntos, o incluso diferentes pesos para las categorías de puntos para insignias particulares. Pero esta configuración permitiría crear y administrar una cantidad ilimitada de insignias y categorías de puntos sin cambiar las estructuras de las tablas.
Si eso no es completamente lo que estás buscando, entonces creo que al menos debería obtener una votación o dos para escribir a máquina.
Esto va a ser casi imposible de hacer en la base de datos: las insignias de adjudicación deben realizarse en la lógica de su negocio dentro de la aplicación. De esta forma, tiene todos los datos existentes que necesita (ediciones, visitas, reputación, etc.) y puede tratarlos como mejor le parezca.
Actualizar:
Si por criterios se entiende reglas que determinan si se otorga o no la insignia, entonces eso no es algo que deba almacenarse en la base de datos. Esto sería casi imposible de probar y mantener.
Si quiere decir, por ejemplo, almacenar el "número de ediciones", no hay forma de evitar modificar una tabla o un procedimiento almacenado para incluir esa información si la necesita.
Haría un seguimiento de sus usuarios únicos en una tabla y distintivos únicos en otra y luego creará una tabla de referencias cruzadas para relacionarlos.
Un usuario puede tener muchas insignias y una insignia puede tener muchos usuarios.
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
)
Las estadísticas que pueden afectar si un usuario gana una insignia se rastrean como parte de la administración del sitio. así que algo así como una respuesta aceptada estaría en un esquema que relaciona preguntas y respuestas. para mostrar la respuesta y el propietario de la respuesta, habría una relación con la tabla de usuarios y activadores que verificarían las condiciones de la credencial siempre que se realizara un cambio.
No estoy preguntando cómo otorgar insignias. Estoy preguntando cómo almacenar criterios dentro de la base de datos.
¿Desea almacenar la operación lógica necesaria para determinar si una insignia se gana en algún campo?
Creo que de acuerdo con el otro afiche que los criterios deben ser parte de la lógica de negocios. Esa lógica puede estar en el lado de la aplicación o dentro de un disparador. Creo que es una cuestión de estilo.
Si estuvieras realmente casado con la idea de almacenar los criterios en un campo, lo almacenaría como SQL parametrizado y lo ejecutaría dinámicamente.
Entonces este tipo de cosas estarían en su campo de criterios:
select "Badge Earned"
from all_posts
where user_id = @user_id
having count(*) > 10000
Me disculpo por ser breve.
Para implementar un sistema como este, podría crear una tabla que almacene nombres de procedimientos almacenados o consultas reales que se usarían para determinar si un usuario en particular obtuvo una insignia.
badge_criteria
badge_key int
badge_criteria varchar(max)
Puede extraer y ejecutar las consultas de insignias que el usuario no haya obtenido de su nivel medio, pero no tendría que hacer ningún código o cambios estructurales para agregar nuevas insignias en el futuro.
Me estoy acercando así: crea una tabla para almacenar todas las insignias, y haz que una columna haga referencia a una función que se ejecuta para ver si se otorga la insignia. De esta manera, la tabla sigue siendo simple y la lógica para determinar las insignias puede mantenerse en el código, donde es más adecuado.
Con este método, los requisitos de la insignia también podrían vincularse entre sí, para formar dependencias más complejas. Por ejemplo, el usuario debe recibir tres credenciales separadas y específicas con un margen de tiempo determinado para obtener esta insignia.
No crearía un incremento para la insignia de edición. Creo que debería tener un trabajo ejecutándose en segundo plano y contar () la cantidad de publicaciones editadas para miembros que aún no tienen la insignia de edición. Cuando vea que el recuento supera el rango que desea, agregue una entrada en la base de datos que indique que el usuario tiene la insignia.
Creo que es lo mismo para otras insignias. Intente limitar el número de escritura y no escriba directamente el recuento de la información de la tarjeta en la tabla de usuarios. Use una tabla que contendrá información de la insignia y vincularla a la tabla del usuario.