怎么用 C# 从纯文本里抽实体和关系
不能直接“构建知识图谱”——C# 本身没有内置的 NLP 或图谱推理能力,得靠组合:先做基础文本解析,再用规则或轻量模型识别实体和关系,最后导出为
nodes.json和
edges.json这类结构化数据。别指望
File.ReadAllText后调个方法就出来三元组。
常见错误是把“知识图谱”当黑盒目标,结果卡在第一步:连人名、地名都分不准。真实场景中,90% 的文本没标注、没句法树、甚至没标点,必须接受“低精度但可调试”的起点。
优先用基于词典+正则的硬匹配(比如识别公司名:后的冒号后内容),不是所有项目都适合上
spaCy或
StanfordNLP避免直接喂整篇长文给 NER 模型——切句比切段更稳,用
Regex.Split(text, @"[。!?;\n]+")比
text.Split('\n') 更靠谱
中文需额外处理:“张三,李四,王五”是三人并列,不是“张三,李四”和“李四,王五”两个关系,得加去重逻辑
C# 里哪些 NLP 库真能跑起来
别碰
ML.NET的
TextClassification做实体识别——它不支持细粒度标签(如 PER/ORG/LOC),训练成本高且效果弱于专用 NER 工具。真正可用的只有两类:
Stanford.NLP.CoreNLP(Java 依赖,需
JVM+
IKVM,Windows 上容易崩在
java.lang.UnsatisfiedLinkError)
SharpNLP(已停更,仅支持英文,
Tokenizer对中文完全失效) 推荐折中方案:起一个本地
Flair或
HanLPHTTP 服务,C# 用
HttpClient调用,传
{"text": "xxx"},收 {"entities": [...], "relations": [...]}
性能上,单次请求平均 120–300ms,吞吐量取决于你愿不愿意开连接池和批量接口。别让
HttpClient在循环里 new——那是
SocketException: Too many open files的直通车。
关系抽取最容易漏掉的三种情况
关系不是靠“主谓宾”语法树就能稳抓的。C# 做规则匹配时,这三类文本结构最常导致漏边:
隐含关系:文本写“腾讯收购了搜狗”,但没出现
“收购方”/
“被收购方”字样,需预置动词映射表:
new Dictionary<string string> { {"收购", "acquired"}, {"投资", "invested_in"} }</string>
跨句指代:前句 “马化腾出席发布会。”,后句
“他宣布新战略。”,不解决共指消解,
"他"就永远是孤节点 否定与条件:
“除非监管批准,否则不合并”这种句子,硬抽会得到错误的
(A, merged_with, B)边,得先过滤含
"除非"、
"未获"、
"暂缓"的句子
没做这三步,导出的图谱里会出现大量虚假连接,后期查证成本远高于前期加规则。
导出知识图谱结构时路径和格式怎么设
别直接写
JsonConvert.SerializeObject(graph)就完事。图谱消费端(比如 Neo4j、Gephi 或前端
vis.js)对字段名极其敏感: 节点必须含
"id"(字符串或数字均可,但全局唯一),不能叫
"nodeId"或
"uid",否则
cypher LOAD CSV会跳过整行 关系必须含
"source"和
"target"(对应节点的
id值),不是
"from"/
"to",也不是索引下标 文件路径别用
@"C:\data\nodes.json"——部署到 Linux 容器时路径炸裂,统一走
Path.Combine(AppContext.BaseDirectory, "output", "nodes.json")
多写一行验证逻辑:
if (node.id == null) throw new InvalidOperationException("node.id is required");,比后期在图数据库里 debug 三元组缺失快十倍。 