「用户标签」在数据库设计时应该如何存储?

业务逻辑是这样的:
用户可以给自己贴标签,以供他人搜索。比如我给自己贴上“90后 程序员”的标签,那么别人就能通过“90后”或者“程序员”搜到我。
用户最多可以给自己贴10个标签。标签可以随时更新。

方案一:在User表里设置一个tags字段,里面存的是“90后,程序员”这样的字符串,用逗号分隔不同标签。缺点:不便于搜索,建立索引的话会很低效,因为“90后,程序员”和“程序员,90后”被认为是不同的。

方案二:在User表里设置10个tag_n字段(n=1,2,3...10),每个字段存一个标签。缺点:不利于Update。比如我现在把我的标签改为“程序员,90后,帅哥”,那么我要逐个检查“程序员”、“90后”和“帅哥”是否已存在,不存在才能添加。
不知道有什么好方法。

我在问问题的时候想到可以先给标签排序在存到数据库里。

注1:存tag的id而不是存tag的内容这一点已经采用了,我在问题里直接用tag内容是为了表述方面。
注2:我使用的是关系型数据库。

解决方案1:多对多

这应该是一个多对多的问题。
对于小型系统,我的设计方案通常是这样

user表
=====================
userId userName
=====================
1 test
2 test2
...

tag表
=====================
tagId tagName
=====================
1 tag
2 tag2
...

relation表
=====================
relationId userId tagId
=====================
1 1 1
2 1 2
...

insert update 之类的应该都很简单,不是问题
查询可能有点麻烦,需要用到联合查询

语句一般是这样
SELECT userId, userName FROM user u
INNER JOIN relation r ON u.userId=r.userId
WHERE r.tagId = 1

这样就查出了所有tagId为1的用户。

索引对这个方案可能效果不是很明显,数据量小的时候,索引的提升不明显,数据量大的时候,索引对联合查询起不到什么提升作用。

其实你的方案1不失为一种可行方案,特别是数据量惊人的情况,你可以采用方案1配合NoSQL的方式。

解决方案2:倒排索引

我想简单说下我的观点。
对于标签这个问题,无论是用户的标签,还是内容的标签,这其实都属于搜索的范畴。
我认为都应该采用倒排表(inverted index)的数据结构来存储。

对于标签的数据结构,无论存储在文件中还是数据库中,格式为:
label1 -> [ id1, id2, id3, .... idN]
label2 -> [ id8, id9, id10, .... idM]
这样存储的好处是,当用户搜索标签时,可以迅速得到所有id集合,然后做交集操作即可。

同时,每个用户user表,可以设一个tags字段,里面存所有label。当想查看某个用户的标签时,也可以迅速获取。

解决方案3:NoSQL

数据量小,用mongodb,建个带索引的array列,里面放标签。

数据量大,用elasticsearch,标签就是关键词,按搜索引擎的套路走。

标签变更生效有一点延迟,不过从业务角度看,这应该不是问题。

Hbase

解决方案4:Bitmap

其实这个问题 nosql 当然能很好的解决,要是用mysql 也不是不行,数据存储方式要斟酌一下,建立一个标签表tag 字段 id(自增) ,users(申请bit空间 字符串方式) 然后用bitmap 进行映射,用户id1 对应第一位 用户2对应第二位 以此类推, 通过计算很容易得出1M大小空间可以存838w用户的映射关系,这样 得出的 结果是 id 1 =》 对应users “10001000....” 代表标签id1的用户有userid 1 和5 ,做标签统计时候 只要对标签求交集并集很轻易何以得出各种统计,同时位运算效率极快。同时用户表加一个字段,用同样方式映射一下 userid 的 标签映射关系,当然要是便于搜索的话,直接存标签id比较好,这样很容易得出用户的标签 我不太会组织语言 不知道描述的清楚否

 

其他参考:

[实战]短视频打标签技术解析与应用

解读电商搜索——如何让你买得又快又好

 

posted @ 2019-10-15 11:14  沙漏哟  阅读(9553)  评论(0编辑  收藏  举报