我正在尝试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浏览器。一辆汽车只能有一个制造商。
我想设计一个数据库,以支持搜索所有梅赛德斯,或者能够列出所有制造商。
我目前的设计是这样的:
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?
我的猜测是否定的。我认为这个问题的解决方案是向vehicleTags添加一个cid列,并创建新的复合主键(vid,cid)。它看起来像是:
vehicleTags
int vid
int cid
int tid
这可以防止汽车有两个制造商,但现在我已经复制了tid在cid中的信息。
我的架构应该是什么?
Tom在上一个问题How do you do many to many table outer joins?
中的数据库架构中发现了这个问题 修改
我知道在示例中制造应该真的是车辆表中的一列,但是假设你不能这样做。这个例子只是一个例子。
答案 0 :(得分:13)
这是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
约束)? tag
列进行约束,因为该约束将适用于其他类别的所有其他标记值。您可以有效地将发动机尺寸和油漆颜色限制为“软顶”。SQL数据库与此模型不兼容。要做到正确是非常困难的,并且查询它变得非常复杂。如果继续使用SQL,则最好按常规方式对表进行建模,每个属性只有一列。如果您需要“子类型”,则为每个子类型(Class-Table Inheritance)定义一个从属表,否则使用Single-Table Inheritance。如果每个实体的属性具有无限的变化,请使用Serialized LOB。
为这些流动的非关系数据模型设计的另一种技术是语义数据库,将数据存储在RDF中并使用SPARQL进行查询。一个免费的解决方案是Sesame。
答案 1 :(得分:3)
我需要解决这个确切的问题(相同的一般领域和一切 - 汽车零件)。我发现问题的最佳解决方案是使用Lucene / Xapian / Ferret / Sphinx或您喜欢的全文索引器。比SQL提供的性能要好得多。
答案 2 :(得分:1)
您描述的不是标签,标签只是值,它们没有关联的键。 标签通常以字符串列的形式实现,值是一个分隔的值列表。
例如#1,标签字段将包含一个值,例如:
“制造_梅赛德斯,型号_SLK32 AMG,敞篷车_硬顶”
然后,用户通常能够通过一个或多个标签的存在轻松过滤条目。从数据库的角度来看,它本质上是无模式数据。标签有缺点,但它们也避免了使用 EAV 模型带来的极端复杂性。如果您确实需要一个 EAV 模型,那么也可能值得考虑一个包含 JSON 数据的属性字段。查询比较痛苦,但还是没有跨多表查询EAV那么可怕。
答案 3 :(得分:0)
我认为您的解决方案是简单地将制造商列添加到您的车辆表中。这是一个你知道所有车辆都会拥有的属性(即汽车不会自动出现),并且通过在车辆表中将其作为一列,您可以解决每辆车只有一个制造商的问题。此方法适用于您知道将由所有车辆共享的任何属性。然后,您可以为非通用的其他属性实施标记系统。
因此,从您的示例中可以看出车辆表格如下:
vehicle vid vin make model
答案 4 :(得分:0)
一种方法是稍微重新考虑您的架构,将标记键从值中标准化:
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)
上的唯一约束。
或者,有一些方法可以创建超出简单外键的约束:根据您的数据库,您是否可以编写自定义约束或插入/更新触发器来强制执行车辆标记唯一性?
答案 5 :(得分:0)
我需要解决这个确切的问题(相同的一般领域和一切 - 汽车零件)。我发现问题的最佳解决方案是使用Lucene / Xapian / Ferret / Sphinx或您喜欢的全文索引器。比SQL提供的性能要好得多。
现在,我几乎从未构建过一个不涉及全文索引器的数据库支持的Web应用程序。这个问题和搜索的一般问题经常出现,无法从工具箱中省略索引器。