知识图谱实战

news2024/11/16 8:37:39

一、知识图谱简单介绍

 

 

 

 

 

二、知识图谱的构建

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 三、知识图谱问答方案

NL2SQL:自然语言转为SQL语句

 

 

bulid_graph.py 

"""知识图谱"""
#三元组:实体-关系-实体   实体-属性-属性值

import re,json
from py2neo import Graph
from collections import defaultdict

"""读取三元组,并将数据写入neo4j"""

#连接图数据库
graph=Graph("http://localhost:7474",auth=("neo4j","Zmj123456!"))

attribute_data=defaultdict(dict)
relation_data=defaultdict(dict)
label_data={}

#有的实体后面有括号,里面的内容可以作为标签
#提取到标签后,把括号部分删除
def get_label_then_clean(x,label_data):
    if re.search("(.+)",x):
        label_string=re.search("(.+)",x).group()
        for label in ["歌曲","专辑","电影","电视剧"]:
            if label in label_string:
                x=re.sub("(.+)","",x)#括号内的内容删除掉,因为括号里面是特殊字符会影响cypher的语句运行
                label_data[x]=label
            else:
                x=re.sub("(.+)","",x)
    return x


#读取实体-关系-实体三元组文件
with open("data/01test.doc",encoding="utf8") as f:
    for line in f:
        head,relation,tail=line.strip().split('\t')#取出三元组
        head=get_label_then_clean(head,label_data)
        relation_data[head][relation]=tail

#读取实体-属性-属性值三元组
with open("data/01triplets_enti_attr_value.doc",encoding='utf8') as f:
    for line in f:
        entity,attribute,value=line.strip().split('\t')#取出三元组
        entity=get_label_then_clean(entity,label_data)
        attribute_data[entity][attribute]=value

#构建cypher语句
cypher=""
in_graph_entity=set()
for i,entity in enumerate(attribute_data):
    #为所有的实体增加一个名字属性
    attribute_data[entity]["NAME"]=entity
    #将一个实体的所有的属性拼接成一个类似于字典的表达式
    text="{"
    for attribute,value in attribute_data[entity].items():
        text+="%s:\'%s\',"%(attribute,value)
    text=text[:-1]+"}"#最后一个逗号替换成大括号
    if entity in label_data:
        label=label_data[entity]
        #带标签的实体构造语句
        cypher+="CREATE (%s:%s %s)"%(entity,label,text)+"\n"
    else:
        "不带标签的实体构造语句"
        cypher+="CREATE (%s %s)"%(entity,text)+"\n"
    in_graph_entity.add(entity)


#构造关系语句
for i in enumerate(relation_data):
    #有可能实体只有和其他实体的关系,但没有属性,为这样的实体增加一个名称属性,便于在图上认出
    if head not in in_graph_entity:
        cypher += "CREATE (%s {NAME:'%s'})"%(head,head)+'\n'
        in_graph_entity.add(head)
    for relation,tail in relation_data[head].items():
        #有可能实体只有和其他实体的关系,但没有属性,为这样的实体增加一个名称属性,便于在图上认出
        if tail not in in_graph_entity:
            cypher +="CREATE (%s {NAME:'%s'})"%(tail,tail)+"\n"
            in_graph_entity.add(tail)

        #关系语句
        cypher +="CREATE (%s)-[:%s]->(%s)"%(head,relation,tail)+"\n"

print(cypher)

#执行建表脚本
graph.run(cypher)

#记录我们图谱里都有哪些实体,哪些属性,哪些关系,哪些标签
data=defaultdict(set)
for head in relation_data:
    data["entitys"].add(head)
    for relation,tail in relation_data[head].items():
        data["relations"].add(relation)
        data["entitys"].add(tail)

for enti,label in label_data.items():
    data["entitys"].add(enti)
    data['labels'].add(label)

for enti in attribute_data:
    for attr,value in attribute_data[enti].items():
        data['entitys'].add(enti)
        data['attributes'].add(attr)

