業務邏輯是這樣的:
用戶可以給自己貼標簽,以供他人搜索。比如我給自己貼上“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集合,然后做交集操作即可。
解決方案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比較好,這樣很容易得出用戶的標簽 我不太會組織語言 不知道描述的清楚否
其他參考: