KBQA的工作流程(基于检索的方法)
图谱构建阶段
注:采用neo4j的方法进行建立图数据库
1.数据准备
- 结构化数据,例如mysql的关系型数据库,进行整理,导出为csv,
- 半结构化数据,采用包装器技术,进行抽取,之后,进行清洗.
- 文本数据,采用信息抽取技术,提取其中的关系
一般情况下,neo4j最好只存储结构化数据,否则会有很多高层散乱的节点,因为没有联系.
关系型数据如下:
2.数据导入
将导出的csv文件,导入到neo4j之中.
导出sql语句:
use movie;
#CMD命令 查看MySql的导入与导出的目录【其他目录无权限】
# 使用mysql -u root -p 连接mysql
# show variables like '%secure%'
#MySql导出csv数据,带表头
#导出电影的类型
SELECT * INTO OUTFILE 'C:/ProgramData/MySQL/MySQL Server 5.7/Uploads/genre.csv'
FIELDS TERMINATED BY ','
FROM (select 'gid','gname' union select*from genre) genre_;
#导出电影的信息 == 如果太多可以只导出前500个,加限制
SELECT * INTO OUTFILE 'C:/ProgramData/MySQL/MySQL Server 5.7/Uploads/movie.csv'
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\r' #电影描述中出现\r换行字符,
FROM (select 'mid','title','introduction','rating','releasedate' union select*from movie) movie_;
#导出演员person的信息 == 如果有中文名要中文名,如果没有取英文名
SELECT * INTO OUTFILE 'C:/ProgramData/MySQL/MySQL Server 5.7/Uploads/person.csv'
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
FROM (select 'pid','birth','death','name','biography','birthplace' union
select person_id,person_birth_day,person_death_day,case when person_name then person_english_name else person_name end
as name,person_biography,person_birth_place from person) person_;
#导出电影ID和电影类别之间的对应 【1对1】
SELECT * INTO OUTFILE 'C:/ProgramData/MySQL/MySQL Server 5.7/Uploads/movie_to_genre.csv'
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
FROM (select 'mid','gid' union select*from movie_to_genre) movie_to_genre_;
#导出演员ID和电影ID之间的对应 【1对多】
SELECT * INTO OUTFILE 'C:/ProgramData/MySQL/MySQL Server 5.7/Uploads/person_to_movie.csv'
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
FROM (select 'pid','mid' union select*from person_to_movie) person_to_movie_;
如图:
导入就会在neo4j当中看到:
3.关系构建
依据对应数据库的关系表,使用neo4j的cypher语句进行关系构建.
如图:
语义解析阶段
1.分词器
典型的有HANLP分词器,自然语言处理工具包,按步骤进行安装(语料库文件,配置文件),驱动文件(jar包)的话使用pom.xml依赖注入就可以,注意版本号.
如图:
2.自定义词典
在分词器的安装目录下,以HANLP工具包为例,在 D:\HanLp\data\dictionary\custom下,自定义词典,主要是导入原先数据表当中的专有数据,例如电影名,电影类型名,评分等,可以看成是对原先分词器词典的优化.便于正确分词.具体图如下:
customDictionary本来就有的,然后根据子集选择进行添加,在genreDict.txt里面
都是些专有名词
3.构建问题模型
在分词器的question目录下:具体地址为:D:\HanLp\data\question,构建问题模型,在每个问题模型当中,其实就是构建不同的问法.然后确定输入语句的问题模型的时候,比对输入语句与各个问题相似性.如图(两张):
具体某个问题模型里面的内容:
之后对问题模型进行索引,就是question_classification.txt如图:
4.构建词汇表
构建词汇表的目的主要是为了:,经过分词器处理之后的输入语句,会分割成若干个词组,这些词组需要在词汇表中进行查找匹配,用来确定 表示输入语句的词向量中的元素的值.(存在为1,不存在为0).具体情况如图:
注:专有名词(电影名,电影类型,评分等)需要在自定义词典构建,不是在这里构建.
问题分类
可以使用spark框架的机器学习算法,来确定输入语句所对应的问题模型
1.创建进程.
使用JavaSparkContext()来创建进程,通过配置进程来确定运行模式,便于后面的并行处理
/**
* 本地模式,*表示启用多个线程并行计算
*/
SparkConf conf = new SparkConf().setAppName("NaiveBayesTest").setMaster("local[*]");
JavaSparkContext sc = new JavaSparkContext(conf);
2.设置训练集
主要是通过创建词向量及其标签,然后添加到列表当中,形成一个训练集
可以从外部文件导入(只不过需要分词器处理,匹配),也可以自己在程序中直接设定.,有稀疏向量/密集向量,用labelpoint()添加对应向量的标签.
//稠密向量 == 连续的
Vector vMale = Vectors.dense(1,0,1,0,1,0);
//稀疏向量 == 间隔的、指定的,未指定位置的向量值默认 = 0.0
int len = 6;
int[] index = new int[]{0,1,2,3,5};
double[] values = new double[]{1,1,1,1,1};
//索引0、1、2、3、5位置上的向量值=1,索引4没给出,默认0
Vector vFemale = Vectors.sparse(len, index, values);
//训练集生成 ,规定数据结构为LabeledPoint == 构建方式:稠密向量模式 ,1.0:类别编号 == 男性
LabeledPoint train_one = new LabeledPoint(1.0,vMale); //(1.0, 0.0, 1.0, 0.0, 1.0, 0.0)
//训练集生成 ,规定数据结构为LabeledPoint == 构建方式:稀疏向量模式 ,2.0:类别编号 == 女性
LabeledPoint train_two = new LabeledPoint(2.0,vFemale); //(1.0, 1.0, 1.0, 1.0, 0.0, 1.0)
//我们也可以给同一个类别增加多个训练集
LabeledPoint train_three = new LabeledPoint(2.0,Vectors.dense(0,1,1,1,0,1));
//List存放训练集【三个训练样本数据】
List<LabeledPoint> trains = new ArrayList<>();
trains.add(train_one);
trains.add(train_two);
trains.add(train_three);
3.数据集格式转换
为了加快训练速度,spark需要使用RDD数据集,所以需要将LIst数据集转换成–>RDD数据集,为了spark能够并行处理数据,具体方法如下:
JavaRDD<LabeledPoint> trainingRDD = sc.parallelize(trains);
/**
* 利用Spark进行数据分析时,数据一般要转化为RDD
* JavaRDD转Spark的RDD
*/
NaiveBayesModel nb_model = NaiveBayes.train(trainingRDD.rdd());
4.测试集的生成
有两种方法:
- 直接设置词向量的测试集,然后直接使用训练好的模型进行训练(根据测试集的大小,决定是否也需要进行格式转换)
- 在外部文件当中设置多个输入语句,之后导入到程序之中,然后使用HANLP分词器(分词,匹配词汇表)转换成词向量,然后进行测试(扩展性强,适应性强)
5.问题模型匹配
通过训练好的模型,输入对应的测试语句,然后算法模型进行该语句与问题模型相似度计算,选出相似度最大的,作为该语句所对应的问题模型.
以上是问的阶段,下面是答的阶段.
查询结果
根据所匹配的问题模型,然后在调用neo4j的接口,在neo4j当中查找问题结果,然后返回,具体过程如下:
输入语句:陈凯歌什么时候出生的,经过机器学习算法分类得到,问题模型的索引编号是13
在问题模型索引/分类表中,如下图:
可以看到是以词典的形式来进行匹配的,结果就是 nnt 出生日期,当中的两个属性:
nnt是对应图数据库当中的person.name=陈凯歌,出生日期对应person.birth,为什么会这样对应?
因为在设置索引阶段的时候就通过词典设定不同问题模型对应的属性.
- 然后将nnt=陈凯歌,出生日期=birth,之后调用neo4j接口,进行具体查找,情况如下: