轉載自mohang
最近在做dmp,負責設計一套标簽管理系統。在對現有标簽進行整理的過程中,整理出了這套東西。
對于标簽(tag),很難列出一個公認的定義,指明這個概念的種差與屬概念。是以為了把握這個概念,就需要采取定義另一種辦法:分類與枚舉。
我們要解決的第一個問題是,有哪些類型的标簽,如何對标簽進行分類。首先不妨對“如何分類”本身進行分類,我們可以從“形式”與“内容”上分辨考察标簽的分類。
标簽的形式是标簽分類最主要的依據。
首先,我們可以列出一些常見或者不常見的的“标簽”樣例:
通過觀察我們可以發現一些東西
通常意義上的标簽是單值标簽,或稱原子标簽。其取值是一個獨立的值。如<code>女</code>,<code>23</code>,<code>90.6</code>。
一部分标簽是多值标簽,多個原子标簽整個作為一個整體形成一個标簽,例如微網誌上人們用來描述自己的關鍵詞清單:例如:<code>['90後','處女座','麼麼哒']</code>。
還有一部分标簽,為每個原子标簽額外添加了一個權值參數。這也是很常見的需求,例如用來表示使用者對邏輯上相關聯的一組取值的頻次頻率值,預測機率等。
最後,為多值标簽的每個原子标簽添加關聯權值就得到了權值标簽,而單個的原子标簽帶有權值也是常見的事情,例如給出一個預測年齡及其置信度。如果這種單kv結構也用權值标簽來表示,就會顯得累贅與奇怪。是以适合單獨作為一類。
從标簽的組織形式上看,标簽可以分為四類:<code>單值标簽</code>,<code>單權标簽</code>,<code>多值标簽</code>,<code>多權标簽</code>。
于是,我們就獲得了兩個基本正交的次元:<code>是否為多值标簽</code>, <code>是否帶有權值</code>。
這四種标簽結構類型,除特殊的<code>單權标簽</code>後,恰好與json的三種primitive type:<code>atomic, array, object</code>相對應。
我們知道,計算機的實體實作本質上隻提供了<code>整形</code>與<code>浮點</code>兩種原子資料類型。将指針,單字元,布爾,浮點數都歸入數值類型,将極其常用的字元數組看做字元串類型,那麼邏輯上其實我們隻有兩種原子資料類型:即<code>數值類型(numeric)</code>與<code>字元串(string)</code>。
我們當然希望所有原子标簽的類型隻有<code>數值</code>與<code>字元串</code>兩種簡單的分類。但出于一些現實的限制(比如就是有離散标簽與連續值标簽的區分,比如odps就區分bigint和double),我們還是會将<code>數值</code>細分為<code>整形</code>與<code>浮點</code>,是以,用于原子标簽的類型就變為三種:<code>整型、浮點,字元串</code>。
對于權值标簽,除了原子标簽的類型,其權值也應當有一個合适的類型。強制其類型為<code>數值</code>是一個合理且合适的限制,可以通過強制其實體類型為double輕易實作。
标簽的<code>原子類型次元</code>和标簽的<code>結構類型次元</code>并不完全正交,這是出于一些技術上的限制。例如python中的dict,<code>數值類型</code>是可以作為key的,然而json規範中,隻有<code>字元串</code>可以作為object的key。<code>整形</code>可以通過序列化安全地轉換為字元串間接地作為key。但<code>浮點</code>的不精密則會帶來諸多麻煩,是以<code>多值标簽</code>的原子類型次元不可以取值<code>浮點</code>。
從标簽的原子類型上看:标簽可以分為<code>整形</code>,<code>浮點</code>,<code>字元串</code>。
在2.1.2中,我們對标簽的原子類型進行了分類,但出于生産實踐的考慮,我們必須考慮另一種非常常見的情況,即<code>枚舉标簽</code>。枚舉标簽通常用一個整形表示标簽取值,同時提供一個從整型值到字元串的字典,用于解釋這個整型值。
例如:
再比如:
是以我們也可以發現,其實布爾類型就是一種特殊的枚舉标簽,有0:'false',1:'true'兩個選項(先不考慮nullable)。完全可以自然地納入枚舉标簽的體系中。
是以,對于整形原子類型的解釋方法,又可以成為一個标簽分類的次元。即<code>是否為枚舉标簽</code>,由于這個次元和2.1.3中原子标簽類型的次元高度相關(當原子标簽類型為整形時本次元才有效),是以這兩個次元應當合二為一。
faq:
枚舉與整形的差別在哪裡,即什麼時候用整形什麼時候用枚舉?
很簡單,取值可以窮盡且數目合理的時候用枚舉。例如,城市代碼就是一個很合适的枚舉标簽。但一個人的頭發數目雖然肯定是一個整數,但就不适合作為枚舉标簽了。
字元标簽與枚舉标簽的差別?
枚舉标簽與其他标簽的差別在哪裡?
枚舉标簽的特點就是需要維護一張标簽字典表,用于維護從枚舉entry的id到item的映射關系。
枚舉标簽可以具有層次關系。例如"城市枚舉标簽"就可以有上層标簽:"省份枚舉标簽"。
多個枚舉标簽的字典可以放在同一張表中。
為什麼不采用字元串作為枚舉的id?
即 : 原子标簽的取值類型與解釋方式。
該次元的取值有4種:<code>枚舉</code>,<code>整形</code>,<code>浮點</code>,<code>字元串</code>
由上述可知,從标簽的形式上,我們獲得了兩個大的,基本正交的分類次元:
組織形式:{ <code>單值标簽</code>,<code>單權标簽</code>,<code>多值标簽</code>,<code>多權标簽</code> }
原子類型:{ <code>枚舉标簽</code> , <code>整形标簽</code>, <code>文本标簽</code>, <code>浮點标簽</code> , }
除了<code>浮點多權标簽</code>不是合理的組合之外,其他共計<code>4 x 4 -1 = 15</code>種組合。
即,标簽從形式上可以分為15個類型。恰好可以用4個bit表示。
因為最常見的标簽都是單值标簽,是以将标簽結構類型的位域放在标簽原子類型的位域之前是合理的設計。
結構
标記
說明
單值标簽
0x00
取值為單一原子類型相應值
單權标簽
0x01
取值為單一原子類型及其權值,可以以分隔符值,數組或字典等形式實作。
多值标簽
0x10
取值為同種原子類型組成的清單
權值标簽
取值為同種原子類型組成的字典,key隻能為string或string(bigint)
枚舉标簽
實際為bigint類型,預設類型,需要對照類型字典解讀
整形标簽
整形數值原子标簽
文本标簽
字元串原子标簽
浮點标簽
0x11
浮點數數值原子标簽
類型id
英文代号
名稱
結構id
結構名
原子id
原子名稱
存儲
atom-enum
單值枚舉
單值
枚舉
int
1
atom-int
單值整形
整形
2
atom-text
單值文本
文本
text
3
atom-float
單值浮點
浮點
float
4
paire-enum
單權枚舉
單權
json
5
paire-int
單權整形
6
paire-text
單權文本
7
paire-float
單權浮點
8
list-enum
多值枚舉
多值
9
list-int
多值整形
10
list-text
多值文本
11
list-float
多值浮點
12
dict-enum
多權枚舉
多權
13
dict-int
多權整形
14
dict-text
多權文本
這裡需要提一下的是,标簽形式分類與其存儲類型的映射關系:
存儲上,單值标簽采用<code>bigint</code>,<code>double</code>,<code>string</code>存儲。單權标簽采用長度固定為2的數組<code>[value,weight]</code>存儲,多值标簽采用數組存儲<code>[value1,value2,...]</code>,多權标簽采用對象<code>{v1:w1}</code>存儲,且當原子類型為整形與枚舉時,其中的<code>value</code>應當存儲其字元串序列化形式以符合json對key類型的要求。
從結果上看,所有單值标簽都直接以其對應類型進行序列化存儲。其餘所有标簽都采用json序列化的方式存儲。
下面給出每種标簽的樣例:
id
title
storage
sample
性别标簽:1 {"0":"男", "1" :"女"}
年齡:23
喜愛小說:"百年孤獨"
體重:60.13
預測性别:[1, 0.99]
預測年齡:[23, 0.99]
電視劇-喜愛度:["星際迷航", 9.8]
預測體重:[60.13, 0.78]
鬧鐘設定:[1, 2, 3, 4, 5]
三圍:[100, 100, 100]
喜愛電視劇:["星際迷航", "絕命毒師", "是的,大臣!"]
月度消費記錄:[6379.13, 6378.24, 6356.12]
鬧鐘設定機率分布:{"1":0.98, "2" :0.75, "3" :0.75, "4" :0.5, "5" :0.3}
幸運數字 - 喜愛度:{"7":0.32, "5" :0.63}
網站浏覽偏好标簽:{"問答類":0.55, "交友類" :0.75}
标簽按内容性質分類的方式,相比形式分類顯得十分多樣。可以純粹的從标簽的取值特性上分類(nullable,權值是否歸一化,etc...),也可以從标簽的來源場景(移動端,pc端),标簽的所有權(私有,内部,群組,公司),标簽的規模,标簽的依賴,标簽的row id類型(oneid, acookie, mobile, umid, etc...),或者前端展示時采用的層級類目等等很多元度上進行分類。
形式分類會決定标簽的展現形式,但内容分類并沒有這種影響。是以按内容分類的結果更适合作為描述字段而非放入類型字段。換句話說,與其把内容分類稱為分類,倒不如稱之為枚舉屬性更為合适。
但是對于内容分類,我們仍然需要進一步的考察。按标簽内容分類可以進一步細分為: 按标簽固有屬性分類,和按人為用途分類。屬于标簽固有屬性的,适合放入标簽中繼資料表中,作為一個字段。而屬于人為用途劃分的,因為需求可能會頻繁地發生變化,是以需要提供一種在不改變資料庫schema的前提下支援動态增添分類體系的機制來實作這一需求。本文建議采用類似"wordpress"的taxonomy概念,為人為劃分建構一個動态分類體系。
為了提供适應這種變化需求的靈活性,可以考慮建構一張分類體系表(tag_taxonomy)、一張分類項表(tag_term)、一張分類表(tag_classification)。動态的實作分類體系的增添。如果需要實作帶有層次結構的分類體系,隻需要在分類項中,為每個分類條目維護一個父條目的指針即可。
舉個例子,如果我們需要動态添加一個"公私"分類。首先,需要在分類體系表裡注冊這種分類體系:"标簽公私分類體系"。然後在分類項表中,添加"公有","私有",兩個分類體系的具體取值條目。最後,在标簽分類表中,将标簽與分類具體取值相關聯。
對于标簽的内容分類:
标簽的固有性質适合作為标簽表的字段出現
标簽的人為分類适合使用動态分類體系通過外鍵引入。
schema的設計如下:

歡迎加入“數加·maxcompute購買咨詢”釘釘群(群号: 11782920)進行咨詢,群二維碼如下: