构建红楼梦人物关系知识图谱

作者: mayi14 | 来源:发表于2018-02-08 15:43 被阅读369次

知识图谱构建步骤:数据获取、知识抽取、关系提取、图数据库构建和语义搜索(本质就是把检索的问题转换为查询语句)

知识图谱实践:构建红楼梦人物关系知识图谱

1、获取数据和数据整理

'''
数据获取:http://www.360doc.com/content/16/1206/07/10310181_612337990.shtml
数据整理
'''
import re
hlm = open('hlm.txt','r+',encoding='utf8')
s=hlm.readlines()
s = [t.strip() for t in s if t.strip()!='']#去除空格
p = re.compile(r'([^\(]+):(.+)')
dict1 = {}#人物属性
for t in s:
    ma = p.match(t)
    if ma and len(ma.group(1))<10:
        dict1[ma.group(1)] = ma.group(2)
dict1
{'七尼': '妙玉、智能、智通、智善、圆信、大色空、净虚。',
 '七彩': '彩屏、彩儿、彩凤、彩霞、彩鸾、彩明、彩云。',
 '五小': '小鹊、小红、小蝉、小舍儿、小螺。',
 '五王': '王夫人、王熙凤、王子腾、王仁、薛姨妈。',
 '十二丫环': '晴雯、麝月、袭人、鸳鸯、雪雁、紫鹃、碧痕、平儿、香菱、金钏、司棋、抱琴。',
 '十二儿': '庆儿、昭儿、兴儿、隆儿、坠儿、喜儿、寿儿、丰儿、住儿、小舍儿、李十儿、玉柱儿。',
 '十二官': '琪官、芳官、藕官、蕊官、药官、玉官、宝官、龄官、茄官、艾官、豆官、葵官。',……

p2 = re.compile(r'([^\(]+)--(.+)')
dict2 = {}#主仆关系
for t in s:
    ma = p2.match(t)
    if ma and len(ma.group(1))<10:
        dict2[ma.group(1)] = ma.group(2)
dict2
{'史湘云': '翠缕、笑儿、篆儿。',
 '林黛玉': '紫鹃、雪雁、春纤。',
 '贾宝玉': '茗烟、袭人、晴雯。',
 '贾惜春': '入画、彩屏、彩儿。',
 '贾探春': '侍画、翠墨、小蝉。',
 '贾迎春': '彩凤、彩云、彩云、彩霞'}
p3 = re.compile(r'.+[(府)(其他)]人物.*')
num = []
for t in range(len(s)):
    ma = p3.match(s[t])
    if ma:
        num.append(t)
profiles = {}#人物简介
for n in range(len(num)):
    begin = num[n]+1
    if n<(len(num)-1):
        end = num[n+1]
    else:
        end = len(s)
    while begin<end:
        if len(s[begin])<6:
            profiles[s[begin]] = s[begin+1]
        begin += 2
profiles
{'佩凤': '佩凤,贾珍之妾,年青姣憨之女子。',
 '偕鸾': '偕鸾,贾珍之妾,年青姣憨之女子。',
 '傻大姐': '傻大姐,贾母房内专做粗活的小丫头。她生得体肥面阔,两只大脚,做起粗活来很是爽利简捷。由于生性愚顽,一无知识,出言便使人发笑,贾母喜欢,便起名 “傻大姐”。正因为她有些弱智,去大观园玩时拾到一个五彩绣香囊,却不认得这是个春意儿,拿在手上只管瞧,才被邢夫人发现,引起了抄检大观园的轩然大波。在贾母等人实施“掉包计”时,她也不明白为什么她说了句“宝二爷要娶宝姑娘” 的话就被人打了一个嘴巴。她觉得委屈,跑到沁芳桥边呜呜咽咽地哭,被黛玉听见,询问何故,她就一一告诉,使黛玉听后如雷轰顶,惟求速死。',
 '入画': '入画,贾惜春的丫环。因她父母在南方,她和哥哥只好跟随叔叔过日子,可叔叔婶婶只知道喝酒赌钱,她哥哥只好把做小厮所得的赏赐托人交给她保管,抄检大观园时被发现。贾惜春非要把她撵走,入画跪地哀求,百般苦告,尤氏只得叫人将入画带到宁府。',
 '冷子兴': '冷子兴,周瑞家的女婿,都城中的古董商,和贾雨村是好朋友。他曾对贾雨村演说过荣国府。有一次卖古董和人打官司,便叫女儿来向荣国府讨情,周瑞家的求求凤姐就成了。',……

2、图数据库的建立

'''
图数据库的建立
'''
#Graph()实例化
from py2neo import Graph
graph = Graph("http://localhost:7474",user='neo4j',password='123')
from py2neo import Node, Relationship,size ,order
personSet = set()#存储所有的人物实体
for key, value in dict1.items():
    v=re.sub(r'[和。]','、',value)#把和替换为、
    lv = [t for t in v.split('、') if t!='']
    for t in range(len(lv)):
        p = re.compile(r'(.+)(.+')
        ma = p.match(lv[t])
        if ma:
            lv[t] = ma.group(1)
        if len(lv[t])!=1:
            personSet.add(lv[t])
for key, value in dict2.items():
    v=re.sub(r'[和。]','、',value)#把和替换为、
    lv = [t for t in v.split('、') if t!='']
    for t in range(len(lv)):
        p = re.compile(r'(.+)(.+')
        ma = p.match(lv[t])
        if ma:
            lv[t] = ma.group(1)
        if len(lv[t])!=1:
            personSet.add(lv[t])
for key, value in profiles.items():
    personSet.add(key)

import pickle
with open('personSet.pkl','wb') as f:
    pickle.dump(list(personSet),f)
with open('alias.pkl','wb') as f:
    pickle.dump(list(dict1.keys()),f)

#创建人员实体
for t in personSet:
    n = Node('Person', name=t)
    graph.create(n) 
#创建别名alias实体
for key, value in dict1.items():
    n = Node('Alias', name=key)
    graph.create(n) 
#创建alias实体和person实体的关系Belong
for key, value in dict1.items():
    v=re.sub(r'[和。]','、',value)#把和替换为、
    lv = [t for t in v.split('、') if t!='']
    for t in range(len(lv)):
        p = re.compile(r'(.+)(.+')
        ma = p.match(lv[t])
        if ma:
            lv[t] = ma.group(1)
        graph.run('Match (p:Person {name:"'+lv[t]+'"}) Match (a:Alias {name:"'+key+'"}) CREATE (p)-[:Belong]->(a)')
#创建person实体和person实体的关系Own
for key, value in dict2.items():
    v=re.sub(r'[和。]','、',value)#把和替换为、
    lv = [t for t in v.split('、') if t!='']
    for t in range(len(lv)):
        p = re.compile(r'(.+)(.+')
        ma = p.match(lv[t])
        if ma:
            lv[t] = ma.group(1)
        graph.run('Match (p1:Person {name:"'+lv[t]+'"}) Match (p2:Person {name:"'+key+'"}) CREATE (p2)-[:Own]->(p1)')
#添加人物简介
for key, value in profiles.items():
    graph.run('Match (p:Person {name:"'+key+'"}) SET p.profile="'+value+'"')
关系Belong
关系Own
所有关系

3、语义搜索

#Graph()实例化
from py2neo import Graph
graph = Graph("http://localhost:7474",user='neo4j',password='123')

from py2neo import Graph,Node,walk,Relationship,NodeSelector

#查询node
def find_node(graph,node_name,output=None):
    s=NodeSelector(graph)  
    try:
        if(output):
            return output(s.select(name=node_name).first())
        else:
            return s.select(name=node_name).first()
    except:
        return '没有这个'+node_name+'节点,查询失败'

find_node(graph,'贾宝玉',dict)

#查询node的属性
def find_node_property(graph,node_name,props):
    tmp=find_node(graph,node_name,output=dict)
    if(type(props)==list):
        result={}
        for i in props:
            try:
                result[i]=tmp[i]
            except:
                print('输入的属性'+i+'有误,没有这个属性')
        return result
    else:
        return tmp[props]
find_node_property(graph,'林黛玉','profile')

#查询与节点有特定关系的节点
def find_node_from_rela(graph,node_name,relationship):
    node=find_node(graph,node_name)
    tmp=[]
    try:        
        for n in graph.match(start_node=node,rel_type=relationship):
            tmp.append(n.end_node()["name"])
        return tmp
    except:
        return '输入有误,查询失败'
    
    
find_node_from_rela(graph,'林黛玉','Own')

#查询两个节点的关系
def find_rela(graph,node_name_1,node_name_2):
    node_1=find_node(graph,node_name_1)
    node_2=find_node(graph,node_name_2)
    try:
        rel=graph.match_one(start_node=node_1,end_node=node_2)
        return node_name_1+rel.type()+node_name_2
    except:
        try:
            rel=graph.match_one(start_node=node_2,end_node=node_1)
            return node_name_2+rel.type()+node_name_1
        except:
            return node_name_1+'与'+node_name_2+'没有关系'
print(find_rela(graph,'贾惜春','入画')) 
print(find_rela(graph,'平儿','贾惜春')) 
print(find_rela(graph,'金陵十二钗正册','贾惜春'))

#查询两个node之间是否存在特定关系
def is_node_rela(graph,node_name_1,node_name_2,rela):
    tmp=find_rela(graph,node_name_1,node_name_2)
    return rela in tmp

is_node_rela(graph,'史湘云','翠缕','Own')  

import pickle
with open('personSet.pkl','rb') as f:
    personSet = pickle.load(f)
with open('alias.pkl','rb') as f:
    alias = pickle.load(f)

nodes = list(personSet)+list(alias)
#关系列表
relation=['Belong','Own']
#属性词表
propertys=['profile']

#同义词处理
own=['Own','拥有','主人','仆人','主仆关系']
belong=['Belong','属于']

synonym=[own,belong]
'''
同义词替换
'''
 
def synonym_replace(question,synonym):
    replace_word=[]
    for words in synonym:
        for i in words:
            if(i in question):
                question=question.replace(i,words[0])
                replace_word.append(i)
    return question,replace_word

synonym_replace('袭人的主人是谁',synonym)

'''
查询语句的处理
'''

def get_node(s,nodes):
    node=[h for h in nodes if h in s]
    return node
    
print(get_node('袭人的主人是谁',nodes))
print(get_node('贾宝玉的别称是绛洞花王吗',nodes))

def get_rela(s,relationship):
    rela=[r for r in relationship if r in s]
    return rela

get_rela('袭人Belong什么',relation)

def get_property(s,propertys):
    prop=[p for p in propertys if p in s]
    return prop

get_property('贾迎春的profile',propertys)

'''
查询模板编写
'''

def search(s,syn,nodes,relation,propertys,graph,output=None):
    node=get_node(s,nodes)
    rela=get_rela(s,relation)
    prop=get_property(s,propertys)
    n=len(node)
    r=len(rela)
    p=len(prop)
    if(all([n==1,r==0,p==0])):
        return find_node(graph,node[0],output=output)
    elif(all([n==1,r==0,p!=0])):
        if(prop[0]=='property'):
            tmp=find_node_property(graph,node[0],prop)['property'].split(' ')
            for t in tmp:
                res=[f for f in syn if f in t]
                if(res):
                    return res
                else:
                    return node[0]+'没有这个属性'                            
        else:
            return find_node_property(graph,node[0],prop)
    elif(all([n==1,r==1,p==0])):
        return find_node_from_rela(graph,node[0],rela[0])
    elif(all([n==2,r==0,p==0])):
        return find_rela(graph,node[0],node[1])
    elif(all([n==2,r==1,p==0])):
        return is_node_rela(graph,node[0],node[1],rela[0])
    else:
        return '查询的问题太复杂,暂时无能为力' 

4、测试

search('贾宝玉的别称是绛洞花王吗','',nodes,relation,propertys,graph,output=None) 
'贾宝玉Belong绛洞花王'

search('紫鹃和林黛玉是什么关系','',nodes,relation,propertys,graph,output=None) 
'林黛玉Own紫鹃'

search('跪求贾探春的简介','',nodes,relation,propertys,graph,output=None)
(b5974f6:Person {name:"贾探春",profile:"贾探春,贾政与妾赵姨娘所生,排行为贾府三小姐。她精明能干,有心机,能决断,连王夫人与凤姐都让她几分,有“ 玫瑰花”之诨名。她的封建等级观念特别强烈,所以对处于婢妾地位的生母赵姨娘轻蔑厌恶,冷酷无情。抄检大观园时,她为了在婢仆面前维护作主子的威严,“令丫环秉烛开门而待”,只许别人搜自己的箱柜,不许人动一下她丫头的东西。“心内没有成算的”王善保家的,不懂得这一点,对探春动手动脚的,所以当场挨了一巴掌。探春对贾府面临的大厦将倾的危局颇有感触,她想用“兴利除弊”的微小改革来挽救,但无济于事。最后贾探春远嫁他乡。"})

相关文章

  • 《红楼梦》人物关系知识图谱

    背景:红楼梦以人物众多,人物关系复杂著称,自己又是忠实的小红迷,于是趁着这个机会想把红楼梦的知识图谱尝试构建一下,...

  • 构建红楼梦人物关系知识图谱

    知识图谱构建步骤:数据获取、知识抽取、关系提取、图数据库构建和语义搜索(本质就是把检索的问题转换为查询语句) 知识...

  • 最全知识图谱介绍:关键技术、开放数据集、应用案例汇总

    1 知识图谱构建技术 本节首先给出知识图谱的技术地图,然后介绍知识图谱构建的关键技术,包括关系抽取技术、知识融合技...

  • KG

    一、中文知识图谱的构建 前情提要 知识图谱的本体学习术语抽取同义关系学习概念概念分类学关系学习非分类学关系学习公理...

  • 2020-01-09

    自动构建知识图谱 一、知识图谱相关概念 Google公司于2012年提出知识图谱(Knowledge Graph)...

  • Building Your Own Knowledge Grap

    从0开始构建你自己的知识图谱:一种两步式构造法 自动构建知识图谱的难点在于 实体和关系的长尾分布导致传统方法构造的...

  • 知识图谱学习笔记 -- 海贼王关系图谱

    这两天准备学习点知识图谱查询的知识,查看到 OpenKG 上发布了一个 海贼王人物关系知识图谱 , 作为 海米 决...

  • 知识图谱入门简介

    一、 知识图谱技术体系 知识图谱的构建主要涉及到知识建模、知识抽取、知识融合、知识存储、知识计算以及知识应用,具体...

  • 从具体案例了解知识图谱构建流程

    经济责任审计知识图谱构建流程总结。     自2012年Google提出“知识图谱”的概念以来,知识图谱就一直是学...

  • 2020-02-03

    语义计算、知识图谱与智能问答(实例) 本文,以医药知识图谱“神机医药”APP为例,简述如何通过“语义计算”构建知识...

网友评论

    本文标题:构建红楼梦人物关系知识图谱

    本文链接:https://www.haomeiwen.com/subject/sqglaxtx.html