📊 中华诗词知识库 · 第二章:数据清洗与入库

Knowledge Base of Chinese Poetry (KBCP) — Chapter 2: Data Clean

1. 为什么"清洗"比"收集"还重要

第一章完成了原始数据的抓取,4600多位诗人、62400多首诗词,打开JSON文件会发现:

有的诗句里夹杂着注释,有的上下阕分段而中间没有分段(换行);有的律诗是两句一行,有的是一句一行;有的开头有多个空行,有的正文开头有多个【】记录信息的文本行

这是原始数据的真实面貌。如果直接入库,后面的检索、向量化、RAG全都会出问题。

所以数据应用的核心任务是把"能用"变成"好用"。

当前开发阶段状态:

阶段 状态 描述
1 🟢 已完成 数据收集
2 🔵 进行中 数据清洗 + 诗人整理 + 元数据补全 + 入库 + 网页展示
3 ⚪ 待开始 数据 Schema 设计
4 ⚪ 待开始 数据加工流程
5 ⚪ 待开始 知识增强方案
6 ⚪ 待开始 RAG 功能

本文对应的是第2阶段的全部内容。


2. 原始数据的"脏"在哪里

在清洗之前,先看看我们面对的是什么。

对比一下

【年代】:先秦
【作者】:屈原
【 题 】:九歌·东君
【内容】:

暾将出兮东方,照吾槛兮扶桑;
抚余马兮安驱,夜皎皎兮既明;
驾龙辀[1]兮乘雷,载云旗兮委[2][3];
长太息兮将上,心低徊兮顾怀;
羌声色兮娱人,观者儋[4]兮忘归;
【年代】:清
【作者】:王士祯
【 题 】:秦淮杂诗
【内容】:
青溪水木最清华,王谢乌衣六代夸。
不奈更耐江总宅,寒烟已失段侯家。

另一首


【年代】:清
【作者】:王士祯
【 题 】:悼亡诗
【内容】:

陌上莺啼细草薰,
鱼鳞风皱水成纹。
江南红豆相思苦,
岁岁花开一忆君。

看起来似乎还可以,但实际数据里有问题,计算机看到的,与人看到的内容是有不同的。

问题类型 举例 影响
换行混乱 两句诗连在1行 分句不统一,影响检索精度
夹带注释 驾龙辀[1]兮乘雷,载云旗兮委[2]蛇[3] 内容不纯,向量检索偏移

这些问题不解决,后面的RAG流程从第二步"关键词检索"开始就会降低质量。


3. 清洗:一行代码一个坑

3.1 换行与分句处理

原始数据中,content字段的存储方式非常不统一,当前的处理策略是:

原始 content 
  → 统一转为字符串
  → 去除所有换行符(\n, \r, \r\n)
  → 按句号/问号/感叹号切分句子
  → 过滤空句和纯注释句
  → 存入数组,每句为一个元素

这样做的好处是:后续做向量检索时,每一句都可以作为独立的语义单元,而不是整首诗糊在一起。

3.2 注释剥离

很多古籍版本会在诗句中夹带校勘注释,这里将注释都进行了剥离,放在了discription字段中。

3.3 标题标准化

诗词的标题,是一个比较令人头疼的问题。这是由于历史演化造成的,比如诗经中“羔裘”为名的有三首,绝句一般也没有题名,宋词元曲更是以词牌名曲牌名,因此为了统一,title为标题,如羔裘\水调歌头, content_title为次级名称,这样就基本解决了标题重复问题。

3.4 去重

当有多个来源时,去重是非常重要的。

同一首诗可能从《全唐诗》《唐诗三百首》《古诗文网》等多个来源抓取。去重策略:

标题 + 作者 + 内容前20字 完全一致 → 判定为重复,保留来源最权威的一条。


4. 诗人信息整理

4.1 为什么要单独整理诗人

原始数据里,诗人信息只有一个名字,比如 "杜甫"。但我们后续要做的事情需要更多:

其中 author_id 是唯一标识,格式为 朝代首字母 + 序号,比如:

朝代 首字母 示例
F F0001(李白)、F0282(杜甫)
S S0001(苏轼)、S0147(李清照)
Y Y0001(关汉卿)
Q Q0001(纳兰性德)

这样做的好处是:即使有重名诗人(比如宋代有3个"张xx"),也能通过author_id精确区分。


