这个博客写到现在有 43 篇文章,每篇在 frontmatter 里带几个标签。把所有标签拉出来数一数,一共 123 个,其中 87 个只用过一次。用得最多的是“AI”(8 篇)和“源码分析”(7 篇),后面跟着“Git”“区块链”“成本测算”这些。
我想把这些文章里的知识点整理成游戏里那种知识树:读完一篇,树上亮起几格;亮了的格子旁边,又露出几格可以接着点的。第一个想到的现成办法是图书馆的分类法,几百万本书都分得下,几十篇文章应该不在话下。
可是图书馆的分类,真的就是那种能点亮的树吗?如果不是,差在哪里?除了图书馆的办法,还有没有更合适的?本文就从把文章放进图书馆分类开始,一步步往下看。
一、图书馆分类法
它解决的是什么问题
图书馆分类法要解决的是一件很实际的事:书架上每本书放在哪。国内的图书馆用《中国图书馆分类法》(中图法),分 22 个大类,每类一个字母,往下用数字细分,比如 T 是工业技术,TP 是其中的自动化技术、计算机技术,TP3 是计算技术、计算机技术1。国外多用杜威十进分类法,十个大类,三位数字加小数逐级往下,005 是计算机编程与软件,005.8 是数据安全2。
每本书拿到一个分类号,加上作者号就成了书脊上的索书号。书只能放在一个书架上,所以一本书只有一个主分类号,这是图书馆分类最根本的约束。
现象:放进博客文章以后
我们拿几篇文章试着归类。下表的类号是我对照类目表归的,只到二三级,不是查馆藏得来。
| 文章 | 中图法 | 杜威 | 文章里的知识点 |
|---|---|---|---|
| TOTP 与 Google 身份验证器 | TP309 计算机安全,或 TN918 保密通信 | 005.8 | HMAC、HOTP、TOTP、数字证书、钓鱼 |
| Git 服务器是怎么工作的 | TP311 软件 | 005.1 | Git 对象模型、传输协议、GitLab、Gerrit、walgit |
| Hyperliquid 为什么快 | F83 金融,或 TP311 软件 | 332.4 或 005 | 区块链、共识算法、订单簿 |
| 两个对不上的 HRV 数字 | R33 人体生理学 | 612.1 | RR 间期、SDNN、RMSSD、自主神经 |
| 注意力有弹性吗 | B84 心理学,或 R33 | 153.7 | 注意资源、HRV、反应时变异 |
| 谁定方向,谁来干活 | C93 管理学,或 B84 | 658 或 158 | 形式权威与实际权威、失败预设 |
黄色的格子都是“两处都说得通”,只能挑一个。
归完一遍,能看到三个问题。
一篇文章常常跨类。 TOTP 那篇讲的是认证,放在计算机安全下面说得通,放在密码通信下面也说得通。图书馆有一套规则帮馆员挑一个,比如按“主要论述的方面”、按“使用者最可能去哪找”,但挑完之后,另一边的读者就找不到它了。中图法和杜威都允许加“参见”,可那只是一行注释,不是结构。
粒度停在文章这一级。 分类号给的是整篇文章的位置,而我们要点亮的是文章里的知识点。TOTP 那一篇里就有 HMAC、HOTP、TOTP、数字证书好几个,它们分别属于不同的小类,一个分类号装不下。
树枝的含义是“属于”,不是“先学”。 TP311 下面挂着 TP311.1、TP311.5,意思是“后者是前者的一部分”。点亮了 TP311,能说明什么?说明不了我接下来能学什么。
前两个问题,后面会看到别的分类体系能补上。第三个问题更根本:游戏里那棵树,树枝的意思到底是什么?
二、游戏里的知识树
现象:点亮一格,旁边才露出几格
玩过《文明》或者《流放之路》的都熟悉这种界面。《文明》的科技树里,一项科技通常要先研究完一两项前置科技才能开始;《流放之路》的天赋盘上,只能点和已点亮格子相邻的格子。树上的位置只是摆放,真正起作用的是格子之间的那条线:这条线说的是“先有 A,才能有 B”。
这和分类树里的线不是一回事。分类树里,一个节点只有一个父类,线的意思是“B 是 A 的一种”;科技树里,一个节点可以有好几个前置,也可以是好几条线的共同前置,线的意思是“B 要求 A”。数学上,前者是一棵树,后者是一张有向无环图。
分析:同一个知识点在两种结构里
拿“哈希函数”这个知识点看最清楚。Git 用它给每个对象起名字,TOTP 用它算 HMAC,区块链用它把区块串起来,三篇文章都要先懂它。
左边的分类树里,哈希函数只能实打实挂在一个分支下,另两处只剩“参见”。右边的依赖图里,它在最上面,三条线都从它出发。点亮它,对三个方向都有意义;这正是游戏里那种“点了这格,好几处同时解锁”的感觉。
所以主结构里必须有一条“先学 A 才能学 B”的边,而图书馆分类法里没有这条边。 那么,那些比图书馆更细、更新的分类体系,有没有这条边?
三、学科本体与叙词表
学科本体:一篇标多个概念
学术界的分类体系,最早遇到的就是“一篇跨好几类”的问题,因为论文比书更专。ACM 的计算机分类体系 ACM CCS 2012 做了两个改变:一是允许一个概念有多个上位,比如同一个概念既挂在“安全”下,也挂在“网络”下;二是一篇论文可以选好几个概念,每个标上权重3。在 ACM 的 LaTeX 模板里,作者这样写:
\ccsdesc[500]{Security and privacy~Authentication}\ccsdesc[300]{Security and privacy~Hash functions and message authentication codes}500、300、100 分别是高、中、低三档相关度4。数学界的 MSC2020 也类似:分三级,63 个两位大类、529 个三位类、6022 个五位类,每篇论文标一个主分类,再加若干次分类5。
这样一来,图 1 里“两处都说得通”的问题解决了:TOTP 那篇可以同时标认证和哈希两个概念,一高一中。五位一级的类目也细到了知识点的粒度。
但这两套体系都只管自己的学科:ACM CCS 里没有 HRV,MSC 里没有 Git。而且它们的边还是“属于”,没有“先学”。
叙词表:存储格式和同义词
把这类概念体系写成机器能读的格式,W3C 有一个标准叫 SKOS,ACM CCS 就是用它发布的。SKOS 里每个概念有一个首选名、若干别名,概念之间有三种关系:更宽(broader)、更窄(narrower)、相关(related)6。
SKOS 有两处正好用得上。别名解决了同义词:“TOTP”“动态口令”“基于时间的一次性密码”是同一个节点,读者搜哪个都能落到这里。多重上位也允许一个概念挂在几个上位下面。
可是三种关系里,related 是对称的:写了 TOTP 相关 HOTP,就等于也写了 HOTP 相关 TOTP,看不出谁先谁后。broader 是“属于”,也不是“先学”。要表达“先学 HOTP 才能学 TOTP”,只能像图 3 下面那样,自己加一个 ex:requires 属性。SKOS 适合做存储格式,不适合当主结构。
学科本体和叙词表都还是在同一个方向上把分类做细。还有一种思路换了方向:与其给一篇文章挑一个位置,不如承认它同时站在好几个维度上。
四、刻面分类
现象:标签里混着几种东西
回头看开头那 123 个标签,里面其实混着几种性质不同的词。“Git”“Prometheus”“HRV”说的是文章讲的对象;“源码分析”“成本测算”“回测”说的是文章的做法;“入门”说的是读者的起点。它们被放在同一个平铺的列表里,所以才会长到 123 个,而且大部分只用一次。
原因与解决:把维度分开
印度图书馆学家阮冈纳赞在 1933 年提出冒号分类法,第一次把这件事系统化:一本书不再放进预先排好的格子,而是在几个基本范畴上各取一个值,再组配起来。他的五个范畴是本体、物质、动作、空间、时间,简称 PMEST7。后来的 UDC 也允许用冒号把两个类号组配成一个8。
把博客标签按这个思路分开,就是下表。
| 文章 | 对象 | 做法 | 中图法大类 |
|---|---|---|---|
| Git 服务器是怎么工作的 | Git、GitLab、Gerrit | 源码分析 | TP |
| E2B 和 Docker 是什么关系 | E2B、Docker | 源码分析 | TP |
| 租云 GPU 转卖大模型 API | GPU、大模型 API | 成本测算 | F |
| 几十美元的小盒子跑大模型 | 边缘设备、内存带宽 | 成本测算 | TP |
| 去中心化推理 | llama.cpp RPC | 成本测算 | TP |
| 纳指 ETF 的时差利差 | 513100、溢价 | 回测 | F |
按“做法 = 成本测算”筛,会同时拿到 TP 和 F 两个大类里的文章。
刻面让“一篇跨几类”不再是问题:它本来就该在几条轴上各有一个值。想看所有成本测算类的文章,按做法筛一下就行,不必管它们在中图法里分属 TP 和 F。
但刻面之间是正交的,没有先后。“对象 = Git”和“做法 = 源码分析”是两个并列的维度,谁也不是谁的前置。刻面是很好的筛选器,可它同样不产生“点亮这格才能点那格”。
到这里,几种分类方式都试过了,它们回答的都是“这个东西在哪、属于什么”。要找“先学什么”这条边,得去看研究学习本身的理论。
五、前置依赖:知识空间理论
它在回答什么问题
1985 年,Jean-Paul Doignon 和 Jean-Claude Falmagne 提出了知识空间理论9。他们关心的问题是:怎样用尽量少的测验题,弄清一个学生到底会什么?
他们的出发点很简单。把一个领域拆成一组知识项(比如一道道代数题),一个人会的那些项组成一个集合,叫他的知识状态。关键在于,并不是任意一个集合都可能是某人的状态:一个会解二次方程、却不会解一次方程的学生,几乎不存在。项和项之间有前置关系,只有“前置都在、自己才在”的集合才是合法的状态。
在这个框架里,有两个概念正好对上游戏里的点亮10:
- 外缘(outer fringe):还没掌握、但前置都已掌握的项。加上任何一个,仍然是合法状态。这就是“下一步能点亮的格子”。
- 内缘(inner fringe):已掌握、而且没有别的已掌握项依赖它的项。去掉它,状态仍然合法。这大致是“最近点亮的末梢”。
商业化的自适应学习系统 ALEKS 就建立在这个理论上:先用一轮测验估出学生的知识状态,再从外缘里挑下一道题。
用博客文章试一试
我从十几篇文章里抽了 20 个知识点,分到系统、安全、Git、区块链、健康五个区域,再给每个点写上前置。假设一个读者读完了 tmux 那篇、HRV 那篇的前一半、Git 服务器那篇的第一节、TOTP 那篇的 HMAC 部分,点亮的就是图 5 里实心的七格。
外缘不用人去数,写一个小脚本就能算。依赖关系写成 YAML,每个节点一行:
# region 只管画在地图哪一块,requires 才决定能不能点亮- {id: 哈希函数, region: 基础, requires: [], from: [git-server-from-clone, totp-google-authenticator]}- {id: HMAC, region: 安全, requires: [哈希函数], from: [totp-google-authenticator]}- {id: HOTP, region: 安全, requires: [HMAC], from: [totp-google-authenticator]}- {id: Git对象模型, region: Git, requires: [哈希函数], from: [git-server-from-clone]}- {id: 区块链, region: 区块链, requires: [哈希函数], from: [hyperliquid-speed]}# ……共 20 个节点脚本做三件事:检查依赖里没有环(有环就没法点亮),检查已点亮的集合是否合法,再算出外缘和内缘。
import sys, yamlnodes = {n["id"]: n for n in yaml.safe_load(open(sys.argv[1]))}lit = set(sys.argv[2].split(","))
# 依赖必须是一张无环图:拓扑排序走不完说明有环seen, order = set(), []def visit(i, path=()): if i in path: sys.exit(f"环:{' → '.join(path + (i,))}") if i in seen: return for r in nodes[i]["requires"]: visit(r, path + (i,)) seen.add(i); order.append(i)for i in nodes: visit(i)
bad = [i for i in lit if not set(nodes[i]["requires"]) <= lit]print("点亮不合法(前置没亮):", bad or "无")fringe = [i for i in order if i not in lit and set(nodes[i]["requires"]) <= lit]print(f"已点亮 {len(lit)}/{len(nodes)}")print("下一步能点亮(外缘):", "、".join(fringe))inner = [i for i in order if i in lit and not any(i in nodes[j]["requires"] for j in lit)]print("最近点亮的末梢(内缘):", "、".join(inner))运行结果:
$ python3 fringe.py tree.yaml 进程与信号,tmux,哈希函数,HMAC,Git对象模型,RR间期,SDNN与RMSSD点亮不合法(前置没亮): 无已点亮 7/20下一步能点亮(外缘): 容器隔离、HOTP、Git传输协议、区块链、HRV最近点亮的末梢(内缘): tmux、HMAC、Git对象模型、SDNN与RMSSD这五格外缘里,四格指向一篇读了一半的文章(HOTP 在 TOTP 那篇,Git 传输协议在 Git 服务器那篇,HRV 在 HRV 那篇,容器隔离在 E2B 那篇),区块链则指向一篇还没读过的 Hyperliquid。这就是“下一篇读什么”的推荐。
知识空间理论给了点亮一个精确的含义。不过它的知识项是一道道能判对错的题,而一个知识点“亮了”又该怎么判?读过一遍算不算?
六、点亮的程度
现象:读过和会用不是一回事
读完 TOTP 那篇,大概能说出“六位数是用时间算出来的”;但要自己写代码算出和手机上一样的六位数,又是另一回事;再往上,是能说清 TOTP 和短信验证码、通行密钥各自防住了什么。三个人都“读过”这一篇,掌握的程度差得很远。游戏里也常这样处理:同一个天赋可以点一级、二级、三级。
解决:用 Bloom 分类给节点分级
教育学里描述“掌握到什么程度”的经典框架是 Bloom 的认知目标分类。2001 年的修订版把它分成六级:记忆、理解、应用、分析、评价、创造11。六级对一个个人知识树来说太细,合并成三级更好用。
| 等级 | Bloom 层级 | 在 TOTP 上意味着 | 怎么检验 |
|---|---|---|---|
| 一级 | 记忆、理解 | 说得出 TOTP 把时间切成 30 秒一段,用段号代替 HOTP 的计数器 | 解释为什么手机开着飞行模式也能出码 |
| 二级 | 应用 | 拿一个密钥和当前时间,自己算出那六位数 | 写二十行代码,结果和身份验证器对上 |
| 三级 | 分析、评价、创造 | 说得清 TOTP、短信验证码、通行密钥各自防住了什么 | 给一个登录场景选方案,并说出理由 |
每一级都配一个能判对错的检验,这就回到了知识空间理论“知识项是题目”的要求。
分级以后,前置关系也可以写得更细:学 TOTP 要求 HOTP 至少一级,而要把 TOTP 点到二级,可能就要求 HMAC 也到二级。
Bloom 分类本身不能当主结构:它对每个节点都是同样的几级,是一条纵向的刻度,不是一张图的骨架。
七、各自的位置
一个节点长什么样
到这里,前面几种方式各自擅长的地方已经清楚了。它们不是互相替代,而是可以同时出现在同一个节点上,各管一件事。
几个字段里只有 requires 决定树的形状。改掉 region,节点只是换个地方画;改掉 requires,能点亮的顺序就变了。
对照:各方案回答什么问题
| 方案 | 回答的问题 | 边的含义 | 在知识树里 |
|---|---|---|---|
| 图书馆分类(中图法、杜威、UDC) | 放在哪 | 属于(单一父类) | 地图分区 |
| 学科本体(ACM CCS、MSC2020) | 属于哪些主题 | 属于(可多个) | 某个分区要细分时参考 |
| 叙词表(SKOS) | 叫什么,和谁有关 | 更宽、更窄、相关 | 存储格式、同义词 |
| 刻面分类 | 从哪几个角度看 | 无(正交的轴) | 筛选 |
| 知识空间理论 | 先学什么 | 要求(有向、无环) | 主结构 |
| Bloom 分类 | 掌握到什么程度 | 无(每个节点的刻度) | 节点等级 |
分区用哪一套
剩下一个实际问题:地图分区用什么?可以自己起名字,但我更建议直接借中图法的大类或二级类,像图 7 里那样在 region 后面记下对应的类号。原因有两个:分区只影响布局,用一套现成的、大家都熟的划分,不必为“这一块叫什么”反复纠结;以后想和别人的知识树或者图书馆的书目对接,类号就是现成的接口。分区不必细,博客现在的文章,十个以内的区域就够了。
八、回到图书馆分类法
回到开头那个念头:图书馆分类法能不能当知识树的主结构?
能用,但只能用在一个地方:地图的分区。它把世界上的知识分成了大家都认得的几块,这对“这一格画在哪”很有用。可它的树枝是“属于”,一个知识点只能挂一处,它不知道哈希函数要先于 HMAC,也不知道 HMAC 要先于 HOTP。游戏里那种点亮的感觉,全来自“先有 A,才有 B”这条边,而这条边只能从知识本身的依赖里来,需要我们一条条写出来。
写依赖边比给文章挑分类号费事得多。一个可行的起点是在每篇文章的 frontmatter 里多写两行:这篇教了哪些知识点(teaches),读之前最好会哪些(requires)。文章就像游戏里的任务,完成一个任务,点亮一组节点。
小结
- 图书馆分类法放得下博客文章吗?放得下,但一篇常跨两个大类,分类号只到文章,进不到知识点,树枝的意思是“属于”而不是“先学”。
- 游戏里的知识树是什么结构?是一张前置依赖的有向无环图,一个节点可以有多个前置和多个后继。“哈希函数”就同时是 Git、TOTP、区块链三条线的起点。
- 学科本体和叙词表补上了什么?ACM CCS 和 MSC 允许一篇标多个概念,粒度也更细;SKOS 给了存储格式和同义词。但它们的边仍然是“属于”和对称的“相关”。
- 刻面分类补上了什么?把“讲什么”和“怎么做”拆成正交的轴,筛选能横穿大类,但轴之间没有先后。
- “点亮”的精确含义是什么?知识空间理论的外缘:前置都已掌握、下一步能学的项。写成 YAML 加二十几行脚本就能算出来。
- 点亮的深浅怎么分?用 Bloom 分类合并成三级,每级配一个能判对错的检验。
- 主结构用什么?用知识点之间的前置依赖图;图书馆分类退为地图分区,刻面做筛选,Bloom 做等级,SKOS 做存储。
参考资料
Footnotes
-
中国图书馆分类法(第五版)clc.nlc.cn ↗五个基本部类、22 个大类,类号由字母和数字组成,如 TP 自动化技术、计算机技术http://clc.nlc.cn/ ↩
-
Dewey Decimal Classificationoclc.org ↗十个大类,三位数字加小数逐级细分,如 005.8 数据安全、612.1 血液与循环生理https://www.oclc.org/en/dewey.html ↩
-
The 2012 ACM Computing Classification Systemacm.org ↗多重上位的概念体系,以 SKOS 格式发布;论文作者为每篇论文选多个概念https://www.acm.org/publications/class-2012 ↩
-
acmart: Class for typesetting publications of ACMctan.org ↗
\ccsdesc[500]{...}给概念标权重,500 / 300 / 100 对应 High / Medium / Lowhttps://ctan.org/pkg/acmart ↩ -
Mathematics Subject Classification 2020 (MSC2020)msc2020.org ↗三级:63 个两位类、529 个三位类、6022 个五位类,如 11G15;论文标一个主分类加若干次分类https://msc2020.org/ ↩
-
SKOS Simple Knowledge Organization System Referencew3.org ↗
skos:broader/skos:narrower/skos:related、skos:prefLabel/skos:altLabel;skos:related是对称关系,skos:broader本身不传递,另有skos:broaderTransitivehttps://www.w3.org/TR/skos-reference/ ↩ -
Colon Classificationen.wikipedia.org ↗第一个系统的刻面分类法;五个基本范畴 PMEST:本体(Personality)、物质(Matter)、动作(Energy)、空间(Space)、时间(Time)https://en.wikipedia.org/wiki/Colon_classification ↩
-
Universal Decimal Classificationudcc.org ↗在杜威基础上发展而来,可以用冒号
:把两个类号组配成一个https://udcc.org/ ↩ -
Spaces for the assessment of knowledgedoi.org ↗知识状态是一个人能解出的题目的集合;知识空间是可能的知识状态组成的族,对并运算封闭https://doi.org/10.1016/S0020-7373(85)80031-6 ↩
-
Knowledge Spaces and Learning Spacesarxiv.org ↗外缘(outer fringe):再加上就仍是合法状态的项,即下一步准备好学的;内缘(inner fringe):去掉后仍合法的项;学习空间里一个状态由它的两个缘唯一确定。ALEKS 据此推荐下一步https://arxiv.org/abs/1511.06757 ↩
-
A Revision of Bloom's Taxonomy: An Overviewdoi.org ↗修订版六级:记忆、理解、应用、分析、评价、创造;完整版见 Anderson & Krathwohl (2001) A Taxonomy for Learning, Teaching, and Assessinghttps://doi.org/10.1207/s15430421tip4104_2 ↩