知识图谱-基于规则的知识抽取

文章目录

    • 一、简介
    • 二、原理
    • 三、实战
      • 1、规则集定义
      • 2、数据获取
      • 3、去除无关词组
      • 4、关系抽取
      • 5、抽取结果验证
      • 6、知识存储
      • 7、查询验证
    • 三、总结


一、简介

基于规则的知识抽取主要还是通过人工定义一些抽取规则,从文章中抽取出三元组信息(实体-关系-实体)。重点即是定义规则。虽然定义规则这种抽取方式看起来有点low,但却简单实用,很多时候,效果比很多高深的算法还要好一些(非绝对,具体领域具体分析)。
本文的数据来源和https://blog.csdn.net/qq_21120275/article/details/102159314保持一致。

二、原理

本文的抽取原理主要分为三个步骤

第一步:定义需要抽取的关系集合,比如【父亲,母亲,儿子,女儿,…】
第二步:遍历文章的每一句话,将每句话中非实体和非关系集合里面的词去掉
第三步:从每句话的第二个词开始遍历,遇到关系集合中的词,就选出该词左右最近的实体

本文没有贴出全部代码,只拿重点代码作为讲解。

三、实战

1、规则集定义

本文从简单入手,依旧和https://blog.csdn.net/qq_21120275/article/details/102159314一样抽取人物关系,先定义需要抽取的关系集合

allowRelationships = ['母亲','父亲','儿子','女儿','母','父','下嫁','又嫁','祖父','祖母','孙','孙子','改嫁','哥哥','姐姐','弟弟']

2、数据获取

使用requests进行文章内容的爬取

import requests
from lxml import etree
import jieba
from jieba import posseg
import re
hraders={'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763'}
url='http://www.uuqgs.com/lsrw/1358.html'
html = requests.get(url,headers=hraders)
text = html.content.decode("gb2312","ignore")
selector = etree.HTML(text)
content=selector.xpath('//div[@id="newscont"]/p/text()')

3、去除无关词组

通过jieba词性识别抽取出nr的实体和带有关系的词组

# 抽取的实体词性
allowTags = ['nr']
relationships = set()
for line in content:
    sentence = []
    for word, tag in posseg.cut(line):
        if tag == 'nr' or word in alowRelationships:
            sentence.append(word)
    sentence = ' '.join(sentence)

4、关系抽取

遍历一句话,从第二个词组开始,如果该词组属于要抽取的关系词组,则抽出前一个词组作为主语,后一个词语作为宾语:

    sentenceSplit = sentence.split(' ')
    print("原始文本:", line)
    for i in range(1,len(sentenceSplit)-1):
        if sentenceSplit[i] in alowRelationships:
            source = sentenceSplit[i-1]
            relationship = sentenceSplit[i]
            target = sentenceSplit[i+1]
            print('提取结果:',source+'->'+relationship+'->'+target)
            relationships.add(source+'->'+relationship+'->'+target)

5、抽取结果验证

结果如下:

'''
原始文本: 武德九年(626年),玄武门之变后,李渊退位称太上皇,禅位于儿子李世民。
提取结果: 太上皇->儿子->李世民
原始文本: 李渊的祖父李虎,在西魏时官至太尉,是西魏八柱国之一。李渊的父亲李昞,北周时历官御史大夫、安州总管、柱国大将军,袭封唐国公。李渊的母亲是隋文帝独孤皇后的姐姐[7] 。
提取结果: 李渊->祖父->李虎
提取结果: 李渊->父亲->李昞
提取结果: 李渊->母亲->隋文帝  #错误结果
'''

6、知识存储

本文的存储形式采用rdf格式,使用rdflib工具包进行操作

import rdflib

g = rdflib.Graph()
pesonUrl = 'http://www.huoyo.org/person/'
relationshipUrl = 'http://www.huoyo.org/relationship/'
for line in relationships:
    line = line.split('->')
    p1 = rdflib.URIRef(pesonUrl+line[0])
    re = rdflib.URIRef(relationshipUrl+line[1])
    #p2 = rdflib.URIRef(pesonUrl+line[2])
    p2 = rdflib.Literal(line[2])
    g.add((p1,re,p2))
    g.serialize("graph.rdf")

文件结果如下


<rdf:RDF
   xmlns:ns1="http://www.huoyo.org/relationship/"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
>
  <rdf:Description rdf:about="http://www.huoyo.org/person/李渊">
    <ns1:女儿>南昌公主ns1:女儿>
     ...
    <ns1:女儿>高密公主ns1:女儿>
    <ns1:女儿>长沙公主ns1:女儿>
    <ns1:儿子>彭思王李元则ns1:儿子>
  rdf:Description>
  <rdf:Description rdf:about="http://www.huoyo.org/person/周王李元方">
    <ns1:>张婕妤ns1:>
  rdf:Description>
   ...
  <rdf:Description rdf:about="http://www.huoyo.org/person/韩王李元嘉">
    <ns1:>宇文昭仪ns1:>
  rdf:Description>
rdf:RDF>

7、查询验证

使用sparql语言进行查询验证

g = rdflib.Graph()
g.parse("graph.rdf", format="xml")
q = "PREFIX p: <"+pesonUrl+">" \
    "PREFIX r: <"+relationshipUrl+">" \
    "select distinct ?b where { p:李渊 r:儿子 ?b }"
x = g.query(q)
t = list(x) 
for i in t:
    print(i)

三、总结

本文主要基于规则进行知识的抽取,核心点就是关系规则的定义和规则两边的实体抽取,整体效果还行,会有部分错误需要人工干预。基于规则抽取的优缺点如下:

  • 优点
  • 无需训练
  • 实现简单
  • 缺点
  • 需要人工干预,特别是细节处理上
  • 只能抽取实体-关系-实体模式的三元组,对于实体-实体-关系模式需要人工识别
  • 局限于通用领域的实体识别,特殊实体和词性需要单独处理

你可能感兴趣的:(知识图谱,NLP)