如何设计一个标签系统?

在很多系统中都有打标签的需求,比如图片、书籍、电影、博客、评论等,并且打标签的对象往往是海量数据。这就给系统的设计提出了挑战:

  • 要求可以根据标签进行分组、过滤、协同查询(比如标签的并集、交集、差集等等)
  • 要求查询的效率很高
  • 要求整个标签系统的扩展性很强

如何设计?

在Tags: Database schemas[1]一文中已经列举出了三种设计方式,并对三种方式做了一些性能测试[2]

  1. “MySQLicious” solution
  2. “Scuttle” solution
  3. “Toxi” solution
    在这里不做赘述。

Toxi设计

数据库表结构如下,这种表可以随便修改成你想要的任意对象和扩展。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
CREATE TABLE objects (
id bigint NOT NULL AUTO_INCREMENT,
name varchar(128) NOT NULL,
url varchar(128) DEFAULT NULL,
description text DEFAULT NULL,
is_delete tinyint DEFAULT 0,
create_user varchar(64) DEFAULT NULL,
create_date datetime DEFAULT CURRENT_TIMESTAMP,
update_user varchar(64) DEFAULT NULL,
update_date datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
)
ENGINE = INNODB,
CHARACTER SET utf8,
COLLATE utf8_general_ci,
COMMENT = '对象表';

CREATE TABLE tags (
id bigint NOT NULL AUTO_INCREMENT,
tag varchar(256) NOT NULL,
is_delete tinyint DEFAULT 0,
create_user varchar(64) DEFAULT NULL,
create_date datetime DEFAULT CURRENT_TIMESTAMP,
update_user varchar(64) DEFAULT NULL,
update_date datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
)
ENGINE = INNODB,
CHARACTER SET utf8,
COLLATE utf8_general_ci,
COMMENT = '标签元数据表';

CREATE TABLE object_tag_relation (
id bigint NOT NULL AUTO_INCREMENT,
object_id bigint NOT NULL,
tag_id bigint NOT NULL,
is_delete tinyint DEFAULT 0,
create_user varchar(64) DEFAULT NULL,
create_date datetime DEFAULT CURRENT_TIMESTAMP,
update_user varchar(64) DEFAULT NULL,
update_date datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX tag_id(tag_id)
)
ENGINE = INNODB,
CHARACTER SET utf8,
COLLATE utf8_general_ci,
COMMENT = '对象标签关系表';