Как создать схему базы данных для поддержки тегов с помощью категорий?
Я пытаюсь сделать что-то вроде Database Design for Tagging, за исключением того, что каждый из моих тегов сгруппирован по категориям.
Например, скажем, у меня есть база данных об автомобилях. Скажем, мы действительно мало знаем об автомобилях, поэтому мы не можем указать колонки, которые будут иметь все транспортные средства. Поэтому мы будем "маркировать" транспортные средства информацией.
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 только в том случае, если в транспортной таре еще нет строки, так что для того же vid нет тот же cid?
Мое предположение - нет. Я думаю, что решение этой проблемы - добавить столбец cid в VehicleTags и создать новый составной первичный ключ (vid, cid). Это будет выглядеть так:
vehicleTags
int vid
int cid
int tid
Это помешало бы автомобилю иметь двух производителей, но теперь я продублировал информацию, которая имеет значение cid.
Какова должна быть моя схема?
Том заметил эту проблему в моей схеме базы данных в моем предыдущем вопросе, Как вы делаете много для многих внешних внешних таблиц?
ИЗМЕНИТЬ
Я знаю, что в примере производство действительно должно быть колонкой в таблице автомобилей, но пусть говорят, что вы не можете этого сделать. Примером может служить только пример.
Ответы
Ответ 1
Это еще одна вариация дизайна 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, вам понадобятся таблицы 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 для проверки некоторых значений ваших тегов? Вы не можете, потому что вы используете длинную строку для каждого значения тега. Является ли эта строка достаточно длинной для каждого тега, который вам понадобится в будущем? Вы не можете сказать.
- Как вы можете ограничить некоторые из ваших тегов набором допустимых значений (обычная таблица использует внешний ключ для таблицы поиска)? Это ваш пример "softtop" и "soft top". Но вы не можете установить ограничение на столбец
tag
, потому что это ограничение применимо ко всем другим значениям тегов для других категорий. Вы эффективно ограничиваете размер двигателя и цвет краски "мягким верхом".
Базы данных SQL не работают с этой моделью. Чрезвычайно сложно получить право, и его запрос становится очень сложным. Если вы продолжаете использовать SQL, вам лучше будет моделировать таблицы традиционно, с одним столбцом на атрибут. Если вам нужно иметь "подтипы", тогда определите подчиненную таблицу для каждого подтипа ( "Наследование классов" ), либо используйте Наследование отдельных таблиц. Если у вас есть неограниченное изменение атрибутов для объекта, используйте Сериализованное LOB.
Другая технология, предназначенная для таких типов жидкостных, нереляционных моделей данных, - это семантическая база данных, хранящая данные в RDF и запрашиваемая с помощью SPARQL. Одно бесплатное решение Сезам.
Ответ 2
Мне нужно было решить эту точную проблему (такую же общую область и все - автозапчасти). Я обнаружил, что лучшим решением проблемы было использование Lucene/Xapian/Ferret/Sphinx или любого индексатора, который вы предпочитаете. Гораздо лучше производительность, чем может предложить SQL.
Ответ 3
Я думаю, ваше решение состоит в том, чтобы просто добавить колонку производителя в таблицу ваших автомобилей. Это признак того, что вы знаете, что все транспортные средства будут иметь (например, автомобили самопроизвольно не появляются сами по себе), и, сделав столбец на вашем автомобильном столе, вы решаете проблему наличия одного и только одного производителя для каждого автомобиля. Этот подход применим к любым атрибутам, которые, как вы знаете, будут использоваться всеми транспортными средствами. Затем вы можете реализовать систему тегов для других атрибутов, которые не являются универсальными.
Таким образом, взяв из вашего примера, стол автомобиля будет выглядеть примерно так:
vehicle
vid
vin
make
model
Ответ 4
Одним из способов было бы немного переосмыслить вашу схему, нормализуя ключи тегов от значений:
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)
.
В качестве альтернативы существуют способы создания ограничений, отличных от простых внешних ключей: в зависимости от вашей базы данных вы можете написать настраиваемое ограничение или триггер insert/update для обеспечения уникальности тегов транспортных средств?
Ответ 5
Мне нужно было решить эту точную проблему (такую же общую область и все - автозапчасти). Я обнаружил, что лучшим решением проблемы было использование Lucene/Xapian/Ferret/Sphinx или любого индексатора, который вы предпочитаете. Гораздо лучше производительность, чем может предложить SQL.
В наши дни я почти никогда не создаю веб-приложение с поддержкой базы данных, которое не включает полнотекстовый индекс. Эта проблема и общая проблема поиска просто слишком часто возникают, чтобы опустить индексаторы из панели инструментов.