data=dict((x,list(y))for x,y in data.items())
with open('data/kg_schema.json','w',encoding='utf8') as f:
    f.write(json.dumps(data,ensure_ascii=False,indent=2))

graph_qa_base_on_sentence_match.py
"""使用文本匹配方式进行知识图谱的应用"""

import itertools,json
import re

import pandas
from py2neo import Graph
from collections import defaultdict

class GraphQA:
    def __init__(self):
        self.graph=Graph("http://localhost:7474",auth=("neo4j","Zmj123456!"))
        schema_path="kg_schema.json"
        templet_path="question_templet.xlsx"
        self.load(schema_path,templet_path)
        print('知识图谱问答系统加载完毕!\n=================')

    #加载模板
    def load(self,schema_path,templet_path):
        self.load_kg_schema(schema_path)
        self.load_question_templet(templet_path)
        return

    #加载图谱信息
    def load_kg_schema(self,path):
        with open(path,encoding='utf8') as f:
            schema=json.load(f)
        self.relation_set=set(schema['relations'])
        self.entity_set=set(schema['entitys'])
        self.label_set=set(schema['labels'])
        self.attribute_set=set(schema['attributes'])
        return

    #加载模板信息
    def load_question_templet(self,templet_path):
        dataframe=pandas.read_excel(templet_path)
        self.question_templet=[]
        for index in range(len(dataframe)):
            question=dataframe["question"][index]
            cypher=dataframe['cypher'][index]
            cypher_check=dataframe["check"][index]
            answer=dataframe["answer"][index]
            self.question_templet.append([question,cypher,json.loads(cypher_check),answer])
        return

    #获取问题中谈到的实体,可以使用基于词表的方式,也可以使用NER模型
    def get_mention_entitys(self,sentence):
        return re.findall("|".join(self.entity_set),sentence)

    #获取问题中谈到的关系,也可以使用各种文本分类模型
    def get_mention_relations(self,sentence):
        return re.findall("|".join(self.relation_set),sentence)

    #获取问题中谈到的属性
    def get_mention_attributes(self,sentence):
        return re.findall("|".join(self.attribute_set),sentence)

    #获取问题中的谈到的标签
    def get_mention_labels(self,sentence):
        return re.findall("|".join(self.label_set),sentence)

    #对问题进行预处理,提取需要的信息
    def parse_sentence(self,sentence):
        entitys=self.get_mention_entitys(sentence)
        relations=self.get_mention_relations(sentence)
        labels=self.get_mention_labels(sentence)
        attributes=self.get_mention_attributes(sentence)
        return{
            "%ENT%":entitys,
            "%REL":relations,
            "%LAB%":labels,
            "%ATT%":attributes
        }

    #将提取到的值分配到键上
    def decode_value_combination(self,value_combination,cypher_check):
        res={}
        for index,(key,required_count) in enumerate(cypher_check.items()):
            if required_count==1:
                res[key]=value_combination[index][0]
            else:
                for i in range(required_count):
                    key_num=key[:-1]+str(i)+"%"
                    res[key_num]=value_combination[index][i]
        return res

    #对于找到了超过模板中需求的实体数量的情况,需要进行排列组合
    #info:{"%ENT%":["周杰伦","方文山"],“%REL%”:["作曲"]}
    def get_combinations(self,cypher_check,info):
        slot_values=[]
        for key,required_count in cypher_check.items():
            slot_values.append(itertools.combinations(info[key],required_count))
        value_combinations=itertools.product(*slot_values)
        combinations=[]
        for value_combination in value_combinations:
            combinations.append(self.decode_value_combination(value_combination,cypher_check))
        return combinations

    #将带有token的模板替换成真实词
    #string:%ENT1%和%ENT2%是%REL%关系吗
    #combination:{“%ENT1%”:"word1","%ENT2%":"word2"}
    def replace_token_in_string(self,string,combination):
       for key,value in combination.items():
           string = string.replace(key,value)
       return string

    #对于单条模板,根据抽取到的实体属性信息扩展,形成一个列表
    #info:{"%ENT%":["周杰伦","方文山"],“%REL%”:["作曲"]}
    def expend_templet(self,templet,cypher,cypher_check,info,answer):
        combinations=self.get_combinations(cypher_check,info)
        templet_cypher_pair=[]
        for combination in combinations:
            replaced_templet=self.replace_token_in_string(templet,combination)
            replaced_cypher=self.replace_token_in_string(cypher,combination)
            replaced_answer=self.replace_token_in_string(answer,combination)
            templet_cypher_pair.append([replaced_templet,replaced_cypher,replaced_answer])
        return templet_cypher_pair

    #验证从文本中提取到的信息是否足够填充模板,如果不够就跳过,节省运算速度。
    #如模板:%ENT%和%ENT%是什么关系?   这句话需要两个实体才能填充,如果问题中只有一个,该模板无法匹配
    def check_cypher_info_valid(self,info,cypher_check):
        for key,required_count in cypher_check.items():
            if len(info.get(key,[]))<required_count:
                return False
        return True

    #根据提取到的实体,关系等信息,将模板展开成待匹配的问题文本
    def expand_question_and_cypher(self,info):
        templet_cypher_pair=[]
        for templet,cypher,cypher_check,answer in self.question_templet:
            if self.check_cypher_info_valid(info,cypher_check):
                templet_cypher_pair+=self.expand_templet(templet,cypher,cypher_check,info,answer)
        return templet_cypher_pair

    #距离函数,文本匹配的所有方法都可以使用
    def sentence_similarity_function(self,string1,string2):
        print("计算  %s  %s"%(string1,string2))
        jaccard_distance=len(set(string1)&set(string2))/len(set(string1)|set(string2))
        return jaccard_distance

    #通过问题匹配的方式确定匹配的cypher
    def cypher_match(self,sentence,info):
        templet_cypher_pair=self.expand_question_and_cypher(info)
        result=[]
        for templet,cypher,answer in templet_cypher_pair:
            score=self.sentence_similarity_function(sentence,templet)
            result.append([templet,cypher,score,answer])
        result=sorted(result,reverse=True,key=lambda x:x[2])
        return result

    #解析结果
    def parse_result(self,graph_search_result,answer,info):
        graph_search_result=graph_search_result[0]
        #关系查找返回的结果形式较为特殊,单独处理
        if "REL" in graph_search_result:
            graph_search_result['REL']=list(graph_search_result["REL"].types())[0]
        answer=self.replace_token_in_string(answer,graph_search_result)
        return answer

    #对外提供问答接口
    def query(self,sentence):#sentence:谁导演的不能说的秘密
        info=self.parse_sentence(sentence)#信息抽取
        templet_cypher_score=self.cypher_match(sentence,info)
        for templet,cypher,score,answer in templet_cypher_score:
            graph_search_result=self.graph.run(cypher).data()
            #最高分命中的模板不一定在图上能找到答案,当不能找到答案时,运行一个搜案语句,找答案时停止查找后面的模板
            if graph_search_result:
                break
            answer=self.parse_resule(graph_search_result,answer,info)

    #通过问题匹配的方式确定匹配的cypher
    def cypher_match(self,sentence,info):
        templet_cypher_pair=self.expand_question_and_cypher(info)
        result=[]
        for templet,cypher,answer in templet_cypher_pair:
            score=self.sentence_similarity_function(sentence,templet)
            result.append([templet,cypher,score,answer])
        result=sorted(result,reverse=True,key=lambda x:x[2])
        return result