5. 元数据补全:能填的都填上

元数据(Metadata)就是"关于数据的数据"。对诗词来说,最重要的元数据字段包括:

字段 原始状态 清洗后状态 说明
title 混乱 ✅ 标准化 去除作者前缀、序号
author 部分缺失 ✅ 补全 从文件名和路径提取
author_id ✅ 新增 F0001格式唯一ID
dynasty 大部分有 ✅ 补全缺失 空值按内容推断
dynasty_id ✅ 新增 单字母朝代码
format ✅ 新增 五言/七言/律诗/绝句/词牌
content 混乱 ✅ 分句数组 每句独立元素
discription ⚠️ 暂空 后续补充注释解读

6. 从JSON到SQLite:为什么要用数据库

JSON文件虽然直观,但有几个致命问题:

  1. 查询困难: json在内存中可以转换成字典容器dict,但是不方便查询
  2. 不支持关联:诗人信息和诗词信息分在两套JSON里
  3. 不支持索引:没有索引,每次检索都是全扫描

SQLite——轻量、无需服务、单文件、Python原生支持。

数据库Schema设计(示意)

-- 诗人表
CREATE TABLE poets (
    author_id   TEXT PRIMARY KEY,
    name        TEXT NOT NULL,
    dynasty     TEXT NOT NULL,
    dynasty_id  TEXT NOT NULL,
    birth       TEXT,
    death       TEXT,
    bio         TEXT,
    tags        TEXT,
    works_count INTEGER DEFAULT 0
);

-- 诗词表
CREATE TABLE poems (
    poem_id     INTEGER PRIMARY KEY AUTOINCREMENT,
    title       TEXT NOT NULL,
    author_id   TEXT NOT NULL,
    dynasty     TEXT NOT NULL,
    dynasty_id  TEXT NOT NULL,
    format      TEXT,
    content     TEXT,           -- JSON数组存分句
    subtitle    TEXT,
    source      TEXT,
    discription TEXT DEFAULT '',
    FOREIGN KEY (author_id) REFERENCES poets(author_id)
);

-- 索引
CREATE INDEX idx_poems_author ON poems(author_id);
CREATE INDEX idx_poems_dynasty ON poems(dynasty);
CREATE INDEX idx_poems_title ON poems(title);
CREATE INDEX idx_poems_format ON poems(format);

6.3 导入结果

指标 数值
诗人表记录数 4,611
诗词表记录数 62,450

7. 用Workbuddy做个网页

Workbuddy 快速搭了一个网页前端,功能包括:

功能 说明
🔍 诗人搜索 输入名字,显示诗人信息 + 作品列表
📜 诗词浏览 按朝代/作者/体裁筛选
📄 诗句查看 点击诗词,显示分句内容
➕ 新增/编辑 直接在网页上录入新诗词

说实话,网页只是"能用"

Workbuddy生成的网页本质上是静态页面 + 简单的前后端交互,适合快速原型。但我自己也清楚:

真正要维护这个知识库,还是用代码直接操作JSON或数据库更方便。

原因很简单:

方式 优点 缺点
Workbuddy做的网页 直观、不用写代码 批量导入不方便、版本控制困难
Python脚本+SQLite 自动化、可版本化、可CI 需要写代码
直接改JSON 最简单 容易出错、没有约束

所以目前的定位是:网页用于日常浏览和单条修改,批量更新还是靠脚本。

后续计划把网页改成 Flask/FastAPI 后端 + 简单前端,这样就能既有界面,又支持API调用了——也可以为后面的RAG阶段做准备。


8. 本章成果总结

任务 状态 成果
原始数据清洗 ✅ 完成 62,450首诗,格式统一,注释剥离
诗人信息整理 ✅ 完成 4,611位诗人
JSON → SQLite ✅ 完成 诗词表,诗人表,朝代表
网页展示 ✅ 完成 Workbuddy原型

下一章(第3章),我们将进入 数据Schema设计 阶段,正式定义诗歌数据的结构化字段,并开始构建自动化的数据加工流水线——分词、向量化、知识图谱构建,为RAG打好地基。


📌 项目进度:第2阶段进行中(1/5子任务完成)
📂 代码与数据:https://github.com/liang1057/Knowledge-Base-of-Chinese-Poetry
📥 JSON数据下载:https://download.csdn.net/download/sdust_dx/92826598(免积分)

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