← 返回 Semantica 专题首页 🌱 SEMANTICA · COOKBOOK · 入门系列

关系抽取 - 全面指南

Semantica 官方 Cookbook 中文翻译 · 第 6 / 37 篇

📦 semantica 🕸️ 知识图谱 🔎 GraphRAG

1概览

本 notebook 提供了一份使用 Semantica 的关系抽取模块抽取实体之间的关系并构建 RDF 三元组的全面指南。你将学习识别连接、抽取结构化三元组,并为知识图谱准备数据。

文档API 参考

学习目标

学完本 notebook 后,你将能够:

  • 使用 RelationExtractor 抽取关系
  • 了解不同的抽取方法(pattern、dependency、co-occurrence、HuggingFace、LLM)
  • 配置抽取参数以获得最佳结果
  • 使用 TripletExtractor 抽取 RDF 三元组
  • 使用 RDFSerializer 将三元组序列化为 RDF 格式
  • 构建完整的实体 → 关系 → 三元组流水线

你将学到什么

组件 用途 使用时机
RelationExtractor 抽取实体关系 寻找连接
TripletExtractor 抽取 RDF 三元组 构建知识图谱
RDFSerializer 序列化为 RDF 格式 数据导出

2安装

从 PyPI 安装 Semantica:

pip install semantica
# 或安装所有可选依赖:
pip install semantica[all]

# 安装 semantica 包
!pip install semantica

3步骤 1:基础关系抽取

让我们从使用 RelationExtractor 抽取实体之间的关系开始。

什么是 RelationExtractor?

RelationExtractor 识别实体之间的关系: - 寻找诸如 "founded_by"、"located_in"、"works_for" 之类的连接 - 返回包含主语、谓词、宾语的 Relation 对象 - 支持多种抽取方法 - 为每个关系提供置信度分数

理解关系

一个关系包含三个部分: - 主语:源实体(例如 "Apple Inc.") - 谓词:关系类型(例如 "founded_by") - 宾语:目标实体(例如 "Steve Jobs")

from semantica.semantic_extract import RelationExtractor, NERExtractor

# 初始化抽取器
ner_extractor = NERExtractor()
relation_extractor = RelationExtractor()

# 包含清晰关系的示例文本
text = """
Apple Inc. was founded by Steve Jobs, Steve Wozniak, and Ronald Wayne in 1976.
The company is headquartered in Cupertino, California. Tim Cook is the current CEO
of Apple Inc. and took over from Steve Jobs in August 2011.
"""

# 首先,抽取实体
entities = ner_extractor.extract(text)
print(f" Extracted {len(entities)} entities\n")

# 然后,抽取关系
relationships = relation_extractor.extract(text, entities)

print(f" Extracted {len(relationships)} relationships:\n")
print("=" * 80)

for i, rel in enumerate(relationships, 1):
    # 同时处理 dict 和对象两种格式
    source = rel.get('source', rel.get('subject', '')) if isinstance(rel, dict) else getattr(rel, 'subject', '')
    target = rel.get('target', rel.get('object', '')) if isinstance(rel, dict) else getattr(rel, 'object', '')
    rel_type = rel.get('type', rel.get('predicate', 'related_to')) if isinstance(rel, dict) else getattr(rel, 'predicate', 'related_to')
    confidence = rel.get('confidence', 1.0) if isinstance(rel, dict) else getattr(rel, 'confidence', 1.0)

    # 获取源和目标文本
    if isinstance(source, dict):
        source_text = source.get('text', source.get('entity', str(source)))
    else:
        source_text = getattr(source, 'text', str(source))

    if isinstance(target, dict):
        target_text = target.get('text', target.get('entity', str(target)))
    else:
        target_text = getattr(target, 'text', str(target))

    print(f"{i:2d}. {source_text:20s} --[{rel_type:15s}]--> {target_text:20s} (conf: {confidence:.2f})")

print("=" * 80)

理解关系对象

每个抽取出的关系包含:

属性 描述 示例
subject 源实体 Entity("Apple Inc.")
predicate 关系类型 "founded_by"
object 目标实体 Entity("Steve Jobs")
confidence 抽取置信度(0-1) 0.85
context 周围文本 "Apple Inc. was founded by Steve Jobs"
metadata 附加信息 {"method": "pattern"}