if __name__=="__main__":
    graph=GraphQA()
    res=graph.query("谁导演的不能说的秘密")
    print(res)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/697426.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

shell脚本检测进程的CPU内存占用率

使用方法&#xff1a; 把xxx替换为自己进程的名字&#xff0c;然后直接运行该脚本即可在当前目录下产生一个叫做memory_info.txt的文件&#xff0c;记录进程的CPU内存占用率信息。可以用来查看自己进程对系统资源的消耗情况。 #!/bin/bashprocess"xxx" output_file…

C#,数值计算——算术编码压缩技术与方法(Compression by Arithmetic Coding)源代码

算术编码的数据压缩 算术编码是无损和有损数据压缩算法中常用的一种算法。 这是一种熵编码技术&#xff0c;其中常见符号比罕见符号用更少的比特进行编码。与诸如霍夫曼编码之类的众所周知的技术相比&#xff0c;它具有一些优势。本文将详细描述CACM87算术编码的实现&#xf…

Uniapp_分包

前言&#xff1a;由于微信小程序的包只限制压缩不能超过2M&#xff0c;当开发的页面过多就要进行分包操作,tabbar页面不能进行分包其他页面可以 最多5个分包 不超过20M 第一步、找到这个位置 然后把这个代码复制进去 开启分包 "optimization" : {"subPackages&…

