- 蘇格團隊
- 作者:YaoLang
角色:產品汪小T,程式設計師小C
小T:小C,有活幹了。我們想做個線上題庫系統,老師可以搜尋題目來備課。
小C看著簡易的需求稿,心想,我一分鐘幾百萬上下,竟然找我做這麼簡單的需求。建個題目表不就完事了。
小C:題目資料從哪裡來,包含什麼屬性?
小T:我們第一期題目資料是從A公司那裡買過來的,題目包含正文,選項,答案,題型,難度。
小C:嗯,也就是我要建一張question表,包括這五個屬性。那題型和難度有哪些呢?
小T:題型有五種,單選,多選,判斷,填空,解答。難度有3種,簡單,一般,困難。使用者可以根據題型或者難度來篩選。 小C拿著筆畫了一下:OK,表設計出來了
t_question表
欄位 | 屬性 | 描述 |
---|---|---|
uid | char(32) | 唯一標示 |
body | TEXT | 正文 |
options | JSON | 題目選項 |
answer | TEXT | 答案 |
type | int(11) | 題目型別,1單選、2多選、3判斷、4填空、5解答 |
difficult | int(11) | 題目難度,1簡單、2一般、3困難 |
小C:搜尋根據body, options模糊匹配,然後篩選讓前端傳入type = 1或者difficult = 3 進行題型和難度的篩選
小T:哇,果然靠譜,那我們上線吧。
小T:小C,我們的題庫系統發到市場上有很多使用者反饋說題目量不太夠,最近我們找到了B公司合作,希望能把B公司的題庫也整合到我們的系統,資料的結構和A公司的很相似,你看下要弄多久。
小C心想,敢情這產品汪不生產題目,只是題目的搬運工啊。
小C:導一下資料就完事了。把介面文件發我對接一下就好了。
小T:好,待會文件發你。
拿到B公司的題目介面,題目整體結構不變,可是題型和難度的分類都比A公司多一點。題型有單選題,多選題,分析題,一般分解題,APP分解題。題型有簡單,一般,困難,極難。
小C心想:我去,我要以哪個公司的題目分類作為標準。於是找到了小T
小C:資料如果做整合的話,可不可以將B公司的分析題,一般分解題,APP分解題變成我們的解答題,極難不要,都變成困難。因為現在沒有定義一個標準,我不太好整合資料。
小T:那好吧,先按你說的去做。
自那以後,小T又找了兩家公司合作,讓小C整合資料。並且小T認為其中一家公司的方法(配方法,消元法,排除法)和能力(推理能力,分析能力,計算能力)資料也是很重要的維度,希望能做補充。
小C崩潰了,我一分鐘幾百萬上下,竟然找我來導資料。每次還要去看資料的分類值應該怎麼做整合。還經常要加欄位。現在因為要接入那兩家公司的題庫資料,要將表修改成
t_question表
欄位 | 屬性 | 描述 |
---|---|---|
uid | char(32) | 唯一標示 |
body | TEXT | 正文 |
options | JSON | 題目選項 |
answer | TEXT | 答案 |
type | int(11) | 題目型別,1單選、2多選、3判斷、4填空、5解答 |
difficult | int(11) | 題目難度,1簡單、2一般、3困難 |
ability | int(11) | 能力屬性,1推理能力,2分析能力 。。。。 |
method | int(11) | 方法屬性,1配方法,2消元法,3排除法。。。 |
- 現在題庫有300W資料,未來還會不斷地增加,如果頻繁改表的話,線上會直接鎖表
- 如果每個分類我還要去看哪些值應該對映為我們定義的哪些值,後面肯定會吃不消的,因為我們沒有一套統一的標準。。。
小C意識到自己跳到了一個大坑中,原來這東西並沒有一開始想的這麼簡單。
經過仔細的思考,小C得出結論:
- 行業內根本就沒有一套標準,必須針對變化點做擴充套件
- 不同的公司題目的維度資料不一樣(如某公司多了能力與方法兩個維度)
- 不同的公司同一維度的資料值不一樣(如B公司的題型和A公司不一樣)
專門針對標籤建立表
- 一個標籤分類下有多個標籤值
- 一道習題有多個標籤屬性
t_tag表
欄位 | 屬性 | 描述 |
---|---|---|
uid | char(32) | 唯一標示 |
tag_name | varchar(64) | 標籤分類 |
tag_key | varchar(64) | 標籤key |
t_tag_value表
欄位 | 屬性 | 描述 |
---|---|---|
uid | char(32) | 唯一標示 |
tag_id | char(32) | 標籤分類id |
value_name | varchar(64) | 標籤值名 |
value_code | varchar(64) | 標籤值編碼 |
t_question_tag表
欄位 | 屬性 | 描述 |
---|---|---|
id | char(32) | 唯一標示 |
tag_value_id | char(32) | 標籤值id |
question_id | char(32) | 題目id |
當一次查詢時,先將查詢到的題目id到t_question_tag表中查出tag_value_id集合。 標籤進行GROUP BY tag_id聚合後得到以下json
[{
分類名:難度,
分類key: difficult,
值列表:[{
值名:簡單,
值編碼: 1
},{
值名:一般,
值編碼: 2
},{
值名:困難,
值編碼: 3
}]}
]
複製程式碼
通過返回標籤聚合,可以在前端展示
難度:簡單,一般,困難
題型:選擇題,判斷題,作文,完形填空。。。
方法:配方法,消元法。。。。
複製程式碼
篩選時,傳入標籤key (difficult),標籤value (1)得到tag_value_id 然後可以篩選出跟標籤繫結的題目。
擴充總結:
- 當某張資料表未來可能資料量會很龐大的,不能因為需求變更頻繁地增加表的欄位,考慮增加中間表的方式來進行擴充
- 一般實體資料資訊不確定的時候,也可以考慮使用NOSQL檢索,如設計成以下的文件,就可以利用NOSQL的陣列查詢功能檢索標籤對應的實體。
{
"uid":"",
"description":"",
"tag_ids":["標籤1","標籤2","標籤3"]
}
複製程式碼
- 該設計也能應用於電商中,如商品的分類篩選
顏色:黃色,藍色,綠色
尺碼:M,L,XL,XXL
風格:休閒,商務
複製程式碼
- 標籤只適合用於有限個數的分類,如檔案大小,價格這些不固定的屬性是不能做成標籤的。
- 標籤欄位是不會有排序需求的,如按照某個分類進行order by。因為標籤定位是有限分類,排序沒有任何的意義,標籤只能用來做篩選。如果一定要排序,建議另外計算標籤和其他屬性計算出一個分數字段。
問題點:
- 為什麼標籤值要分成標籤uid和標籤code呢
標籤code屬於多變的,可以自定義,如讓簡單定義為1,困難定義為2。如果直接讓題目繫結1,很可能和其他的分類衝突。如題型的1為單選題。
- 為什麼要前端傳入key和value不直接傳標籤uid
會有一些場景需要業務自定義標籤,如省市區,使用者使用時更想用101100這種全國通用的地區編碼來做標籤篩選。
做到這裡,小C稍微鬆了一口氣,之後你來一個公司的資料,如果有新的分類,就可以加標籤類別再加標籤值。如果同一分類下來新的值,先看一下分類的中文名是不是對應的上,對應不上新建標籤,然後讓產品去做標籤的整合或者就當成兩個不同的標籤來算。再也不怕整合資料了。