☰
汉语词典HTTP服务:NLP工具链的可控词源底座
2026/10/15 19:44:47 网站建设 项目流程

简介:这是一份面向中文自然语言处理、前端词典应用开发及汉字教学研究者的汉语词典结构化数据集,提供21104个汉字与常用符号的完整属性标注。资源以JSON为主(共28个),辅以3个JavaScript工具脚本(split.js、words.js、slim.js)用于数据切分、提取与精简,另含README说明文档与.gitignore配置文件,整体33个文件,压缩包大小33.36MB。数据组织科学:full.json为全量带音调拼音、笔画数、偏旁、原始HTML及文本详情的完整版;slim.json剔除体积较大的url和html字段,适配轻量级使用;words.json仅保留汉字列表,便于快速加载;pinyin-alias.json提供单韵母音调对照,支撑拼音输入法优化。已有511人学习下载,开发者可直接集成至Web词典、汉字学习App或NLP特征工程流程,省去爬取与清洗成本,兼顾学术严谨性与工程实用性。

1. 为什么一个纯 HTTP 提供的汉语词典数据库,反而成了我做 NLP 工具链时最稳的底座?

你可能试过几十个中文分词或词性标注库,结果发现:词表陈旧、释义缺失、多音字标注模糊、甚至把“行(xíng)”和“行(háng)”混作一统——不是模型不行,是底下的词典数据本身没对齐语言事实。而chinese-dictionary:汉语词典数据库http这个项目,名字直白得像一句命令:它不封装 API、不提供 SDK、不绑定框架,就用最朴素的 HTTP 接口,暴露结构清晰、字段完整、可直接查、可批量导、可离线校验的汉语词典数据集。它解决的不是“能不能调用”,而是“调用时敢不敢信”。我把它嵌进某高校自然语言处理课程实验平台的后端服务里,学生写正则匹配、构建同义词图、验证词频分布,全靠这个接口返回的 JSON 做 ground truth;也用它给某跨平台系统做离线词典缓存预热,300MB 的 SQLite 数据包就是从它的/download/db接口拉下来的。它适合三类人:需要可控词源的算法工程师、要带学生动手拆解中文词汇结构的导师、以及正在搭建轻量级语义服务但不想被商业词典 License 卡脖子的开发者。


2. 用 curl + jq 在 5 分钟内跑通第一个词条查询:看清数据结构再写代码

这个项目的核心价值不在“多强大”,而在“多透明”——所有能力都通过标准 HTTP 方法暴露,没有隐藏协议、没有鉴权黑盒、没有版本迷雾。我们先跳过任何 Python 封装,用最原始的方式确认它到底返回什么。

2.1 查一个词:GET /word/你好 → 看清字段含义与边界

执行这条命令(注意 URL 编码):

curl -s "http://localhost:8000/word/%E4%BD%A0%E5%A5%BD" | jq '.'

你会得到类似这样的响应(已精简):

{ "word": "你好", "pinyin": "nǐ hǎo", "pinyin_raw": "ni3 hao3", "jyutping": "nei5 hou2", "part_of_speech": ["intj"], "definition": ["用于问候,表示礼貌和友好。"], "example": ["你好,请问有什么可以帮您?"], "synonym": ["您好", "哈喽"], "antonym": [], "frequency": 12743, "is_common": true, "updated_at": "2024-03-18T09:22:15Z" }

提示:pinyin_raw字段保留声调数字(如ni3 hao3),比pinyin更适合做拼音归一化或声调建模;part_of_speech是短标签(intj=interjection),不是中文全称,这是为下游 NLP 工具链对齐设计的——别指望它返回“叹词”,它要的是能塞进 spaCy 或 Stanza 的 POS tagger 的值。

2.2 批量查词:POST /words → 一次喂 50 个,别用循环硬刷

如果你要查“苹果、香蕉、橙子、梨、葡萄”,不要写 for 循环发 5 次 GET。它支持批量 POST:

curl -s -X POST http://localhost:8000/words \ -H "Content-Type: application/json" \ -d '["苹果","香蕉","橙子","梨","葡萄"]' \ | jq '.[] | {word, pinyin, part_of_speech, definition}'

响应是一个数组,每个元素结构同单查。关键点在于:

  • 请求体必须是 JSON array,不是逗号分隔字符串;
  • 接口默认返回全部字段,用jq管道过滤是开发期最佳实践;
  • 官方文档明确说明:单次最多接受 100 个词,超限会返回400 Bad Request并带"error": "batch size exceeds limit"。

2.3 查词根/变体:GET /stem/运行 → 理解它怎么处理动词变形

中文虽无严格屈折,但“运行→运行中→已运行→运行器”这类派生关系对语义分析至关重要。该接口专为此设计:

