ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

text2graph实战:中文文本自动构建可交互知识图谱

2026/9/28 1:55:35 拓冰建站 浏览量
text2graph实战:中文文本自动构建可交互知识图谱 简介这份资源面向具备一定Python基础、希望入门自然语言处理与知识图谱构建的开发者与学习者围绕「文本转知识图谱」这一典型AI应用场景提供可运行的完整工程实现。包内共63个文件以JavaScript前端脚本、XML配置、Python源码及编译缓存为主另含CSS样式、HTML页面与说明文本压缩包约605.62MB其中包含分词、命名实体识别、关系抽取、图构建与可视化等环节所需的代码与数据。项目覆盖文本预处理、实体与关系识别、基于networkx的图结构搭建、ECharts可视化展示以及模型训练优化等模块并配有测试样例用于验证各阶段输出。已有597人学习下载适合希望系统理解从原始文本到知识图谱全流程、并借助现成代码快速上手实践的读者参考。1. 从一段中文文本到一张可交互图谱text2graph 到底能跑出什么手里有一堆访谈记录、产品需求文档或者行业研报想快速看出里面的人、事、物是怎么勾连的靠肉眼一行行读效率太低。text2graph.zip这个包解决的就是这件事把一段中文文本喂进去自动分词、抽关键词、识别实体、抽关系最后吐出一张能在浏览器里拖拽缩放的 HTML 图谱。它不是 Neo4j 那种重型图数据库方案而是一个纯 Python 的轻量管线核心依赖 LTP 做句法分析、TextRank 做关键词、ECharts 做前端渲染。适合谁做数据分析想快速摸清文本结构的、学 NLP 想找一个能跑通全流程的练手项目的、以及需要给非技术同事展示文本关系的从业者。整个包解压后不大但麻雀虽小从分词到可视化的链路是完整的拿来改比从零搭省事得多。2. 拆开 text2graph 的目录每个文件在管线里干什么活2.1 核心脚本的分工与调用顺序拿到一个源码包我习惯先看根目录的文件名因为命名往往暴露了作者的设计意图。text2graph这个包的结构不算复杂但每个文件的位置和职责需要先理清楚不然后面改代码容易改错地方。根目录下最显眼的是text_grapher.py这是整个流程的入口脚本。它负责串联所有步骤读文本、调分词、抽关键词、做句法分析、生成图数据、最后输出 HTML。你运行的时候主要就是跟这个文件打交道。旁边有个sentence_parser.py名字直白专门处理句子级别的解析内部会调用 LTP 的接口做分词、词性标注和依存句法分析。这两个文件是管线的核心逻辑。keywords_textrank.py是关键词抽取模块实现了 TextRank 算法。TextRank 的思路来自 PageRank把词当成节点共现关系当成边迭代算权重最后排在前面的就是关键词。这个文件独立出来是有道理的因为关键词抽取的参数窗口大小、迭代次数经常需要根据文本长度调整单独一个文件方便改。GraphShow.py负责可视化部分。它读取前面生成的图数据套进 ECharts 的模板输出graph_show.html。dist目录下能看到echarts-optimize-conf.js和source文件夹这是 ECharts 的运行时文件说明前端渲染不依赖 CDN离线也能打开。VIS目录应该是存放可视化中间产物的ltp_data.zip是 LTP 的模型数据压缩包需要解压后才能用。.idea和__pycache__是 IDE 配置和 Python 字节码缓存跟业务逻辑无关可以忽略。注意ltp_data.zip必须解压到脚本能找到的路径否则sentence_parser.py初始化 LTP 时会直接报模型加载失败。常见做法是解压到当前目录然后在代码里把ltp_data的路径写对。2.2 环境准备与依赖安装的实操步骤这个包用的是 Python 3.6 时代的 LTP 版本从.pyc文件名里的cpython-36能看出来但你现在用 Python 3.8 到 3.10 也能跑只是 LTP 的安装方式要换。老版本的pyltp在新 Python 上编译经常翻车血泪经验是直接用ltp这个包名的新版接口或者用pyltp的 fork 版本。先建虚拟环境别污染系统 Pythonpython -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate然后装核心依赖。pyltp如果装不上换成ltppip install pyltp0.2.1 # 如果这行报错看下面的替代方案 pip install jieba networkx如果pyltp编译失败在 Windows 上尤其常见用这个替代pip install ltpltp新版接口和pyltp有差异需要改sentence_parser.py里的调用方式。具体来说pyltp.Segmentor()要换成ltp.LTP()seg.segment()换成ltp.seg()。参数上新版不需要单独加载cws.model、pos.model、parser.model三个文件而是统一加载一个模型目录。networkx用来构建图数据结构虽然这个包最终输出的是 ECharts 的 JSON 格式但中间计算节点度、找社区的时候用 networkx 会方便很多。jieba是备用分词器当 LTP 加载失败或者你只想快速测试时可以临时切到 jieba。解压 LTP 模型数据unzip ltp_data.zip -d ltp_data解压后ltp_data目录下应该有cws.model、pos.model、ner.model、parser.model这几个文件。如果压缩包里只有文件夹没有模型文件说明你下的是空壳需要去 LTP 官方渠道补下模型。这一步没有后悔药模型文件不对后面全跑不通。3. 跑通第一条链路从文本输入到 graph_show.html 输出3.1 修改入口脚本的输入路径与参数text_grapher.py里通常有一个if __name__ __main__:块里面写死了输入文本的路径。你需要把它改成你自己的文本文件路径。常见做法是准备一个input.txt把待分析的文本存进去UTF-8 编码不要带 BOM。# text_grapher.py 末尾的入口部分 if __name__ __main__: # 把这里改成你的文本文件路径 input_file input.txt with open(input_file, r, encodingutf-8) as f: text f.read() # 关键词抽取的 topK默认 10文本长可以调到 20 top_k 15 # 调用主流程 graph_data build_graph(text, top_ktop_k) # 输出 HTML render_html(graph_data, outputgraph_show.html)这段代码的逻辑是读文本 → 调build_graph做全流程处理 → 把图数据传给render_html生成 HTML。top_k控制关键词数量直接影响到图谱里节点多少。文本短几百字设 10 左右文本长几千字设 20 到 30太多会让图变得像毛线团。build_graph内部会依次调用sentence_parser做句法分析、keywords_textrank抽关键词。如果你只想调关键词抽取可以单独跑from keywords_textrank import TextRank tr TextRank() keywords tr.extract(text, top_k20) for word, weight in keywords: print(f{word}\t{weight:.4f})TextRank 的窗口大小默认是 5意思是前后 5 个词之内算共现。中文文本里这个值偏大改成 3 更合适否则远距离的词也会被连边图谱会多出很多弱关系。改的地方在keywords_textrank.py里找window参数。3.2 句法分析与关系抽取的衔接逻辑sentence_parser.py干的事是把一段文本拆成句子对每句话做依存句法分析然后从依存关系里抽实体和关系。LTP 的依存分析会输出每个词跟它父节点的关系标签比如SBV主谓关系、VOB动宾关系、ATT定中关系。关系抽取的常见做法是找动词作为关系触发词然后看它的主语和宾语。比如“张三创办了公司”这句话依存分析会标出“张三”是“创办”的主语“公司”是“创办”的宾语那么就能抽出一个三元组(张三, 创办, 公司)。# sentence_parser.py 里关系抽取的核心逻辑示意 def extract_relations(words, postags, arcs): relations [] for i, arc in enumerate(arcs): # 找动词 if postags[i] v: subject None obj None for j, a in enumerate(arcs): if a.head i 1: # 依存弧指向当前动词 if a.relation SBV: subject words[j] elif a.relation VOB: obj words[j] if subject and obj: relations.append((subject, words[i], obj)) return relations这段代码遍历所有词遇到动词就找它的主语和宾语。arcs是 LTP 输出的依存弧列表head是父节点索引从 1 开始relation是关系标签。参数上postags是词性列表只有动词才触发关系抽取这是简化处理。更严谨的做法是把名词性谓语也考虑进来但那样代码复杂度会上去。抽出来的三元组会跟关键词一起传给GraphShow.py构建成 ECharts 需要的节点和边格式。节点去重、边合并权重这些操作在GraphShow.py里做。3.3 生成 HTML 与浏览器验证跑完text_grapher.py后当前目录下会生成graph_show.html。直接用浏览器打开不需要起服务器。如果打开是空白页按 F12 看 Console 报什么错。最常见的是 ECharts 的 JS 文件路径不对dist目录下的echarts-optimize-conf.js需要能被 HTML 引用到。!-- graph_show.html 里引用 ECharts 的部分 -- script srcdist/echarts-optimize-conf.js/script如果 HTML 文件和dist不在同一级目录这个相对路径就要改。另一个常见问题是图数据为空原因是 LTP 模型没加载成功sentence_parser返回了空列表。在sentence_parser.py里加一行print看分词结果是否正常是最快的排查方式。图谱渲染出来后节点大小通常跟关键词权重挂钩边粗细跟共现次数挂钩。拖拽节点、滚轮缩放、悬停看详情这些交互是 ECharts 自带的不用额外写代码。如果节点太多导致卡顿把top_k调小或者在GraphShow.py里加一个度过滤只保留度数大于 2 的节点。4. 避坑与排查跑 text2graph 时最容易翻车的五个地方4.1 LTP 模型加载失败现象是分词结果为空或报错现象运行脚本后没有任何输出或者报AttributeError: NoneType object has no attribute segment。原因通常是ltp_data路径不对或者模型文件缺失。pyltp初始化Segmentor时需要指定cws.model的完整路径路径里如果有中文或者空格也会出问题。解决把ltp_data放在脚本同级目录用绝对路径加载路径里不要有中文。检查ltp_data下是否有cws.model、pos.model、parser.model三个文件缺哪个补哪个。4.2 pyltp 安装编译报错现象是 pip install 卡在 building wheel现象pip install pyltp跑了几分钟最后报error: Microsoft Visual C 14.0 is required或者gcc: command not found。原因是pyltp包含 C 扩展需要本地编译环境。Windows 上装 Visual Studio Build ToolsLinux 上装build-essential和python3-dev。如果还是不行直接换ltp包接口虽然不同但功能覆盖了分词、词性、NER、依存分析改几行调用代码的事。4.3 关键词抽取结果全是单字现象是 TextRank 输出“的”“了”“在”现象跑keywords_textrank.py出来的 top 词全是停用词或者单字。原因是分词后没有过滤停用词TextRank 把“的”“了”这种高频词也算进去了。解决在keywords_textrank.py里加一个停用词表分词后先过滤再建图。停用词表可以自己攒也可以用现成的中文停用词库。另外词性过滤也管用只保留名词、动词、形容词把助词、介词、连词都扔掉。4.4 图谱节点过多导致浏览器卡死现象是打开 HTML 后页面无响应现象graph_show.html打开后浏览器风扇狂转拖拽延迟好几秒。原因是节点数超过 200 时 ECharts 的力导向布局计算量暴涨。解决在GraphShow.py里加节点过滤只保留度数排名前 50 的节点或者把top_k从 30 降到 10。另一个办法是换布局算法把force换成circular牺牲一点美观换流畅度。4.5 关系抽取结果不符合预期现象是三元组里出现“是”“有”这种空动词现象抽出来的关系大量是(X, 是, Y)或者(X, 有, Y)没有实际意义。原因是依存分析把判断动词和存在动词也标成了SBV和VOB关系。解决在extract_relations里加一个动词黑名单把“是”“有”“为”“在”这类词过滤掉。更精细的做法是只保留特定语义类的动词但这需要额外维护一个动词表看你的文本领域决定。5. 进阶调优让图谱从“能看”变成“好用”的几个参数5.1 用词性过滤和停用词表提升关键词质量默认的 TextRank 实现通常只做了分词没有做词性过滤。你把keywords_textrank.py打开找到建图之前的那段加一个词性筛选。LTP 的词性标注里n是名词v是动词a是形容词nh是人名ns是地名ni是机构名。只保留这些词性关键词的可读性会明显提升。# 在 keywords_textrank.py 的 extract 方法里加词性过滤 allow_pos {n, v, a, nh, ns, ni} filtered_words [] for word, pos in zip(words, postags): if pos in allow_pos and word not in stopwords: filtered_words.append(word)stopwords是一个集合可以从文件读也可以硬编码。我一般会准备一个stopwords.txt每行一个词用set(open(stopwords.txt).read().splitlines())加载。这个过滤步骤放在分词之后、建图之前对最终关键词列表的影响立竿见影。5.2 调整 TextRank 窗口与阻尼系数控制关系密度TextRank 有两个关键参数窗口大小window和阻尼系数d。窗口大小决定多远距离内的词算共现默认 5 对中文偏大改成 3 更合适。阻尼系数默认 0.85跟 PageRank 一样调低到 0.6 到 0.7 会让权重分布更均匀避免少数几个词霸占整个图谱。# TextRank 迭代部分的参数调整 d 0.7 # 阻尼系数默认 0.85调低让权重分散 window 3 # 共现窗口默认 5中文建议 3 max_iter 100 # 最大迭代次数 min_diff 0.001 # 收敛阈值改完这几个参数后重新跑一遍对比节点数量和边数量。如果边数还是太多可以在GraphShow.py里加一个边权重阈值只保留权重排名前 30% 的边。这样图谱会稀疏一些但核心关系更突出。5.3 把输出接入 Neo4j 做持久化查询ECharts 的 HTML 适合展示但不适合做复杂查询。如果你需要按关系类型检索、做多跳推理把三元组导入 Neo4j 是更工程化的做法。text_grapher.py抽出来的三元组可以直接拼成 Cypher 语句。# 把三元组转成 Neo4j 的 Cypher 导入语句 def to_cypher(triples): lines [] for subj, rel, obj in triples: # 转义单引号避免 Cypher 语法错误 subj subj.replace(, \\) obj obj.replace(, \\) rel rel.replace(, \\) line fMERGE (a:Entity {{name: {subj}}}) line fMERGE (b:Entity {{name: {obj}}}) line fMERGE (a)-[:{rel}]-(b); lines.append(line) return \n.join(lines)这段代码用MERGE而不是CREATE避免重复导入时产生重复节点。关系类型直接用动词Neo4j 支持中文关系类型但建议还是映射成英文比如“创办”映射成FOUNDED这样查询语句写起来更顺手。导入之后就能用 Cypher 做多跳查询了比如“找出所有跟张三间接相关的公司”。5.4 验证图谱质量的三个检查点跑完一遍不算完得验证结果靠不靠谱。我一般看三个地方第一随机抽 10 个三元组人工判断关系是否成立准确率低于 70% 就要回去调依存分析的过滤规则第二看关键词列表里有没有明显的噪声词如果有说明停用词表不够全第三看图谱的连通性如果大部分节点是孤立的说明关系抽取太稀疏需要放宽窗口或者降低边权重阈值。从那以后我每次跑完 text2graph都会先拿一段自己熟悉的文本做回归测试确认三元组和关键词没跑偏再换新文本。这个习惯帮我省了很多来回调试的时间。希望帮到你。本文还有配套的精品资源点击获取