Архитектура базы данных для системы "Badge" и произвольные критерии (MySQL / PHP) - PullRequest
47 голосов
/ 26 июня 2009

Недоброкачественная-Вопрос:

Подводя итог, я немного озадачен тем, как бы я проектировал такую ​​базу данных, которая позволяла бы создавать неопределенные правила для значков, не требуя структурных изменений ранее существующих пользовательских таблиц в базе данных.

Сохранение названия значка, критериев и т. Д. Как будет выглядеть эта таблица?

  • badge_id (1)
  • badge_title (значок 10K)
  • badge_image (10k.jpg)
  • badge_criteria ([posts]> = 10000)
    ...

наматывается-Вопрос:

Я хотел бы внедрить систему бейджей в свои личные проекты, но мне нужно несколько советов о том, как лучше всего это сделать. Я читал здесь некоторые вопросы о бейдж-системах, но не вижу, чтобы архитектура баз данных привлекала большое внимание.

Значки, основанные на пользовательских баллах (Гипотетический «10k Badge»), могут показаться довольно простыми. Любое событие, которое влияет на репутацию пользователя (положительные, отрицательные, принятые ответы и т. Д.), Вызывает метод проверки новой репутации пользователей и потенциального присвоения значка.

Эта система звучит довольно прямо, но как она выглядит как база данных для администратора, который хочет создавать бесчисленное количество значков без особых усилий в будущем - некоторые из которых могут основываться на других критериях, а не просто репутация пользователя.

Репутация пользователя, скорее всего, является значением в самой записи пользователя. Но в идеале, не хотите ли вы не добавлять новые поля в пользовательскую таблицу при создании новых значков? Например, значок «Edited 100 Entries» - вы бы не создали новый столбец «records_edited» в таблице пользователей, не так ли? И затем увеличивать это после каждой отредактированной записи ...

Есть подсказки?

Архив Stackoverflow:


Примечание. Я НЕ спрашиваю, как связать значки с пользователями. Я НЕ спрашиваю, как награждать значки (это будет сделано программно)

Ответы [ 7 ]

23 голосов
/ 26 июня 2009

Учитывая, что критерии значков могут быть произвольно сложными, я не думаю, что вы можете сохранить их в таблице базы данных, разбитой на «простые» элементы данных. Попытка написать «механизм правил», который может обрабатывать произвольно сложные критерии, приведет вас на путь переписывания всех инструментов, которые есть в вашем языке программирования.

Если вы заранее знаете, что хотите, чтобы значки были ограничены только определенными полями (то есть значки основаны только на репутации, количестве правок или чем-то еще), вы можете сохранить их в простой таблице, например:

ReputationBadgeCriteria
  BadgeId
  BadgeName
  MinReputation

В качестве альтернативы, вы могли бы использовать какой-то DSL для написания своих «правил», но в конечном итоге вам также необходимо создать синтаксический анализатор для разбора правил при их чтении, а также что-то для выполнения этих правил. В зависимости от сложности вашей DSL, это может быть не тривиальной задачей. Это похоже на путь, по которому вы идете в своем вопросе с наличием столбца Criteria (предположительно, простого текста), в котором есть что-то вроде «[Reputation]> 1000» или «[Posts]> 5». Вам все еще нужно проанализировать и выполнить эти правила, и сложность написания чего-либо зависит от того, насколько сложными вы хотите, чтобы эти правила были.

Я бы рекомендовал вам прочитать эти Ежедневные WTF статьи для получения информации о том, почему этот подход приводит к боли.

19 голосов
/ 26 июня 2009

В зависимости от того, как далеко вы хотите зайти, ваша схема может быть довольно сложной. Мне кажется, что базовые элементы, которые нужно отслеживать:

Badges awarded
Points earned

Пока довольно просто, но вы хотите иметь возможность динамически создавать новые значки и новые категории очков. Награды за значки будут зависеть от начисления баллов в одной или нескольких категориях баллов, которые будут составлять определенную сумму. Таким образом, вам необходимо отслеживать отношения между категориями очков (и заработанными очками) и значками:

Point categories
Badge categories

Таким образом, ключом будет таблица ваших пользовательских баллов, которая будет ссылаться на категории баллов, которые ссылаются на значки. Пользователи зарабатывают очки в определенной категории, что будет способствовать получению очков за один или несколько значков.

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)
...

Ваш интерфейс администратора позволит кому-то создать новый значок и выбрать, какие категории баллов необходимы для получения этого значка (point_groups). Всякий раз, когда пользователь зарабатывает очки (user_points), вы обновляете таблицу user_points, а затем определяете, на какие значки эти баллы могут быть внесены (point_groups). Затем вы перекомпилируете баллы для значков, на которые повлияли заработанные баллы, и обновите таблицу user_badges с помощью point_earned. Затем проверьте поле points_earned в user_badges с обязательными точками в таблице значков.

Вы можете стать намного интереснее, назначив разные веса разным категориям очков или даже разным весам для категорий очков для определенных значков. Но эта настройка позволила бы создавать неограниченное количество значков и категорий точек и управлять ими довольно легко, не меняя структуры таблиц.

Если это совсем не то, что вы ищете, то я думаю, что я должен, по крайней мере, получить один или два голоса за много печатания.

5 голосов
/ 26 июня 2009

Вы будете отслеживать своих уникальных пользователей в одной таблице и уникальные значки в другой, а затем создавать таблицу перекрестных ссылок, чтобы связать их.

У пользователя может быть много значков, а у значка может быть много пользователей.

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
)

Статистика, которая может повлиять на то, зарабатывает ли пользователь значок, отслеживается как часть администрирования сайта. поэтому что-то вроде принятого ответа будет в схеме, которая связывает вопросы и ответы. чтобы отобразить ответ и владельца ответа, будет существовать связь с пользовательской таблицей и триггерами, которые будут проверять условия значка при каждом изменении.

Я не спрашиваю, как награждать значки. Я спрашиваю, как хранить критерии в базе данных.

То есть вы хотите сохранить логическую операцию, необходимую для определения, заработан ли значок в поле где-нибудь?

Я думаю, согласен с другим автором, что критерии должны быть частью бизнес-логики. Эта логика может быть на стороне приложения или внутри триггера. Я думаю, что это вопрос стиля.

Если бы вы действительно были женаты на идее сохранения критериев в поле, я бы сохранил его как параметризованный SQL и выполнял бы его динамически.

Так что это будет в поле ваших критериев:

select "Badge Earned"
from all_posts 
where user_id = @user_id
having count(*) > 10000
3 голосов
/ 03 августа 2011

Я подхожу к этому следующим образом: создайте таблицу для хранения всех значков и сделайте так, чтобы в одном столбце была указана функция, которая запускается, чтобы определить, был ли награжден значок. Таким образом, таблица остается простой, и логику определения значков можно сохранить в коде там, где он лучше всего подходит.

При использовании этого метода требования к значкам также могут быть связаны друг с другом для формирования более сложных зависимостей. Например, чтобы получить этот значок, пользователь должен получить три отдельных значка с определенными временными рамками.

3 голосов
/ 26 июня 2009

Прошу прощения за краткость.

Чтобы реализовать такую ​​систему, я мог бы создать таблицу, в которой будут храниться имена хранимых процедур или фактические запросы, которые будут использоваться для определения того, заработал ли конкретный пользователь значок.

badge_criteria
badge_key int
badge_criteria varchar(max)

Вы можете извлекать и выполнять запросы для значков, которые пользователь не заработал на вашем среднем уровне, но вам не придется вносить какие-либо изменения в код или структурные изменения для добавления новых значков в будущем.

3 голосов
/ 26 июня 2009

Я бы не стал создавать приращение для значка редактирования. Я думаю, что вы должны работать в фоновом режиме и считать () количество постов, отредактированных для участников, у которых еще нет значка редактирования. Когда вы видите, что число превышает желаемый диапазон, вы добавляете в базу данных запись, сообщающую, что у пользователя есть значок.

Я думаю, что то же самое для других значков. Постарайтесь ограничить количество записей и не записывайте непосредственно количество информации о значке в пользовательской таблице. Используйте таблицу, которая будет содержать информацию о значках, и свяжите ее с пользовательской таблицей.

2 голосов
/ 26 июня 2009

Это будет практически невозможно в базе данных - награждение значками должно выполняться в вашей бизнес-логике в приложении. Таким образом, у вас есть все существующие данные, которые вам нужны (изменения, посещения, репутация и т. Д.), И с ними можно обращаться по своему усмотрению.

Обновление:

Если под критериями вы подразумеваете правила, определяющие, присуждается ли значок и каким образом, то это не то, что должно храниться в базе данных. Это было бы почти невозможно проверить и поддерживать.

Если вы имеете в виду, например, сохранение «количества правок», то нет способа изменить таблицу или хранимую процедуру, чтобы включить эти данные, если вам это нужно.

...