菜哥学知识图谱(通过“基于医疗知识图谱的问答系统”)(八)(知识存储)

上接菜哥学知识图谱(通过“基于医疗知识图谱的问答系统”)(七)(知识图谱设计、知识抽取1)
先跳过机器学习方式抽取知识。在人工标注信息后,将知识录入到图数据库中。
1.人工知识抽取
将“出行指南”模块的第一部分“车票”的内容先复制下来。
菜哥学知识图谱(通过“基于医疗知识图谱的问答系统”)(八)(知识存储)_第1张图片
人工标注信息(这是个csv文件):
菜哥学知识图谱(通过“基于医疗知识图谱的问答系统”)(八)(知识存储)_第2张图片
2.将知识写入到图数据库中。先要把vc++14装上,不装还是不方便。
代码:

# 读取csv文件,生成Cypher语言并写入图数据库
# -*- coding: utf-8 -*-
import csv
from py2neo import Graph, Node


class MAIN:
    def __init__(self):
        # 创建实例
        self.g = Graph(
            host="127.0.0.1",  # neo4j 搭载服务器的ip地址,ifconfig可获取到
            http_port=7474,  # neo4j 服务器监听的端口号
            user="neo4j",  # 数据库user name,如果没有更改过,应该是neo4j
            password="neo4jzl")

    def write(self, csvfile, message):  # 写入csv数据
        newfile = open(csvfile, 'a+', newline='')
        filewriter = csv.writer(newfile)
        filewriter.writerows(message)

    def open(self, file):
        self.file = file
        with open(self.file, 'r') as f:
            self.reader = csv.reader(f)
            self.messages = list(self.reader)
            print(self.messages)

    def tra_attribute(self):  # 经测试,neo4j的类型名、属性内容可以是中文,但属性名必须是英文。因此先要把所有的属性名全部翻译成英文。
        list_attribute = []
        for messages in self.messages[1:]:
            for message in messages:
                if r'#' in message:
                    for i in message.split(r'@@'):
                        if r'#' in i:
                            node_attribute = i.split(r'#')
                            list_attribute.append(node_attribute[0])
        list_attribute = list(set(list_attribute))
        lists_attribute = []
        for i in list_attribute:
            j = []
            j.append(i)
            j.append('')
            lists_attribute.append(j)
        self.write(csvfile='C:\\chouquxinxi\\出行指南\\属性名.csv', message=lists_attribute)
        # 后面需要手动打开该文件,手动翻译属性名,写在第二列。弄了半天自动翻译没弄成,有点尴尬。

    def cypher_make_send(self):  # 核心方法
        # 读取翻译结果
        dict_attribute = {}
        with open('C:\\chouquxinxi\\出行指南\\属性名.csv', 'r') as f:
            reader = csv.reader(f)
            for l in reader:
                dict_attribute[l[0]] = l[1]

        # 判断每行数据信息
        for message in self.messages[1:]:
            if len(message) == 2 or message[2] == '':  # 2列信息描述结点
                node_type = message[0]       # 节点类型
                node_attributes = message[1]    # 节点属性
                dict_node_attribute = {}  # 属性字典,下面做这个字典
                for i in node_attributes.split(r'@@'):
                    node_attribute = i.split(r'#')     # 节点属性分段,node_attribute[0]属性名,node_attribute[1]属性值
                    node_attribute[0] = dict_attribute[node_attribute[0]]  # 属性名翻译为英文
                    dict_node_attribute[node_attribute[0]] = node_attribute[1]  # 转为字典
                # print(dict_node_attribute)
                if '名称' in node_attributes:  # 如果这一条信息里面有“名称”字样,则说明该信息是对单个节点进行操作。
                    # 准备这么操作:建立该节点,然后一条属性一条属性的添加
                    namevalue = dict_node_attribute.pop('name')  # 删除要删除的键值对"name",返回值是删除的值name的内容。剩下的就是需要创建或修订的其他属性
                    cypher = "MERGE (m:%s { name: '%s' })  RETURN m.name" % (node_type, namevalue)
                    # 上一句的意思是,如果该节点类型、名称不存在,则创建该节点。
                    re = self.g.run(cypher).data()
                    print("-->节点<--新建节点:%s" % (re))
                    for key, value in dict_node_attribute.items():
                        cypher = "MERGE (m:%s { name: '%s' })   \
                                ON MATCH SET m.%s = '%s'    \
                                RETURN m.%s" % (node_type, namevalue, key, value, key)
                        re = self.g.run(cypher).data()
                        print("-->节点<--'%s':新建或修改属性:%s" % (namevalue, re))
                else:  # 如果不包含“名称”字样,则说明该信息是所有该类型的节点进行操作
                    for key, value in dict_node_attribute.items():
                        cypher = "MERGE (m:%s)              \
                                ON MATCH SET m.%s = '%s'     \
                                RETURN m.%s" % (node_type, key, value, key)
                        re = self.g.run(cypher).data()
                        print("-->节点<--新建或修改属性:%s" % (re))

            elif len(message) == 3:  # 3列信息描述关系
                relationships = message[0]  # 关系
                dict_relationships = {}  # 关系字典,下面做这个字典
                if r'@@' in relationships:  # 如果包含分割符,说明包含属性,此时需要把属性读取出来
                    list_relationships = relationships.split(r'@@')
                    dict_relationships['type'] = list_relationships[0]  # 关系类型
                    for i in list_relationships[1:]:
                        relationships_attribute = i.split(r'#')
                        relationships_attribute[0] = dict_attribute[relationships_attribute[0]]  # 属性名翻译为英文
                        dict_relationships[relationships_attribute[0]] = relationships_attribute[1]  # 转为字典
                else:
                    dict_relationships['type'] = relationships

                node_start = message[1]  # 起节点
                dict_node_start = {}  # 起节点属性字典,下面做这个字典
                for i in node_start.split(r'@@'):
                    node1_attribute = i.split(r'#')
                    node1_attribute[0] = dict_attribute[node1_attribute[0]]  # 属性名翻译为英文
                    dict_node_start[node1_attribute[0]] = node1_attribute[1]  # 转为字典

                node_end = message[2]  # 止节点
                dict_node_end = {}  # 止节点属性字典,下面做这个字典
                for i in node_end.split(r'@@'):
                    node2_attribute = i.split(r'#')     # 节点属性分段,node_attribute[0]属性名,node_attribute[1]属性值
                    node2_attribute[0] = dict_attribute[node2_attribute[0]]  # 属性名翻译为英文
                    dict_node_end[node2_attribute[0]] = node2_attribute[1]  # 转为字典

                #下面开始写语句

                start_type = ''
                start_attribute = ''
                if 'type' in dict_node_start:  # 如果包含类型
                    start_type = ":%s" % (dict_node_start['type'])
                    dict_node_start.pop('type')
                for key, value in dict_node_start.items():
                    start_attribute = start_attribute + "%s:'%s'" % (key, value) + ','
                if start_attribute == '':
                    cypher_node_start = start_type
                else:
                    cypher_node_start = start_type+'{'+start_attribute[:-1]+'}'  #[:-1]把最后一个逗号去掉

                end_type = ''
                end_attribute = ''
                if 'type' in dict_node_end:  # 如果包含类型
                    end_type = ":%s" % (dict_node_end['type'])
                    dict_node_end.pop('type')
                for key, value in dict_node_end.items():
                    end_attribute = end_attribute + "%s:'%s'" % (key, value) + ','
                if end_attribute == '':
                    cypher_node_end = end_type
                else:
                    cypher_node_end = end_type + '{' + end_attribute[:-1] + '}'

                relationships_type = ''
                relationships_attribute = ''
                if 'type' in dict_relationships:  # 如果包含类型
                    relationships_type = ":%s" % (dict_relationships['type'])
                    dict_relationships.pop('type')
                for key, value in dict_relationships.items():
                    relationships_attribute = relationships_attribute + "%s:'%s'" % (key, value) + ','
                if relationships_attribute == '':
                    cypher_relationships = relationships_type
                else:
                    cypher_relationships = relationships_type + '{' + relationships_attribute[:-1] + '}'

                cypher = " MATCH(m" + cypher_node_start + "),(n" + cypher_node_end + ")  MERGE(m)-[r" + cypher_relationships +"]->(n)   RETURN m,n,r"
                re = self.g.run(cypher).data()
                print("-->关系<--新建或修改关系:%s" % (re))