常见关系类型

  • founded_by:组织由某人创立
  • located_in:实体位于某地
  • works_for:某人为某组织工作
  • born_in:某人出生于某地
  • part_of:实体是另一个实体的一部分
  • related_to:通用关系

4步骤 2:不同的抽取方法

Semantica 支持多种关系抽取方法:

方法对比

方法 速度 准确性 使用场景 所需条件
pattern ⭐⭐⭐ 常见关系
dependency ⭐⭐⭐⭐ 语法关系 spaCy
cooccurrence ⭐⭐ 基于邻近性
huggingface ⭐⭐⭐⭐⭐ 领域特定 HF 模型
llm ⭐⭐⭐⭐⭐ 复杂、自定义 API 密钥
from semantica.semantic_extract import RelationExtractor

sample_text = "Apple Inc. was founded by Steve Jobs in Cupertino, California."
sample_entities = ner_extractor.extract(sample_text)

print(" Comparing Relation Extraction Methods:\n")
print("=" * 80)

# 尝试不同的方法
methods_to_try = ["pattern", "dependency", "cooccurrence"]

for method_name in methods_to_try:
    try:
        print(f"\n Method: {method_name.upper()}")
        print("-" * 40)

        extractor = RelationExtractor(method=method_name)
        relations = extractor.extract(sample_text, sample_entities)

        print(f"Found {len(relations)} relations:")
        for rel in relations[:3]:  # 显示前 3 个
            source = rel.get('source', rel.get('subject', '')) if isinstance(rel, dict) else getattr(rel, 'subject', '')
            target = rel.get('target', rel.get('object', '')) if isinstance(rel, dict) else getattr(rel, 'object', '')
            rel_type = rel.get('type', rel.get('predicate', 'related_to')) if isinstance(rel, dict) else getattr(rel, 'predicate', 'related_to')

            # 获取文本表示
            source_text = source.get('text', str(source)) if isinstance(source, dict) else getattr(source, 'text', str(source))
            target_text = target.get('text', str(target)) if isinstance(target, dict) else getattr(target, 'text', str(target))

            print(f"  • {source_text} --[{rel_type}]--> {target_text}")

    except Exception as e:
        print(f"  ️  Method '{method_name}' not available: {str(e)[:50]}")

print("\n" + "=" * 80)

5步骤 3:带配置的高级关系抽取

RelationExtractor 提供了强大的配置选项:

