前言
文章通俗明了,故摘抄于此!
正文
角色:产品汪小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稍微松了一口气,之后你来一个公司的数据,如果有新的分类,就可以加标签类别再加标签值。如果同一分类下来新的值,先看一下分类的中文名是不是对应的上,对应不上新建标签,然后让产品去做标签的整合或者就当成两个不同的标签来算。再也不怕整合数据了。
————————————————
版权声明:本文为CSDN博主「雪糕的爸爸」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/YaoLang1995/article/details/89173978