if __name__ == '__main__':
    file = 'C:\\chouquxinxi\\出行指南\\车票.csv'
    read = MAIN()
    read.open(file=file)
    #read.tra_attribute()  #第一步,运行完毕后手动翻译
    read.cypher_make_send()  #第二步

几个重点:
1.tra_attribute()方法是将中文属性名写入一个文件,然后需要手动翻译一下,中文翻译为英文。有时间会做一个自动翻译方法。
2.类型名不能带引号。
3.知识融合问题。主要用到cypher语言“MERGE”关键字,该关键字的作用是已有(属性名、关系)的话修改,没有的话创建。这样就把知识融合、知识存储统一到一句cypher语句中了,不用通过程序反复查询、判断。变量cypher是最终的语句,可以打印输出,查看一下生成的语句的构成。
其他的注释的比较清楚,就不多说。

运行注意事项:
1.需要先修改代码里面的几个文件车票.csv、属性名.csv地址,改为放到本机文件的位置。
2.提前打开neo4j.bat console,打开数据库。可提前清空该数据库中的内容,具体语句CSDN可搜索。
3.最下面第一步我已经翻译过了,可以直接运行第二步。
代码是通用代码,不指定具体的内容形式,只要按车票.csv中的格式标注,任何内容都可以存贮到图知识库中。

文章不再更新……最尴尬的是论文拿去了,职称评审组的说我根据的职责,需要考国家计算机考试……

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