具体实施方式
以下结合实施例和说明书附图,详细说明本发明的实施过程。
本发明的基于本体和受限自然语言处理的关系数据库查询方法,包括以下6个步骤:
1)本体转PCDO图数据结构:本体(Ontology)是由万维网联盟(W3C)提出的用于描述万维网上各类资源信息的一种规范,本发明中的本体是根据关系数据库的模式信息,按照一定规则构建出来的,用于描述数据库中的各类资源信息,本体构建规则如下:
(a)本体中构建类(class):对于关系数据库中的所有关系表,在本体中分别构建出一个对应的类,类和关系表一一对应;
(b)本体中构建数据类型属性(dataTypeProperty):对于每一张关系表t中的每一列c,在本体中分别构建出一个c对应的数据类型属性,该数据类型属性所属的类即为关系表t所对应的类;
(c)本体中构建对象属性(objectProperty):对于关系数据库中的每一个关联两张关系表t1、t2的外键f,在关系表t1、t2对应的两个类之间,构建出一个f对应的对象属性,该对象属性连接的两个类即为关系表t1、t2对应的类。
本体中仅包含类、对象属性和数据类型属性。为了充分利用本体中的信息,我们提出了PCDO图数据结构(下称PCDO图)。PCDO图主要包含两种子数据结构即结点(Node)和边(Edge)。
结点的数据结构如表1所示:
表1结点的数据结构
结点的数据结构中包含Type、Name、Edges、Keyword、Value、KeywordType六个属性。Type属性用于标识结点的类型,结点类型包括类结点(C_Node)和属性结点(P_Node);Name属性用于标识结点的名称;Edges属性用于记录与当前结点相邻的所有的边;Keyword属性、Value属性、KeywordType属性在步骤1)的转换过程中全部置为空,步骤4)中详细描述这三个属性的初始化过程。
边的数据结构如表2所示:
表2边的数据结构
边数据结构中包含Type、Name、Node1、Node2四个属性。Type属性用于标识边的类型,边的类型包括数据类型属性边(D_Edge)和对象属性边(O_Edge);Name属性用于标识边的名称;Node1、Node2两个属性用于记录当前边连接的两个结点。因为PCDO图是无向图,所以Node1和Node2两个属性的属性值是可交换的。
本体到PCDO图的转换步骤:
(1)类结点(C_Node)的转换:本体中所有的类分别转换为一个结点,结点的Type属性设置为“C_Node”,结点的Name属性设置为对应类的名称,结点的Edges属性设置为空;
(2)属性结点(P_Node)的转换:本体中所有的数据类型属性分别转换成一个结点,结点的Type属性设置为“P_Node”,结点的Name属性设置为对应的数据类型属性的名称,结点的Edges属性设置为空;
(3)数据类型属性边(D_Edge)的转换:在属性结点P以及该属性结点所属的类结点C之间添加一条边,边的Type属性设置为“D_Edge”,边的Node1、Node2属性分别设置为P、C,数据类型属性边的Name属性设置为“hasProperty”,分别在结点P和结点C的Edges属性中添加当前转换得到的数据类型属性边;
(4)对象属性边(O_Edge)的转换:本体中的所有对象属性分别转换成它连接的两个类结点C1、C2之间的一条边,边的Type属性设置为“O_Edge”,边的Node1、Node2属性分别设置为C1、C2,边的Name属性设置为对应的对象属性的名称,分别在结点C1、C2的Edges属性中添加当前转换得到的对象属性边。
2)构建分词专用词典和关键词索引:
遍历数据库中的所有关系表,依次读取关系表中的每一条记录,将记录值写入到词典中,同时将该记录值作为键,将该记录值在数据库中对应的关系表名和列名作为值,组成键值对,作为关键词索引。本发明的一个优选实施例中,非关系型数据库采用MongoDB数据库,键值对存入到MongoDB数据库中,作为关键词索引。当然,本发明方法并不限于采用MongoDB数据库,所有非关系型(NoSQL)数据库均可在此使用。
键值对的结构及实例如下表3所示。例如“学生”表中“姓名”这一列下有一条记录为“张三”,当读取到“张三”这条记录时,将“张三”作为键(key),TableName属性设置为“张三”对应的关系表名“学生”,ColumnName属性设置为“张三”对应的列的列名“姓名”,组成键值对,存入关键词索引中。词典构建完成后以文件的形式保存在磁盘中,每次用到该词典时则去磁盘中相应位置读取。构建分词专用词典的是为了从用户输入的自然语言查询中分解出关键词。
表3键值对结构及实例
遍历每一张关系表的过程中,同时将关系表的表名和所有列名分别作为键,构造出表3所示的键值对,存入到关键词索引中:对于关系表的表名,将TableName属性设置为“table”,将ColumnName属性设置为对应关系表的表名;对于关系表的列名,将TableName属性设置为“column”,将ColumnName属性设置为对应列的列名。
另外,一个关键词可能对应数据库中多个元素,例如上述“张三”也可能对应另一张表的另一列,也需要将这个键值对存入到关键词索引中。当用户查询“张三”时,通过查询关键词索引,可以迅速得到“张三”这个词对应的所有表名和列名。
3)利用专用词典进行分词:***接收到用户自然语言查询后,利用步骤2)中构建出的专用词典将自然语言分解为多个有意义的关键词;
4)结合图2说明查询空间的构建:对步骤3)中分解出的每个关键词,通过查询关键词索引,可以得到该词在数据库中对应的所有的关系表名和列名。根据步骤1),一个关系表名对应本体中的一个类,该类对应PCDO图中的一个类结点;关系表中的一个列名对应本体中的一个数据类型属性,该数据类型属性也对应PCDO图中的一个属性结点。当一个关键词对应多个关系表名和列名时,也就对应到PCDO图中的多个结点。下面将关键词对应PCDO图中的结点称为该关键词的映射结点。
映射结点的Keyword属性置为相应的关键词。若对于一个关键词有多个映射结点,用Value属性进行区分,Value取不同的编号即可。KeywordType属性包括“table”、“column”、“value”三个值,根据关键词索引来确定。若关键词索引中的TableName值为“table”,则KeywordType属性设置为“table”;若关键词索引中的TableName值为“column”,则KeywordType属性设置为“column”;其他情况下KeywordType属性设置为“value”。
将所有关键词对应的所有映射结点所属的连通分量从步骤1)中构建的PCDO图中提取出来,作为查询空间。因为查询空间一定为PCDO图的一个子集,且通过关键词索引找到所有映射结点所属的连通分量后,可以有效的缩小搜索范围。
5)结合图3说明连通子图搜索方法:根据步骤4)中构建出的查询空间,搜索包含所有关键词的连通子图,主要步骤如下:
a)随机选择查询空间中的一个没有处理过的连通分量,找到该连通分量中的所有映射结点,放入到集合X中。
b)如果集合X中存在n(n≥2)个映射结点Node1、Node2…Noden的Keyword属性相同,则根据Value属性的不同将集合X扩展成n个集合X1、X2…Xn,然后将X中除Node1、Node2…Noden之外的其他所有映射结点添加到X1、X2…Xn中,并删除集合X。
c)对X1、X2…Xn重复重复步骤b),直到每一个集合中的每一个映射结点的Keyword属性都不一样,最终得到m个不可再扩展的集合;
d)任意选择m个集合中的一个集合记为W,任意选择一个映射结点作为初始结点做广度优先搜索(BFS);
e)在BFS遍历过程中,如果遇到新的映射结点,则将此结点到初始结点的路径记录在集合Set中,并将新遇到的映射结点从W中删除;
f)重复e),直到集合W中所有映射结点都遍历完成,此时集合Set中的记录了将W中所有映射结点连接到一起的结点和边,即搜索到了一个关联W中所有映射结点的路径,且该路径是步骤1)中构建出的PCDO图的一个子集,下面将这样的连通路径称为PCDO子图;
g)重复d)直至所有的集合处理完毕;
h)重复a),直至所有的子查询空间处理完毕;
i)对得到的所有PCDO子图进行排序,按其包含的关键词的个数从大到小进行排序,对于包含关键词数相同的PCDO子图,则再根据所包含的边数从小到大进行排序,最后选择排序最靠前的k个PCDO子图,k需要根据具体数据库的大小确定一个合适的值,或由用户指定,这里仅代表一个合适的数;
6)生成SQL语句:根据步骤5)中得到了k个PCDO子图,分别将PCDO子图转换成SQL语句,SQL语句格式如下:
select<查询内容>
from<数据表>
where<查询条件>
PCDO子图到SQL的转换规则:
a)select子句中填入“*”,表示将数据库中的符合查询条件的所有列全部返回给用户;
b)from子句根据PCDO子图中的所有类结点,填入对应的关系表;
c)where子句根据PCDO子图的对象属性边,填入对应的外键关系(没有对象属性边则不填);
d)where子句根据PCDO子图中的属性结点,填入属性结点对应的值。
上述SQL语句生成后,通过数据库查询接口对数据库进行查询,最终将结果返回给用户。
以下结合一个简化的应用实例,详细说明本发明的实施过程:
1)本体转PCDO图:本实例所涉及的关系数据库是一个记录学生选课相关信息的数据库,数据中包含如下信息:
关系表:学生、选课、课程、学院
列名:学生.姓名、学生.学号、选课.课程代号、选课.学号、课程.院系代号、课程.课程代号、学院.院系代号、学院.院系备注
外键:选课.学号=学生.学号、选课.课程代号=课程.课程代号、课程.院系代号=学院.院系代号
因此从该关系数据库的模式信息中抽取出的本体是一个描述学生选课相关信息的本体。本体中包含的详细信息如下:
类:学生、选课、课程、学院;
数据类型属性:学生_姓名、学生_学号、选课_课程代号、选课_学号、课程_院系代号、课程_课程代号、学院_院系代号、学院_院系备注;
对象属性:学生_学号_选课_学号、选课_课程代号_课程_课程代号、课程_院系代号_学院_院系代号。
从关系模式转换得到的本体如下:
<?xml version="1.0"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns="http://www.project.com/d2o_owl#"
xml:base="http://www.project.com/d2o_owl">
<owl:Ontology rdf:about=""/>
<owl:ObjectProperty rdf:ID="选课_学号_学生_学号">
<rdfs:range rdf:resource="#学生"/>
<rdfs:domain rdf:resource="#选课"/>
</owl:ObjectProperty>
<owl:DatatypeProperty rdf:ID="选课_学号">
<rdfs:range rdf:resource="http://www.project.com/d2o_owl#字符串型"/>
<rdfs:domain rdf:resource="#选课"/>
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID="课程_课程代号">
<rdfs:range rdf:resource="http://www.project.com/d2o_owl#字符串型"/>
<rdfs:domain rdf:resource="#课程"/>
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID="选课_课程代号">
<rdfs:range rdf:resource="http://www.project.com/d2o_owl#字符串型"/>
<rdfs:domain rdf:resource="#选课"/>
</owl:DatatypeProperty>
<owl:Class rdf:ID="选课"/>
<owl:DatatypeProperty rdf:ID="学生_学号">
<rdfs:range rdf:resource="http://www.project.com/d2o_owl#字符串型"/>
<rdfs:domain rdf:resource="#学生"/>
</owl:DatatypeProperty>
<owl:Class rdf:ID="课程"/>
<owl:DatatypeProperty rdf:ID="课程_院系代号">
<rdfs:range rdf:resource="http://www.project.com/d2o_owl#字符串型"/>
<rdfs:domain rdf:resource="#课程"/>
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID="学生_姓名">
<rdfs:range rdf:resource="http://www.project.com/d2o_owl#字符串型"/>
<rdfs:domain rdf:resource="#学生"/>
</owl:DatatypeProperty>
<owl:Class rdf:ID="学生">
</owl:Class>
<owl:ObjectProperty rdf:ID="选课_课程代号_课程_课程代号">
<rdfs:range rdf:resource="#课程"/>
<rdfs:domain rdf:resource="#选课"/>
</owl:ObjectProperty>
<owl:ObjectProperty rdf:ID="课程_院系代号_学院_院系代号">
<rdfs:range rdf:resource="#学院"/>
<rdfs:domain rdf:resource="#课程"/>
</owl:ObjectProperty>
<owl:DatatypeProperty rdf:ID="学院_院系代号">
<rdfs:range rdf:resource="http://www.project.com/d2o_owl#字符串型"/>
<rdfs:domain rdf:resource="#学院"/>
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID="学院_院系备注">
<rdfs:range rdf:resource="http://www.project.com/d2o_owl#字符串型"/>
<rdfs:domain rdf:resource="#学院"/>
</owl:DatatypeProperty>
<owl:Class rdf:ID="学院"/>
<rdf:RDF>
通过步骤1)中转换规则将本体转成PCDO图数据结构,如图4所示。
本体中的类转换为PCDO图中的类结点,即图中椭圆结点;本体中的数据类型属性转换为PCDO图中的属性结点,即图中的矩形结点;属性结点与它对应的类结点用一条hasProperty边相连;本体中的对象属性转换为连接两个类结点的边。
2)构建分词专用词典和关键词索引,关键词索引部分内容如下:
“学生”:{
“TableName”:“table”,
“ColumnName”:“学生”}
“课程”:{
“TableName”:“table”,
“ColumnName”:“课程”}
“学院”:{
“TableName”:“table”,
“ColumnName”:“学院”}
“学号”:{
“TableName”:“column”,
“ColumnName”:“学生”}
“09131011”:{
“TableName”:“学生”
“ColumnName”:“学号”,}
其中,键“学生”对应的键值对中,TableName属性为“table”,ColumnName属性为“学生”,表示“学生”在此处对应的是一个关系表,且关系表名为“学生”;
键“学号”对应的键值对中TableName字段为“column”,ColumnName字段为“学生”,即表示“学号”在此处对应的是一个列名,且列名为“学号”;
键“09131011”对应的ColumnName字段为“学号”,TableName字段为“学生”,即表示键“09131011”在此处对应“学生”表中“学号”列下的一个具体值。
3)分词:例如,用户输入查询语句“查找学号为09131011的学生所选的课程的所属学院”,经过分词之后得到五个有意义的关键词:学号、09131011、学生、课程、学院。
4)构建查询空间:利用2)中得到的关键词索引,可以得到关键词与PCDO图中结点的映射关系如下:
表4关键词映射PCDO图结点
根据关键词和PCDO图结点的映射关系,构建出查询空间如图5所示(其中加粗的结点为关键词映射到的结点)。
5)连通子图搜索:根据搜索算法,找到PCDO图中能将所有关键词连接到一起的一个或多个连通子图,搜索得到的结果如图6所示。
6)根据PCDO子图到SQL的转换规则,生成SQL语句:
select子句填“*”,即得到select子句:select*;
from子句填入类结点对应的关系表名,即得到from子句:
from学生,选课,课程,学院;
where子句根据对象属性边转换为对应的外键,图6中三条对象属性边:学生_学号_选课_学号、选课_课程代号_课程_课程代号、课程_院系代号_学院_院系代号,分别转换,即得到where子句:where学生.学号=选课.学号and选课.课程代号=课程.课程代号and课程.院系代号=学院.院系代号
最后处理属性结点:“09131011”的映射结点为“学生_学号”,转换后得到学生.学号=“09131011”,添加到where子句中。
最终生成的SQL语句为:
select*
from学生,选课,课程,学院
where学生.学号=选课.学号and选课.课程代号=课程.课程代号and课程.院系代号=学院.院系代号and学生.学号=“09131011”
SQL语句生成后,通过数据库查询接口对数据库进行查询,最终将结果返回给用户。