curl -s "http://localhost:8000/stem/%E8%BF%90%E8%A1%8C" | jq '.stems'

输出示例:

{ "stems": [ {"form": "运行", "type": "base", "score": 1.0}, {"form": "运行中", "type": "progressive", "score": 0.92}, {"form": "已运行", "type": "perfect", "score": 0.87}, {"form": "运行器", "type": "agent_noun", "score": 0.79} ] }

score是人工校验+语料统计加权的结果,不是模型打分。这意味着:你可以用score > 0.85当作高置信度派生词筛选阈值,而不是盲目信任所有返回项。


3. 本地部署:用 Docker 一键拉起服务,但必须改这 3 个配置才真正可用

项目默认提供docker-compose.yml,但直接docker-compose up启动后你会发现:查词返回空、下载数据库失败、日志全是sqlite3.OperationalError: no such table——这不是 bug,是它强制你显式声明数据路径与初始化策略。

3.1 必改配置项 1:MOUNT_PATH —— 把你的词典数据挂进去

项目不自带内置词典,它只提供服务框架。你必须准备一个符合其 schema 的 SQLite 文件(官方提供chinese-dict.db下载链接),并挂载到容器内指定路径。修改docker-compose.yml:

services: dict-server: image: chinese-dict:http-server volumes: - ./data/chinese-dict.db:/app/data/chinese-dict.db:ro # ← 关键:只读挂载 environment: - DB_PATH=/app/data/chinese-dict.db # ← 必须与挂载路径一致

注意:DB_PATH环境变量必须与volumes中容器内路径完全一致,大小写、斜杠都不能错。曾有 A 同学因写成/app/data/chinese_dict.db(下划线)导致服务启动成功但所有查询返回{"error":"database not found"},查日志才发现是路径拼写错误。

3.2 必改配置项 2:ENABLE_DOWNLOAD —— 不开它,/download/db 就是 404

该接口默认关闭,防止生产环境被恶意批量下载。启用方式是在environment块中加:

- ENABLE_DOWNLOAD=true - DOWNLOAD_TOKEN=your_secure_token_here # ← 若开启,必须设 token

然后下载时需带 Header:

curl -H "X-Download-Token: your_secure_token_here" \ http://localhost:8000/download/db \ -o chinese-dict-latest.db

血泪经验:token 不是密码,它不加密、不校验用户身份,只防脚本误触发。若你用在内网测试环境,可设为dev-mode这类明文,但绝不能留空或删掉这一行——否则接口永远 404。

3.3 必改配置项 3:LOG_LEVEL=debug —— 启动失败时,日志是你唯一的黑匣子

默认日志级别是warning,意味着数据库打开失败、SQL 查询报错等关键信息全被吞掉。开发期务必改成:

- LOG_LEVEL=debug

启动后观察日志流:

dict-server-1 | DEBUG:root:Connecting to database at /app/data/chinese-dict.db dict-server-1 | DEBUG:root:Executing query: SELECT * FROM words WHERE word = ? dict-server-1 | ERROR:root:Database error: no such table: words

看到最后一行,你就立刻知道:挂载的 DB 文件格式不对,或者不是它期望的 schema 版本。


4. 避坑:5 条真实翻车记录,每条都来自某次凌晨三点的线上排查

这个服务看似简单,但因数据驱动特性,很多问题藏在“理所当然”的假设里。以下是我在某图像处理 Demo 项目集成时踩过的坑,按发生频率排序:

4.1 现象:查“的”“了”“吗”等高频虚词,返回{"error":"not found"}

原因:词典数据库默认过滤掉词频低于 50 的虚词(避免噪声),而chinese-dict.db的min_freq配置项设为 50。这些词虽常用,但单字在语料中常被切分为更小单位(如“了吗”→“了+吗”),导致单字频次未达标。
解决:启动时加环境变量- MIN_FREQ=10,或手动修改挂载 DB 的config表(UPDATE config SET value = '10' WHERE key = 'min_freq';)。

4.2 现象:/stem/学习返回空数组,但/word/学习正常

原因:词干提取依赖stems表,而该表需单独生成。官方提供的chinese-dict.db默认不包含此表(体积+维护成本考虑),需运行初始化脚本scripts/generate_stems.py生成后重新挂载。
解决:不要跳过 README 里的Generate stem table步骤;若用 Docker,应在构建镜像时RUN python scripts/generate_stems.py。

4.3 现象:并发查 200 个词时,部分请求返回503 Service Unavailable

原因:服务内置连接池上限为 100,且 SQLite 是文件锁模型,高并发写(如日志写入)会阻塞读。这不是性能瓶颈,是资源争用。
解决:加 NGINX 做请求队列限流(limit_req zone=api burst=50 nodelay),或改用--workers 4启动多个 Uvicorn 实例(需配合 PostgreSQL 替换 SQLite)。