关键参数:

  • relation_types:要抽取的特定关系类型(例如 ["founded", "works_at"]
  • bidirectional:抽取双向关系(默认:False)
  • confidence_threshold:最低置信度分数(0.0-1.0,默认:0.6)
  • max_distance:实体之间的最大 token 距离(默认:50)
# 使用自定义配置创建抽取器
advanced_extractor = RelationExtractor(
    relation_types=["founded_by", "located_in", "works_for"],  # 只抽取这些类型
    confidence_threshold=0.7,  # 更高的阈值以保证质量
    bidirectional=False,  # 只抽取单向关系
    max_distance=50  # 实体之间最多 50 个 token
)

# 示例文本
texts = [
    "Microsoft was founded by Bill Gates and Paul Allen in Albuquerque, New Mexico.",
    "Satya Nadella works for Microsoft as the CEO.",
    "Google is located in Mountain View, California.",
    "Amazon was founded by Jeff Bezos in Seattle, Washington."
]

print(" Advanced Relation Extraction:\n")
print("=" * 80)

for i, text in enumerate(texts, 1):
    entities = ner_extractor.extract(text)
    relations = advanced_extractor.extract(text, entities)

    print(f"\n Text {i}: {text}")
    print(f"   Relations found: {len(relations)}")

    for rel in relations:
        source = rel.get('source', rel.get('subject', '')) if isinstance(rel, dict) else getattr(rel, 'subject', '')
        target = rel.get('target', rel.get('object', '')) if isinstance(rel, dict) else getattr(rel, 'object', '')
        rel_type = rel.get('type', rel.get('predicate', 'related_to')) if isinstance(rel, dict) else getattr(rel, 'predicate', 'related_to')
        confidence = rel.get('confidence', 1.0) if isinstance(rel, dict) else getattr(rel, 'confidence', 1.0)

        source_text = source.get('text', str(source)) if isinstance(source, dict) else getattr(source, 'text', str(source))
        target_text = target.get('text', str(target)) if isinstance(target, dict) else getattr(target, 'text', str(target))

        print(f"     • {source_text} --[{rel_type}]--> {target_text} (conf: {confidence:.2f})")

print("\n" + "=" * 80)

6步骤 4:关系分类

按谓词类型对已抽取的关系进行分组和分类。

# 从所有文本中抽取关系
all_relations = []
for text in texts:
    entities = ner_extractor.extract(text)
    relations = advanced_extractor.extract(text, entities)
    all_relations.extend(relations)

# 对关系进行分类
classified_relations = advanced_extractor.classify_relations(all_relations)

print("️  Relation Classification:\n")
print("=" * 80)

for rel_type, rel_list in sorted(classified_relations.items()):
    print(f"\n{rel_type.upper()} ({len(rel_list)} relations):")
    print("-" * 40)

    for rel in rel_list:
        source = rel.get('source', rel.get('subject', '')) if isinstance(rel, dict) else getattr(rel, 'subject', '')
        target = rel.get('target', rel.get('object', '')) if isinstance(rel, dict) else getattr(rel, 'object', '')

        source_text = source.get('text', str(source)) if isinstance(source, dict) else getattr(source, 'text', str(source))
        target_text = target.get('text', str(target)) if isinstance(target, dict) else getattr(target, 'text', str(target))

        print(f"  • {source_text}{target_text}")

print("\n" + "=" * 80)

7步骤 5:三元组抽取

使用 TripletExtractor 抽取 RDF 三元组。三元组是知识图谱的基础。

什么是 RDF 三元组?

RDF(资源描述框架)三元组是由三个部分组成的陈述: - 主语:我们在谈论什么 - 谓词:属性或关系 - 宾语:值或目标

示例:(Apple Inc., founded_by, Steve Jobs)

为什么要使用三元组?

  • 用于知识表示的标准化格式
  • 与 RDF 数据库和语义网兼容
  • 可使用 SPARQL 进行查询
  • 跨系统可互操作
from semantica.semantic_extract import TripletExtractor

# 初始化三元组抽取器
triplet_extractor = TripletExtractor(
    include_temporal=True,  # 包含时序信息
    include_provenance=True  # 追踪来源句子
)

# 示例文本
triplet_text = """
Apple Inc. was founded by Steve Jobs in 1976. The company is based in Cupertino, California.
Tim Cook became CEO in 2011. Apple develops the iPhone and MacBook products.
"""

# 抽取三元组
triplets = triplet_extractor.extract_triplets(triplet_text)

print(f" Extracted {len(triplets)} RDF Triplets:\n")
print("=" * 80)

for i, triplet in enumerate(triplets, 1):
    subject = triplet.get('subject', '') if isinstance(triplet, dict) else triplet.subject
    predicate = triplet.get('predicate', '') if isinstance(triplet, dict) else triplet.predicate
    obj = triplet.get('object', '') if isinstance(triplet, dict) else triplet.object
    confidence = triplet.get('confidence', 1.0) if isinstance(triplet, dict) else getattr(triplet, 'confidence', 1.0)

    print(f"{i:2d}. ({subject}, {predicate}, {obj})")
    print(f"    Confidence: {confidence:.2f}")

    # 如果有时序信息则显示
    metadata = triplet.get('metadata', {}) if isinstance(triplet, dict) else getattr(triplet, 'metadata', {})
    if metadata.get('temporal'):
        print(f"    Temporal: {metadata['temporal']}")
    print()

print("=" * 80)

8步骤 6:RDF 序列化

使用 RDFSerializer 将三元组序列化为各种 RDF 格式。

支持的格式:

格式 扩展名 使用场景
Turtle .ttl 人类可读、紧凑
N-Triples .nt 简单、基于行
JSON-LD .jsonld 对 Web 友好、基于 JSON
RDF/XML .rdf 基于 XML、冗长
from semantica.semantic_extract import RDFSerializer

# 初始化序列化器
serializer = RDFSerializer()

print(" RDF Serialization Examples:\n")
print("=" * 80)

# 序列化为不同格式
formats = ["turtle", "ntriples", "jsonld"]

for fmt in formats:
    print(f"\n {fmt.upper()} Format:")
    print("-" * 40)

    try:
        serialized = serializer.serialize_to_rdf(triplets[:3], format=fmt)  # 显示前 3 个

        # 显示预览(前 300 个字符)
        preview = serialized[:300] + "..." if len(serialized) > 300 else serialized
        print(preview)

    except Exception as e:
        print(f"Error: {str(e)[:50]}")

print("\n" + "=" * 80)

9步骤 7:完整抽取流水线

让我们构建一个完整的流水线:实体 → 关系 → 三元组

这演示了知识图谱构建的完整工作流。

def extract_knowledge(text):
    """
    完整知识抽取流水线。

    Args:
        text: 输入文本

    Returns:
        dict: 抽取出的实体、关系和三元组
    """
    # 步骤 1:抽取实体
    entities = ner_extractor.extract(text)

    # 步骤 2:抽取关系
    relations = relation_extractor.extract(text, entities)

    # 步骤 3:抽取三元组
    triplets = triplet_extractor.extract_triplets(text, entities=entities, relationships=relations)

    return {
        'entities': entities,
        'relations': relations,
        'triplets': triplets
    }

# 富含知识的示例文本
knowledge_text = """
Tesla Inc. was founded by Elon Musk, JB Straubel, Martin Eberhard, Marc Tarpenning, 
and Ian Wright in 2003. The company is headquartered in Austin, Texas. Tesla produces 
electric vehicles including the Model S, Model 3, Model X, and Model Y. Elon Musk serves 
as CEO and has been instrumental in the company's growth.
"""

print(" Complete Extraction Pipeline:\n")
print("=" * 80)

# 运行流水线
result = extract_knowledge(knowledge_text)

print(f"\n Extraction Results:")
print("-" * 40)
print(f"Entities extracted: {len(result['entities'])}")
print(f"Relations extracted: {len(result['relations'])}")
print(f"Triplets extracted: {len(result['triplets'])}")

print(f"\n Sample Triplets:")
for i, triplet in enumerate(result['triplets'][:5], 1):
    subject = triplet.get('subject', '') if isinstance(triplet, dict) else triplet.subject
    predicate = triplet.get('predicate', '') if isinstance(triplet, dict) else triplet.predicate
    obj = triplet.get('object', '') if isinstance(triplet, dict) else triplet.object
    print(f"  {i}. ({subject}, {predicate}, {obj})")

print("\n" + "=" * 80)

10步骤 8:最佳实践与技巧

选择合适的方法

  1. 对于常见关系,从基于 pattern 的方法开始
  2. 对于语法准确性,使用 dependency 解析
  3. 对于探索性分析,尝试 co-occurrence
  4. 对于复杂、领域特定的关系,考虑 LLM

优化抽取

  • 设置置信度阈值(生产环境为 0.6-0.7)
  • 指定 relation_types 以聚焦抽取
  • 根据文本结构调整 max_distance

需要避免的常见陷阱

  • 不要跳过实体抽取(关系需要实体)
  • 不要使用非常低的置信度阈值
  • 不要忘记将三元组序列化以便存储

何时使用每个组件

使用场景 推荐组件
寻找实体连接 RelationExtractor
构建知识图谱 TripletExtractor
导出为 RDF RDFSerializer

性能技巧

  1. 只抽取一次实体,供关系和三元组复用
  2. 批量处理多个文档
  3. 缓存抽取器而不是重新创建
  4. 使用置信度阈值尽早过滤

11小结

你学到了什么

在本 notebook 中,你学会了如何:

使用 RelationExtractor 抽取关系
对比抽取方法(pattern、dependency、co-occurrence、HuggingFace、LLM)
配置抽取参数以获得最佳结果
使用 TripletExtractor 抽取 RDF 三元组
使用 RDFSerializer 序列化为 RDF 格式
构建从实体到三元组的完整流水线

关键要点

  1. 关系连接实体:它们构成知识图谱的骨干
  2. 多种方法可用:根据准确性 vs 速度的需求选择
  3. 配置很强大:为你的领域调整参数
  4. 三元组是标准化的:使用 RDF 实现互操作性
  5. 流水线是高效的:按顺序抽取实体 → 关系 → 三元组

下一步

下一篇 Notebook07-building-knowledge-graphs.html
学习如何从你抽取的三元组构建完整的知识图谱!

延伸阅读: - Semantic Extract API 参考 - 知识图谱模块 - 高级图分析


有问题或疑问? 请查看我们的 GitHub 仓库文档