Jak zaprojektować schemat bazy danych obsługujący tagowanie kategoriami?
Próbuję stworzyć coś w stylu bazy danych do tagowania , z tym, że każdy z moich tagów jest pogrupowany w kategorie.
Na przykład, załóżmy, że mam bazę danych o pojazdach. Powiedzmy, że właściwie nie wiemy zbyt wiele o pojazdach, więc nie możemy określić kolumn, które będą miały wszystkie pojazdy. Dlatego będziemy "tagować" Pojazdy informacjami.1. manufacture: Mercedes
model: SLK32 AMG
convertible: hardtop
2. manufacture: Ford
model: GT90
production phase: prototype
3. manufacture: Mazda
model: MX-5
convertible: softtop
Teraz, Jak widać wszystkie samochody są oznaczone ich produkcji i modelu, ale inne kategorie nie wszystkie mecz. Należy pamiętać, że samochód może mieć tylko jedną kategorię. IE. Samochód może mieć tylko jednego producenta.
Chcę zaprojektować bazę danych obsługującą wyszukiwanie wszystkich Mercedesów lub listę wszystkich producentów.
Mój obecny projekt jest mniej więcej taki:
vehicles
int vid
String vin
vehicleTags
int vid
int tid
tags
int tid
String tag
int cid
categories
int cid
String category
Mam wszystkie klucze główne i zagraniczne na miejscu, z tym, że nie mogę poradzić sobie ze sprawą, w której każdy samochód może mieć tylko jednego producenta. Czy Mogę?
Czy Mogę dodać ograniczenie klucza obcego do złożonego klucz główny w samochodach? IE. Czy Mogę dodać ograniczenie takie, że złożony klucz podstawowy (vid, tid) może być dodany tylko do vehicleTags tylko wtedy, gdy nie ma już wiersza w vehicleTags takiego, że dla tego samego vid, nie ma już tid w tym samym cid?
Zgaduję, że nie. Myślę, że rozwiązaniem tego problemu jest dodanie kolumny cid do vehicleTags i wykonanie nowego złożonego klucza podstawowego (vid, cid). Wyglądałoby to tak:vehicleTags
int vid
int cid
int tid
To uniemożliwiłoby samochodowi posiadanie dwóch producentów, ale teraz skopiowałem informację, że tid jest w cid.
Jaki powinien być mój schemat?
Tom zauważył ten problem w moim schemacie bazy danych w moim poprzednim pytaniu, Jak zrobić wiele do wielu zewnętrznych złączeń tabeli?
EDIT
Wiem, że w przykładzie produkcja powinna być naprawdę kolumną w tabeli pojazdów, ale powiedzmy, że nie możesz tego zrobić. Przykład jest tylko przykładem.
5 answers
Jest to kolejna odmiana projektuEncja-atrybut-wartość .
Bardziej rozpoznawalna tabela EAV wygląda następująco:
CREATE TABLE vehicleEAV (
vid INTEGER,
attr_name VARCHAR(20),
attr_value VARCHAR(100),
PRIMARY KEY (vid, attr_name),
FOREIGN KEY (vid) REFERENCES vehicles (vid)
);
Niektórzy zmuszają attr_name
do odwoływania się do tabeli z predefiniowanymi nazwami atrybutów, aby ograniczyć chaos.
To, co zrobiłeś, to po prostu rozłożenie tabeli EAV na trzy tabele, ale bez poprawy kolejności metadanych:
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"
);
Jeśli zamierzasz używać projektu EAV, potrzebujesz tylko vehicleTags
i categories
stoły.
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)
);
Ale pamiętaj, że mieszasz dane z metadanymi. Tracisz możliwość zastosowania pewnych ograniczeń do modelu danych.
- Jak sprawić, by jedna z kategorii była obowiązkowa (konwencjonalna kolumna używa ograniczenia
NOT NULL
)? - Jak można używać typów danych SQL do walidacji niektórych wartości znaczników? Nie możesz, ponieważ używasz długiego ciągu dla każdej wartości znacznika. Czy ten ciąg jest wystarczająco długi dla każdego znacznika, którego potrzebujesz w przyszłość? Nie wiadomo.
- jak można ograniczyć niektóre znaczniki do zestawu dozwolonych wartości(konwencjonalna tabela używa klucza obcego do tabeli wyszukiwania)? To jest twój przykład "softtop" vs. "soft top". Ale nie można utworzyć ograniczenia w kolumnie
tag
, ponieważ ograniczenie to ma zastosowanie do wszystkich innych wartości znaczników dla innych kategorii. Skutecznie ograniczyłbyś rozmiar silnika i kolor lakieru do "miękkiego topu".
Bazy danych SQL nie działają dobrze z tym modelem. Jest to niezwykle trudne, aby uzyskać prawo, a zapytanie staje się bardzo złożone. Jeśli nadal używasz SQL, lepiej będzie modelować tabele konwencjonalnie, z jedną kolumną na atrybut. Jeśli musisz mieć "podtypy", zdefiniuj podrzędną tabelę dla podtypu (dziedziczenie klas), lub użyj dziedziczenie pojedynczych tabel. Jeśli masz nieograniczoną zmienność atrybutów dla jednostki, użyj Serialized LOB.
Inny technologia, która jest zaprojektowana dla tego rodzaju płynnych, nie relacyjnych modeli danych, to semantyczna baza danych, przechowująca dane w RDF i zapytana o SPARQL. Jednym wolnym rozwiązaniem jest Sezam .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-17 00:41:04
Musiałem rozwiązać ten dokładny problem (ta sama ogólna Domena i wszystko-Części Samochodowe). Odkryłem, że najlepszym rozwiązaniem problemu było użycie Lucene/Xapian/Ferret / Sphinx lub dowolnego pełnotekstowego indeksera, który wolisz. Znacznie lepszą wydajność niż to, co może zaoferować SQL.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-27 11:43:04
Myślę, że Twoim rozwiązaniem jest po prostu dodanie kolumny producenta do tabeli pojazdów. Jest to atrybut, który wiesz, że wszystkie pojazdy będą miały (tzn. samochody nie pojawiają się spontanicznie same) i tworząc kolumnę w tabeli pojazdów rozwiązujesz problem posiadania jednego i tylko jednego producenta dla każdego pojazdu. Takie podejście będzie miało zastosowanie do wszystkich atrybutów, o których wiecie, że będą współdzielone przez wszystkie pojazdy. Następnie można zaimplementować system tagowania dla innych atrybutów, które nie są uniwersalne.
Więc biorąc z twojego przykładu tabelę pojazdów będzie coś w stylu:
vehicle vid vin make model
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-16 23:31:59
Jednym ze sposobów byłoby lekkie przemyślenie schematu, normalizacja kluczy tagów z dala od wartości:
vehicles
int vid
string vin
tags
int tid
int cid
string key
categories
int cid
string category
vehicleTags
int vid
int tid
string value
Teraz wszystko czego potrzebujesz to unikalne ograniczenie vehicleTags(vid, tid)
.
Alternatywnie istnieją sposoby tworzenia ograniczeń poza prostymi kluczami obcymi: w zależności od bazy danych, czy możesz napisać własne ograniczenie lub wyzwalacz wstawiania/aktualizacji, aby wymusić unikalność znacznika pojazdu?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-16 23:51:52
Musiałem rozwiązać ten dokładny problem (ta sama ogólna Domena i wszystko-Części Samochodowe). Odkryłem, że najlepszym rozwiązaniem problemu było użycie Lucene/Xapian/Ferret / Sphinx lub dowolnego pełnotekstowego indeksera, który wolisz. Znacznie lepszą wydajność niż to, co może zaoferować SQL.
W dzisiejszych czasach prawie nigdy nie kończę na budowaniu aplikacji internetowej opartej na bazie danych, która nie wymaga indeksatora pełnotekstowego. Ten problem i ogólny problem wyszukiwania po prostu pojawiają się zbyt często, aby pominąć indeksujących z twojego skrzynka narzędziowa.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-24 16:46:39