4.4 现象:/word/编程返回pinyin_raw: "bian1 cheng2",但实际口语中常读bian4 cheng2

原因:该字段基于《现代汉语词典》第7版规范读音,不收录方言/语境变调。项目定位是“标准语料基线”,不是语音识别前端。
解决:若需语境化拼音,应在其返回基础上叠加规则引擎(如“编”在“编程”中固定读bian1,但在“编辑”中读bian4),不要试图改词典源数据。

4.5 现象:用curl -I测健康检查,返回200 OK,但实际/word/测试返回 500

原因:/health接口只检测服务进程存活和数据库连接是否建立,不执行真实 SQL 查询。它不校验words表是否存在、索引是否损坏。
解决:自定义健康检查端点/health/full(需修改源码),或在 CI/CD 中加入探针脚本:curl -s http://localhost:8000/word/一 | jq -e '.word == "一"' >/dev/null。


5. 进阶用法:用 SQLite 直连做离线校验,绕过 HTTP 层压测词典一致性

HTTP 接口方便,但当你需要验证 10 万词条的拼音覆盖率、统计多音字比例、或对比两个词典版本差异时,每次走网络不仅慢,还引入不确定性。这时,直接打开它背后的 SQLite 文件,才是工程师的后悔药。

5.1 用 CLI 快速统计核心指标:3 条命令看清词典质量

进入挂载目录,执行:

# 1. 总词数 & 高频词占比(词频≥1000 的词占多少?) sqlite3 chinese-dict.db "SELECT COUNT(*) FROM words;" # → 128432 sqlite3 chinese-dict.db "SELECT COUNT(*) FROM words WHERE frequency >= 1000;" # → 8421 # 2. 多音字识别率:有多少词有多个 pinyin_raw? sqlite3 chinese-dict.db " SELECT COUNT(DISTINCT word) FROM words WHERE word IN ( SELECT word FROM words GROUP BY word HAVING COUNT(DISTINCT pinyin_raw) > 1 ); " # → 2176(即 2176 个词存在多音) # 3. 释义完整性:多少词有 definition 字段且非空? sqlite3 chinese-dict.db " SELECT COUNT(*) FROM words WHERE definition IS NOT NULL AND definition != '[]'; " # → 112983(92% 有释义)

提示:definition字段存的是 JSON 字符串(如"['名词,指...']"),所以判空要用!= '[]',不能用IS NOT NULL单独判断。

5.2 对比两个版本词典:用 SQL 找出新增/消失的高频词

假设你有v2023.db和v2024.db,想看哪些高频词(freq≥5000)在新版里消失了:

# 导出两库的高频词到 CSV sqlite3 v2023.db "SELECT word,frequency FROM words WHERE frequency >= 5000 ORDER BY word;" > v2023_high.csv sqlite3 v2024.db "SELECT word,frequency FROM words WHERE frequency >= 5000 ORDER BY word;" > v2024_high.csv # 用 comm 找差集(需先 sort) comm -23 <(sort v2023_high.csv) <(sort v2024_high.csv) | head -10

输出类似:

一,12743 丁,5210 七,5892

说明这些词在 v2024 中已移除(或频次跌破 5000)。这种对比无法通过 HTTP 接口完成,却是词典迭代审计的关键动作。

5.3 构建轻量同义词图:用 JOIN 一次性拉出三层关联

词典中synonym字段是 JSON 数组,但 SQLite 3.38+ 支持json_each()表函数。你可以这样查“电脑”的直接同义词,及其同义词的同义词(二级):

-- 查“电脑”的一级同义词 SELECT s.value AS synonym FROM words w, json_each(w.synonym) s WHERE w.word = '电脑'; -- 查“电脑”的二级同义词(排除一级) SELECT DISTINCT s2.value FROM words w1, json_each(w1.synonym) s1, words w2, json_each(w2.synonym) s2 WHERE w1.word = '电脑' AND s1.value = w2.word AND s2.value != '电脑' AND s2.value NOT IN ( SELECT s1.value FROM words w1, json_each(w1.synonym) s1 WHERE w1.word = '电脑' );

这个查询在 12 万词典上耗时 <800ms,比用 Python 循环调 HTTP 接口快两个数量级。它证明:当你要做深度语义挖掘时,数据库直连不是退路,而是必经之路。

我习惯在每次上线新词典前,跑一遍stats.sql脚本(含上述三条查询),把结果存为 Markdown 报告附在 PR 描述里。不是为了炫技,是让每个改动都可追溯、可证伪。词典不是黑匣子,它是你 NLP 系统的第一块基石——压得越实,上面搭的模型才越敢跑。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询