微内核操作系统采用了哪些技术,微内核方法设计操作系统的优点
KBQA问答系统的实现首先默认你已经学会了如何构建知识图谱,如何用sparql语言查询知识库中的知识。如果没有,请查看下面的链接。
D2RQ用于将关系数据库的信息转换成rdf文件。
用jena构建知识库tdb,然后学习如何查询相关知识。
源代码在GitHub上。
目录结构很简单:
知识图谱问答系统
/kbqa中有四个文件,它们是
Word_tag.py ##这个主要用于分词。
Question_temp.py ##这是一个问题模板
Question2sparql.py ##这个用来把问题变成sparql语句。
Query_main.py ##显然这是最终的查询文件。
另一个文件是:lsy.nt这是知识rdf的三元组,问答系统的知识源。
首先,把句子切割成单词,这是word_tag.py的工作
本文主要利用斯坦福大学的stanfordcorenlp。
在使用这个包之前,你应该先下载一些东西。
斯坦福CoreNLP官网下载
stanford-corenlp-full-2018-10-05
1.先下载红色按钮,解压,然后把下面下载的jar包放进去。
2.使用说明安装pip install stanfordcorenlp。
这里需要介绍的是,实现了一个类word,用token(标记)和pos(词性)两个属性来表示一个词汇。
Nlp.pos_tag(sentence)将返回元组列表,即单词及其词性。
这样就可以把句子分段了。
二、问题模板的构建首先基于知识库,我们可以有以下几个问题
littlejun叫什么名字?‘查查的年龄是多少?’,scc的用户名是什么?’、‘谁的年龄大于18岁?’,‘查查的电话号码是多少?’,‘小君的密码是什么?’] sparql的模板最终由以下模式组成
#问题模板prefix _ TEMP= prefix PS:http://soli cucu/person/# prefix US:3358 soli cucu/user/# prefix vocab:3358 soli cucu/vocab/ SPARQL _ select _ TEMP=U { prefix } SELECT DISTRICT { SELECT } WHERE { { expression } } 那么值得注意的是我们只需要完成SELECT和expression的填充即可。
它与这个确切的问题有关,所以我们要做的是,我们如何知道进来的问题属于哪个句子?
o(对象的正则表达式)是基于对象级的正则匹配,和python的正则表达式非常相似。
ab 是Literal(a) Literal(b)a* 是Star(Literal( a )(ab)(bb)*?is:a=literal( a )b=Literal( b )regex=plus(a b) star(b b,greedy=false)如上所述,Literal是一个Literal类,那些类支持一些基本的符号:连接的含义。
表示或,
python正则表达式的个数用加号()代替,表示一对多。
python正则表达式的*号换成了星号(),表示0到1以上。你可以选择是否采用贪婪模式。
因此,词汇的定义非常重要:
#定义一个继承谓词类W(谓词)的词汇类:# token的文字符号。属性def __init__(self,token=。“*”的位置词汇,位置=“。*):self . token=re . pile(token $ )self . pos=re . pile(pos $ )super(w,self)。_ _ init _ _ (self.match) #必不可少的def match(self,Word):m1=self . token . match(Word . token)m2=self . pos . match(Word . pos)谓词返回m1和m2的定义,这是一个继承了predict (from refo)的类,并定义了另一个正则匹配对象属性。
匹配功能,表面上,对于输入的词,必须同时满足标记和词性。
#定义一些规则,相当于正则表达式类Rule(object)的某个模式匹配的条件和条件的个数:#,以及动作回调函数def _ _ init _ _ (self,condition _ num,condition=none,action=None):assert condition和action self . condition=condition self . action=action self . condition _ num=condition _ numdef apply(self,Word_list):#因为有很多可能的条件,所以使用matches列表存储匹配=[]#使用条件查找匹配的单词。finditer使用yeild,就是每次找到一个就返回一个结果。寻找#可以理解为Finder返回的值可以在Finder中迭代m(self。condition,word _ list): i,j=m . span()matches . extend(word _ list[I:j])#要提取匹配的句子区间并画出来,可能还有return self等其他杂词。行动(匹配)和自我。条件编号规则类。首先,必须有两个参数,condition和action,以指示该规则的适用条件(对象正则表达式)和操作(回调函数)。
注意里面finditer返回的对象是Match对象,匹配范围由span()获取
当谓词定义好了,规则定义好了,就可以写匹配规则了。
#疑问代词关键字whowhatwhat=(W( what ) W( what ))whoser=(W( who ) W( of )number _ entity=W(pos= CD )# attribute关键字name=W( name )phone=W( phone )age=W( age )password=W( password )attr _ noun=(username name phone age password)# Common _ noun=W(pos=pos _ Common _ noun)看上面。定义的词汇,什么可以匹配大写或小写,因为what=(w ("what") w ("what "))
所以一个谓词,可以是多个谓词的OR,也可以只有一个谓词,匹配一个固定的单词。
Number _ entity=w (pos="CD ")这里定义了一个数值谓词。因为我们不关注它的值,所以把属性指定为“CD”就好了。至于为什么是“cd”
详见standfordcorenlp的英文词性标注。
Attr_noun:表示属性名词。在这个知识库中,主要涉及的属性名词如上。
规则定义
rules=[# sb-uname的名字是什么?#什么是sb-uname时代?# s b-uname的用户名是什么?# sb-uname的电话号码是多少?# sb-name的密码是什么?Rule(condition_num=4,condition=what Star(Any(),greedy=False) attr_noun Star(Any(),greedy=False)of common _ noun Star(Any(),greedy=False),action=question set . process _ attr _ noun),#谁的年龄大于18?Rule(condition_num=4,condition=who attr _ noun Star(Any(),greedy=False) compare Star(Any(),greedy=False)number _ entity Star(Any(),Greedy=False),action=questions set。Who _ age _ compare)]这里只有两个规则:第一个匹配上面五个问题,第二个匹配上面的问题。
第一个参数condition_num:这是我们在条件中关注的单词数。比如我们要匹配的第一个是what attr_noun(即姓名、年龄等五个名字中的一个),那么common_noun就是3。
第二个参数条件:
这里可以看出,加了几个谓语,也就是前面说的,表示连接,所以条件表达式的意思是
任何句型都是:什么/什么…姓名/年龄/用户名/密码/电话… of comommn _ noun …
所以才符合上面那句话。
第三个参数动作:
回调函数,rule中有这样一个属性,是apply后匹配就会调用的函数。
这里,它指向一个问题集。Process _ attr _ noun函数,可以继续确定是哪个规则。
提取词汇,填充模板
# 1 sb-uname叫什么?def what _ name(word _ list):# if(len(word _ list)):# print(成功匹配问题)# for w in word _ list:# print(w . token,end= )sparql=Noneselect=?颠倒的w的"名称"(单词列表):#找到第一个普通名词if(w . pos==pos _ common _ noun):e= PS:{ person } vocab:person _ name?姓名格式(person=w . token)SPARQL=SPARQL _ select _ temp。format(prefix=prefix _ temp,select=select,expression=e)breakreturn sparql首先是对挑选赋值,确定要查询的变量,比如这里就是?名字就是要查询的变量
最终要的是确定表达式的变量,这里是:
ps:{person} vocab:person_name ?name
表示某人的名字是什么,这个某人就会是单词列表从后往前的一个名词,所以,找到之后,就可以破裂退出了。
然后返回,对应的查询语言语句
三、把句子转化为查询语言语句def get _ SPARQL(句子):word _ list=word _ tag。对于question _ temp中的规则,get _ word _ list(sentence)query=None queries _ dict=dict()。规则:查询,数量=规则。apply(word _ list)if(query not None):query _ dict[num]=query if len(queries _ dict)==0:return None elif len(queries _ dict)==1:#要转化为目录才可以用索引访问返回列表(查询_字典。values())[0]否则:# key就是对多元组的排序指定列项目的名字随便,表示列表的元素,项目[0]表示那个值sorted _ dict=sorted(query _ dict。ITER项(),key=lambda项:item[0],reversed=True)返回sorted_dict[0][1]上面,就是对句子去匹配每一个规则,放到一个字典里面。
如果长度为0,那么就是没有匹配,如果长度为一那么就是只匹配到一个句子,直接取第0个值,但是注意要转化为列表的形式才可以用索引访问。
如果长度大于一的时候,就对字典排序,按照键的大小排序,从大到小,也就是取匹配到关键字最多的一个。
四、访问端点,显示查询结果包装器( http://localhost:3030/db/query )。setreturnformat(JSON)if _ _ name _ _= _ _ main _ _ :# sentence= SCC的用户名是什么?while True:句子=输入(请输入问题?input quit to leave n )# print( question:,sentence)if(sentence== quit ):break str _ SPARQL=q2s。get _ SPARQL(句子)if(str _ SPARQL not None):SPARQL。set query(str _ SPARQL)results=SPARQL。查询().convert()head=results[ head ][ vars ]values=results[ results ][ bindings ]#存储的结果if(len(values)==0):print(无相关答案)else:print(答案为:,end= )为v in values: #对于所有值,通过变量名获取其值对于头中的varname:print(v[varname][ value ])else:print(对不起,我不能理解你的意思)这里要注意的就是,我们查询的变量名存在结果["head"]["vars"]
对应的值存在结果["结果"]["绑定"]结果是一个个字典