Как разработать схему базы данных для поддержки тегов с категориями? - PullRequest
15 голосов
/ 17 декабря 2008

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

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

1. manufacture: Mercedes
   model: SLK32 AMG
   convertible: hardtop

2. manufacture: Ford
   model: GT90
   production phase: prototype

3. manufacture: Mazda
   model: MX-5
   convertible: softtop

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

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

Мой текущий дизайн выглядит примерно так:

vehicles
  int vid
  String vin

vehicleTags
  int vid
  int tid

tags
  int tid
  String tag
  int cid

categories
  int cid
  String category

У меня есть все необходимые первичные и внешние ключи, за исключением того, что я не могу справиться со случаем, когда у каждого автомобиля может быть только один производитель. Или я могу?

Можно ли добавить ограничение внешнего ключа в составной первичный ключ в vehicleTags? IE. Могу ли я добавить ограничение, чтобы составной первичный ключ (vid, tid) можно было добавлять только в vehicleTags только в том случае, если в vehicleTags еще нет строки, такой, что для того же vid еще нет tid тот же cid?

Я думаю, нет. Я думаю, что решение этой проблемы - добавить столбец cid в vehicleTags и создать новый составной первичный ключ (vid, cid). Это будет выглядеть так:

vehicleTags
  int vid
  int cid
  int tid

Это предотвратит появление у двух производителей автомобиля, но теперь я продублировал информацию о том, что находится в cid.

Какой должна быть моя схема?

Том заметил эту проблему в моей схеме базы данных в моем предыдущем вопросе, Как вы делаете много-много внешних табличных объединений?

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

Ответы [ 5 ]

13 голосов
/ 17 декабря 2008

Это еще один вариант дизайна Entity-Attribute-Value .

Более узнаваемая таблица EAV выглядит следующим образом:

CREATE TABLE vehicleEAV (
  vid        INTEGER,
  attr_name  VARCHAR(20),
  attr_value VARCHAR(100),
  PRIMARY KEY (vid, attr_name),
  FOREIGN KEY (vid) REFERENCES vehicles (vid)
);

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

То, что вы сделали, просто распространили таблицу EAV на три таблицы, но без улучшения порядка ваших метаданных:

CREATE TABLE vehicleTag (
  vid         INTEGER,
  cid         INTEGER,
  tid         INTEGER,
  PRIMARY KEY (vid, cid),
  FOREIGN KEY (vid) REFERENCES vehicles(vid),
  FOREIGN KEY (cid) REFERENCES categories(cid),
  FOREIGN KEY (tid) REFERENCES tags(tid)
);

CREATE TABLE categories (
  cid        INTEGER PRIMARY KEY,
  category   VARCHAR(20) -- "attr_name"
);

CREATE TABLE tags (
  tid        INTEGER PRIMARY KEY,
  tag        VARCHAR(100) -- "attr_value"
);

Если вы собираетесь использовать EAV design, вам нужны только таблицы vehicleTags и categories.

CREATE TABLE vehicleTag (
  vid         INTEGER,
  cid         INTEGER,     -- reference to "attr_name" lookup table
  tag         VARCHAR(100, -- "attr_value"
  PRIMARY KEY (vid, cid),
  FOREIGN KEY (vid) REFERENCES vehicles(vid),
  FOREIGN KEY (cid) REFERENCES categories(cid)
);

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

  • Как сделать одну из категорий обязательной (в обычном столбце используется ограничение NOT NULL)?
  • Как вы можете использовать типы данных SQL для проверки некоторых значений ваших тегов? Вы не можете, потому что вы используете длинную строку для каждого значения тега. Достаточно ли длинна эта строка для каждого тега, который вам понадобится в будущем? Вы не можете сказать.
  • Как вы можете ограничить некоторые из ваших тегов набором допустимых значений (обычная таблица использует внешний ключ для таблицы поиска)? Это ваш пример "мягкой вершины" против "мягкой вершины". Но вы не можете наложить ограничение на столбец tag, поскольку это ограничение будет применяться ко всем другим значениям тегов для других категорий. Вы также эффективно ограничите размер двигателя и цвет краски на «мягкий верх».

Базы данных SQL плохо работают с этой моделью. Это очень трудно получить право, и запрос становится очень сложным. Если вы продолжите использовать SQL, вам будет лучше смоделировать таблицы традиционным способом, используя один столбец для каждого атрибута. Если вам нужно иметь «подтипы», тогда определите подчиненную таблицу для каждого подтипа ( Наследование таблиц классов ) или используйте Наследование для одной таблицы . Если у вас есть неограниченное разнообразие атрибутов для каждой сущности, используйте Serialized LOB .

Еще одна технология, разработанная для этих типов текучих нереляционных моделей данных, - это семантическая база данных, хранящая данные в RDF и запрашиваемая с SPARQL . Одно бесплатное решение - Кунжут .

3 голосов
/ 27 октября 2012

Мне нужно было решить именно эту проблему (та же общая область и все - автозапчасти). Я обнаружил, что лучшим решением проблемы было использование Lucene / Xapian / Ferret / Sphinx или любого другого полнотекстового индексатора, который вы предпочитаете. Гораздо лучшая производительность, чем у SQL.

0 голосов
/ 24 апреля 2009

Мне нужно было решить именно эту проблему (та же общая область и все - автозапчасти). Я обнаружил, что лучшим решением проблемы было использование Lucene / Xapian / Ferret / Sphinx или любого другого полнотекстового индексатора, который вы предпочитаете. Гораздо лучшая производительность, чем у SQL.

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

0 голосов
/ 17 декабря 2008

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

vehicles
  int vid
  string vin

tags
  int tid
  int cid
  string key

categories
  int cid
  string category

vehicleTags
  int vid
  int tid
  string value

Теперь все, что вам нужно, это уникальное ограничение на vehicleTags(vid, tid).

В качестве альтернативы, существуют способы создания ограничений помимо простых внешних ключей: в зависимости от вашей базы данных, можете ли вы написать пользовательское ограничение или триггер вставки / обновления для обеспечения уникальности тега транспортного средства?

0 голосов
/ 17 декабря 2008

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

Итак, по вашему примеру, таблица транспортного средства будет выглядеть примерно так:

vehicle
  vid
  vin
  make
  model
...