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.

Author: Community, 2008-12-17

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 .

 13
Author: Bill Karwin,
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.

 3
Author: ben 10,
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
 0
Author: Carlos Nunes-Ueno,
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?

 0
Author: Dan Vinton,
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.

 0
Author: Bob Aman,
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