Linux系统【VS】Windows系统

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

FPS(CF、CS GO、PUBG、APEX、瓦罗兰) AI YOLOV5 自瞄 模型 权重

YOLOV5的各种AI自瞄权重&#xff0c;有需要的联系 联系方式 如果对上面的资源有需要&#xff0c;私聊或者留言或者进入下面项目了解详细内容 联系方式 加我时&#xff0c;请备注所需要的权重 https://gitee.com/wcx895278175/cf-ai-yolov5-self-aiming

【Oracle】springboot连接Oracle 集成mybatis、druid

目录 项目结构与库表数据pom.xmlapplication.yml实体类Mappercontroller接口测试 基于spring-boot 2.7.11&#xff0c;连接Oracle 11g 仅做一个简单的示例 特别说明&#xff08;不一定正确&#xff0c;还请指正&#xff09;&#xff1a;我Oracle也不熟&#xff0c;但据我观察发…

【Java高级语法】(二十三)系统辅助工具类:解析System类,一个系统操作与资源管理工具类~

Java高级语法详解之系统辅助工具类 1️⃣ 概念2️⃣ 优势和缺点3️⃣ 使用3.1 System类常用方法3.2 使用技巧 4️⃣ 应用场景&#x1f33e; 总结 1️⃣ 概念 Java的System类是Java标准库中一个重要且常用的类。它被设计用于提供与系统相关的操作和信息访问功能。System类的设计…

【算法系列之贪心算法III】leetcode135. 分发糖果

134. 加油站 力扣题目链接 在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发&#xff0c;开始时油箱为空。 给定…

创建临时文件mkstemp()和tmpfile()

有些程序需要创建一些临时文件&#xff0c;仅供其在运行期间使用&#xff0c;程序终止后即行删除。例如&#xff0c;很多编译器程序会在编译过程中创建临时文件。GNU C语言函数库为此而提供了一系列库函数。&#xff08;之所以有“一系列”的库函数&#xff0c;部分原因是由于这…

ASD光谱仪.asd格式光谱曲线文件转换为.txt格式的方法

本文介绍基于ViewSpec Pro软件&#xff0c;将ASD地物光谱仪获取到的.asd格式文件&#xff0c;批量转换为通用的.txt文本格式文件的方法。 ASD光谱仪是英国Malvern Panalytical公司研发的系列野外便携式全范围光谱辐射仪和光谱仪&#xff0c;可以获取地物的实时光谱信息。我们用…

Arch Linux 中的 AUR 是什么?您应该使用它吗?

Arch Linux AUR 存储库包含社区驱动的软件,如果您采取一些简单的预防措施,就可以安全使用。即使您不懂 shell 脚本,也可以使用一些指标来判断包是否安全。 AUR 是 Arch Linux 皇冠上的宝石之一,提供了数千个附加软件包。但是这个用户驱动的存储库使用起来安全吗,还是应该避…

你给企业创建百科了吗?5分钟带你看懂创建企业百度百科的实用技巧和注意事项

企业百度百科是一种企业在互联网上展示自身形象和产品的重要途径。通过在百度百科上创建企业页面&#xff0c;可以让更多的人了解企业的历史、文化、产品和服务等信息&#xff0c;提高企业知名度和品牌形象。分媒互动将介绍企业百度百科的创建方法和需要注意的事项。 一、企业百…

搭建IP代理池 - ProxyPool

前言 在爬虫开发中&#xff0c;我们经常会碰到ip封禁&#xff0c;访问限制的问题&#xff0c;今天主要分享个我在开发中用到过比较好用的ip代理池&#xff0c;希望有需要的小伙伴提供到帮助~ 简介 ProxyPool是一个简易高效的代理池&#xff0c;他可以在windows上搭配redis使…

【强化学习】常用算法之一 “SARSA”

作者主页&#xff1a;爱笑的男孩。的博客_CSDN博客-深度学习,活动,python领域博主爱笑的男孩。擅长深度学习,活动,python,等方面的知识,爱笑的男孩。关注算法,python,计算机视觉,图像处理,深度学习,pytorch,神经网络,opencv领域.https://blog.csdn.net/Code_and516?typeblog个…

飞控的安全性设计

针对安全性设计&#xff0c;就必须先考虑故障情况。一般来讲&#xff0c;飞控故障有以下几个方面&#xff1a; 1、通讯故障 飞行器与地面端&#xff08;遥控器或地面站等设备&#xff09;需要进行实时通信&#xff0c;如果通信发生故障&#xff0c;后果很严重&#xff0c;因此…

赛效:WPS文字(Word)中的页面背景如何删除

1&#xff1a;打开一个有背景颜色的文档。 2&#xff1a;在“页面布局”选项卡里点击“背景”&#xff0c;在下拉菜单里点击“删除页面背景”。 3&#xff1a;接下来我们看到&#xff0c;文档背景已经恢复了默认的颜色。 如果你想了解更多办公软件以及办公技巧&#xff0c;可以…

青大数据结构【2019】【五算法设计】

关键字: 简单选择排序、二叉树后序遍历 1) void Countsort(int A[],int B[],int n) {int i,j,count;for(i=0;i<n;i++){count=0;for(j=0;j<n;j++)if(A[j]<A[i])count++;B[count]=A[i];}} 2) 每个元素都要与n个元素(含自身)进行比较,故比较次数为n方 3) …

Redis之数据类型String、List、Hash、Set、Sorted Set(详细)

一、String数据类型 1、SET/GET/APPEND/STRLEN &#xff08;1&#xff09; APPEND &#xff08;2&#xff09; SET/STRLEN 2、 INCR/ DECR/INCRBY/DECRBY &#xff08;1&#xff09;INCR/ DECR &#xff08;2&#xff09; INCRBY/DECRBY INCRBY key increment&#xff1…

JavaWed第二章:HTML和CSS的知识制作静态网页

目录 前言 一.HTML和CSS的介绍 &#x1f496;HTML的基本框架 二.HTML常用标签大全 三.资源路径讲解 &#x1f496;路径 &#x1f496;图片 img标签讲解 &#x1f496;超链接标签讲解 四.CSS &#x1f496;CSS的引入方式 五.HTML页面布局 &#x1f496;盒子模型介绍 …

小米手机文件误删还有救,这10个工具请收好!

说到智能手机&#xff0c;小米以其令人印象深刻的功能和实惠的价格成为一个受欢迎的品牌。然而&#xff0c;与任何其他智能手机一样&#xff0c;小米设备上可能会由于各种原因而发生数据丢失。幸运的是&#xff0c;有多种恢复软件可以帮助您从小米设备中检索丢失或删除的数据。…