从零实现基于医疗知识图谱的问答系统(三)-问题解析处理

文章目录
  1. 1. ahocorasick的安装问题
  2. 2. 构建问题分类器-question_classify.py
    1. 2.1. 设置加载词路径
    2. 2.2. 加载词载入list
    3. 2.3. 构造领域actree
    4. 2.4. 构造词对应的类型
    5. 2.5. 设置问句疑问词
    6. 2.6. 问句过滤
    7. 2.7. 对问题进行分类
    8. 2.8. 测试问题分类
  3. 3. 问题解析器-question_parser.py
    1. 3.1. 在Neo4j中使用查询语句
    2. 3.2. 构建实体节点
    3. 3.3. 针对不同的问题进行sql查询
    4. 3.4. 对问题进行解析

在第一篇博客和第二篇博客中,已经完成了数据的采集和知识图谱的构建,在这篇博客中将讲解问答系统的构建过程。
btw,我也是第一次接触问答系统,再次感谢刘老师提供开源代码给小白学习,好人一生平安-w-

ahocorasick的安装问题

↓↓↓ 下面是博主本人的精分现场 ↓↓↓
首先介绍一下ahocorasick是什么:ahocorasick是个python模块,Aho-Corasick算法是多模式匹配中的经典算法,目前在实际应用中较多。
既然需要做问答,那就需要对问题先进行匹配。然而,库是非常的好的库,装上去还是有点麻烦的,下面说一下我安装过程中遇到的各种坑。

Problem 1 不存在ahocorasick这个库
exo 喵???不存在我怎么装???
后来我查了一下…原来改名了,叫pyahocorasick。

Problem 2 Microsoft Visual C++ 14.0 is required
本来我以为就是改个名字的事,万万没想到啊,居然还要要求C++ 14.0这种东西…
行叭,let’s check check…
我觉得最快捷的办法就是安装一个微软的Visual Studio,刚好我的度云里有一个2013的安装包。
(悔啊,我电脑里原来是有Visual Studio的,后来用全家桶去了就给卸了,悔啊
(恕我直言,全家桶才是最好用的编译器-w-
分享出来,有需要自取:

1
2
链接:https://pan.baidu.com/s/1kIX8S1X1SmYuryzS9rr6tA 
提取码:y8in

你以为这样就结束了吗?这个还是继续报错,还是要求C++ 14.0…
我查了下这些版本的对应关系:

1
2
3
Visual Studio 2013 ---> 12 
Visual Studio 2015 ---> 14
Visual Studio 2017 ---> 15

ORZ…果断卸载VS2013…

继续check,找到了这个:https://www.microsoft.com/en-us/download/details.aspx?id=48145
去这里下载简体中文的VS2015,vc_redist.x64.exe,这个文件只有13.9M,下载完毕后安装。

你以为这样就结束了吗?这个还是继续报错,继续报错,继续报错啊!F***!!!

害,肿么可以随便就放弃呢?那就继续找啊0.0:https://www.scivision.dev/python-windows-visual-c-14-required/

我安装了博主推荐的三个链接中的一个,这个需要等一段时间,安装包有点大,有好几个G的亚子。
安装完成后,我怀着受伤的(划掉)坚强的小心心再次执行了安装命令:

1
pip3 install pyahocorasick

看到了吗!!!!看到successful了吗!!!!额滴个神呐!(这句话请用掌柜的调来念)

我觉得这个库应该不止有品如的衣服,它甚至把整个品如的衣柜搬到我面前来了,安装的东西叫pyahocorasick,import的时候要把py删掉…
真是让人rbq的一个库啊,西湖的水啊我的泪啊QAQ…

安装部分完了,给看到这儿的看官推荐一首歌QAQ:
http://music.163.com/m/song?id=461107563&userid=466490903

构建问题分类器-question_classify.py

这个问题下面有个deny.txt,应该是刘老师自己整理的停用词,所以这里直接拷贝到对应的 ./dict 文件夹下面。

设置加载词路径

首先在 __init__下面设置特征词路径:

1
2
3
4
5
6
7
8
9
# 特征词路径
self.disease_path = os.path.join(cur_dir, './dict/disease.txt')
self.department_path = os.path.join(cur_dir, './dict/department.txt')
self.check_path = os.path.join(cur_dir, './dict/check.txt')
self.drug_path = os.path.join(cur_dir, './dict/drug.txt')
self.food_path = os.path.join(cur_dir, './dict/food.txt')
self.producer_path = os.path.join(cur_dir, './dict/producer.txt')
self.symptom_path = os.path.join(cur_dir, './dict/symptoms.txt')
self.deny_path = os.path.join(cur_dir, './dict/deny.txt')

加载词载入list

再将对应的特征词加载到一个list中:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 加载特征词
self.disease_wds = [i.strip() for i in open(self.disease_path) if i.strip()]
self.department_wds = [i.strip() for i in open(self.department_path) if i.strip()]
self.check_wds = [i.strip() for i in open(self.check_path) if i.strip()]
self.drug_wds = [i.strip() for i in open(self.drug_path) if i.strip()]
self.food_wds = [i.strip() for i in open(self.food_path) if i.strip()]
self.producer_wds = [i.strip() for i in open(self.producer_path) if i.strip()]
self.symptom_wds = [i.strip() for i in open(self.symptom_path) if i.strip()]
self.region_words = set(self.department_wds + self.disease_wds
+ self.check_wds + self.drug_wds +
self.food_wds + self.producer_wds +
self.symptom_wds)
self.deny_words = [i.strip() for i in open(self.deny_path,encoding='utf-8') if i.strip()]

这段代码需要留意 region_words 这个字段,后续需要根据其中的字段来构造领域actree。

构造领域actree

使用AC自动机来进行字符串匹配。
将之前得到的region_words添加到build_actree中进行构建。

1
2
3
4
5
6
7
# 构造actree,加速过滤
def build_actree(self, wordlist):
actree = ahocorasick.Automaton()
for index, word in enumerate(wordlist):
actree.add_word(word, (index, word))
actree.make_automaton()
return actree

可以参考这篇博客来查看相关用法。

构造词对应的类型

做法就是定义一个字典,然后遍历region_words,再寻找其对应的类型,是厂商,还是症状,然后分类,举个栗子:

1
{'普德药业氨酪酸注射液': ['producer']}

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def build_wdtype_dict(self):
wd_dict = dict()
for wd in self.region_words:
wd_dict[wd] = []
if wd in self.disease_wds:
wd_dict[wd].append('disease')
if wd in self.department_wds:
wd_dict[wd].append('department')
if wd in self.check_wds:
wd_dict[wd].append('check')
if wd in self.drug_wds:
wd_dict[wd].append('drug')
if wd in self.food_wds:
wd_dict[wd].append('food')
if wd in self.symptom_wds:
wd_dict[wd].append('symptom')
if wd in self.producer_wds:
wd_dict[wd].append('producer')
#print(wd_dict)
return wd_dict

设置问句疑问词

这里的疑问词我估计是刘老师自己整理出来的,所以这里我直接引用。
我猜测如果后面需要自己构建这类问答系统,那么也需要我自己来构建这个问句疑问词。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
self.symptom_qwds = ['症状', '表征', '现象', '症候', '表现']
self.cause_qwds = ['原因','成因', '为什么', '怎么会', '怎样才', '咋样才', '怎样会', '如何会', '为啥', '为何', '如何才会', '怎么才会', '会导致', '会造成']
self.acompany_qwds = ['并发症', '并发', '一起发生', '一并发生', '一起出现', '一并出现', '一同发生', '一同出现', '伴随发生', '伴随', '共现']
self.food_qwds = ['饮食', '饮用', '吃', '食', '伙食', '膳食', '喝', '菜' ,'忌口', '补品', '保健品', '食谱', '菜谱', '食用', '食物','补品']
self.drug_qwds = ['药', '药品', '用药', '胶囊', '口服液', '炎片']
self.prevent_qwds = ['预防', '防范', '抵制', '抵御', '防止','躲避','逃避','避开','免得','逃开','避开','避掉','躲开','躲掉','绕开',
'怎样才能不', '怎么才能不', '咋样才能不','咋才能不', '如何才能不',
'怎样才不', '怎么才不', '咋样才不','咋才不', '如何才不',
'怎样才可以不', '怎么才可以不', '咋样才可以不', '咋才可以不', '如何可以不',
'怎样才可不', '怎么才可不', '咋样才可不', '咋才可不', '如何可不']
self.lasttime_qwds = ['周期', '多久', '多长时间', '多少时间', '几天', '几年', '多少天', '多少小时', '几个小时', '多少年']
self.cureway_qwds = ['怎么治疗', '如何医治', '怎么医治', '怎么治', '怎么医', '如何治', '医治方式', '疗法', '咋治', '怎么办', '咋办', '咋治']
self.cureprob_qwds = ['多大概率能治好', '多大几率能治好', '治好希望大么', '几率', '几成', '比例', '可能性', '能治', '可治', '可以治', '可以医']
self.easyget_qwds = ['易感人群', '容易感染', '易发人群', '什么人', '哪些人', '感染', '染上', '得上']
self.check_qwds = ['检查', '检查项目', '查出', '检查', '测出', '试出']
self.belong_qwds = ['属于什么科', '属于', '什么科', '科室']
self.cure_qwds = ['治疗什么', '治啥', '治疗啥', '医治啥', '治愈啥', '主治啥', '主治什么', '有什么用', '有何用', '用处', '用途',
'有什么好处', '有什么益处', '有何益处', '用来', '用来做啥', '用来作甚', '需要', '要']

print('model init finished ......')

问句过滤

这个部分的作用是删除问句里的停用词并且建立问句里面词语及类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 问句过滤
def check_medical(self,question):
region_wds=[]
for i in self.region_tree.iter(question):
# 获取问题中在actree里面的词
wd=i[1][1]
region_wds.append(wd)
# 建立停用词
stop_wds=[]
for wd1 in region_wds:
for wd2 in region_wds:
# 如果wd2中包含了wd1的内容,并且wd1和wd2不同,将wd1划为停用词
if wd1 in wd2 and wd1!=wd2:
stop_wds.append(wd1)
# 获取去除停用词的list
final_wds=[i for i in region_wds if i not in stop_wds]
# 重新生成不包含停用词的物品类型dict
final_dict={i:self.wdtype_dict.get(i) for i in final_wds}
return final_dict

对问题进行分类

这个函数的作用是通过查找问题中的关键词来给问题进行分类,使用到的相关函数已在上述内容中说明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# 对问题进行分类
def classify(self,question):
data={}
medical_dict=self.check_medical(question)
if not medical_dict:
return {}
data['args']=medical_dict

# 收集问句当中涉及到得实体类型
types=[]
for type_ in medical_dict.values():
types+=type_
# 定义问题类型
question_type='others'

question_types=[]
# 症状 : disease 对应的是疾病的名称
if self.check_words(self.symptom_qwds,question) and ('disease' in types):
question_type='disease_symptom'
question_types.append(question_type)

if self.check_words(self.symptom_qwds,question) and ('symptom' in types):
question_type = 'symptom_disease'
question_types.append(question_type)

# 原因
if self.check_words(self.cause_qwds, question) and ('disease' in types):
question_type = 'disease_cause'
question_types.append(question_type)
# 并发症
if self.check_words(self.acompany_qwds, question) and ('disease' in types):
question_type = 'disease_acompany'
question_types.append(question_type)

# 推荐食品
if self.check_words(self.food_qwds, question) and 'disease' in types:
deny_status = self.check_words(self.deny_words, question)
if deny_status:
question_type = 'disease_not_food'
else:
question_type = 'disease_do_food'
question_types.append(question_type)

# 已知食物找疾病
if self.check_words(self.food_qwds + self.cure_qwds, question) and 'food' in types:
deny_status = self.check_words(self.deny_words, question)
if deny_status:
question_type = 'food_not_disease'
else:
question_type = 'food_do_disease'
question_types.append(question_type)

# 推荐药品
if self.check_words(self.drug_qwds, question) and 'disease' in types:
question_type = 'disease_drug'
question_types.append(question_type)

# 药品治啥病
if self.check_words(self.cure_qwds, question) and 'drug' in types:
question_type = 'drug_disease'
question_types.append(question_type)

# 疾病接受检查项目
if self.check_words(self.check_qwds, question) and 'disease' in types:
question_type = 'disease_check'
question_types.append(question_type)

# 已知检查项目查相应疾病
if self.check_words(self.check_qwds + self.cure_qwds, question) and 'check' in types:
question_type = 'check_disease'
question_types.append(question_type)

#  症状防御
if self.check_words(self.prevent_qwds, question) and 'disease' in types:
question_type = 'disease_prevent'
question_types.append(question_type)

# 疾病医疗周期
if self.check_words(self.lasttime_qwds, question) and 'disease' in types:
question_type = 'disease_lasttime'
question_types.append(question_type)

# 疾病治疗方式
if self.check_words(self.cureway_qwds, question) and 'disease' in types:
question_type = 'disease_cureway'
question_types.append(question_type)

# 疾病治愈可能性
if self.check_words(self.cureprob_qwds, question) and 'disease' in types:
question_type = 'disease_cureprob'
question_types.append(question_type)

# 疾病易感染人群
if self.check_words(self.easyget_qwds, question) and 'disease' in types:
question_type = 'disease_easyget'
question_types.append(question_type)

# 若没有查到相关的外部查询信息,那么则将该疾病的描述信息返回
if question_types == [] and 'disease' in types:
question_types = ['disease_desc']

# 若没有查到相关的外部查询信息,那么则将该疾病的描述信息返回
if question_types == [] and 'symptom' in types:
question_types = ['symptom_disease']

# 将多个分类结果进行合并处理,组装成一个字典
data['question_types'] = question_types

return data

完整的question_classifier.py文件这里就不再放出,后面会直接上传到github上,同时会在目录博客中说明。

测试问题分类

首先把程序运行起来,根据提示进行输入:

问题解析器-question_parser.py

在Neo4j中使用查询语句

在阐述这个python文件之前,还需要补一下Neo4j中的查询语句,否则无法进行查询-v-
首先,启动Neo4j进入浏览器主界面:localhost:7474
先执行这样一条查询语句:

1
MATCH (m:Disease) where m.name = '感冒' return m.name, m.cause

可以看到已经得到了我们的查询结果:

同时也可以查询感冒的治愈率,预防方式,治疗周期等等。

妥,下面来系统的看一下Neo4j的查询语句,CQL。
(虽然这个在构建知识图谱那一章就该讲的但是那里用到得不多所以偷了个懒,害,写在这里也是一样的嘛-v-

本来一开始是写在这里的,然鹅我觉得这么写感觉以后我要翻回来看看也不是hin方便,那还是单独再开一篇博客吧,戳下面↓↓↓
Neo4j图数据库查询语句总结

构建实体节点

返回实体节点及其类型,具体写在代码注释上:

1
2
3
4
5
6
7
8
9
10
11
# 构建实体节点
def build_entitydict(self,args):
entity_dict={}
for arg,types in args.items():
for type in types:
if type not in entity_dict:
entity_dict[type]=[arg]
else:
entity_dict[type].append(arg)
# 返回的数据类型类似于:{'food': ['白菜']},如果类型不止一种则继续增加
return entity_dict

针对不同的问题进行sql查询

这个函数主要是构造CQL查询语句的,熟悉CQL查询就行,问题不大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# 针对不同的问题进行sql查询
def sql_transfer(self, question_type, entities):
# 如果不存在实体,返回空
if not entities:
return []
# 查询语句
sql = []
# 查询疾病的原因
if question_type == 'disease_cause':
sql = ["MATCH (m:Disease) where m.name = '{0}' return m.name, m.cause".format(i) for i in entities]

# 查询疾病的防御措施
elif question_type == 'disease_prevent':
sql = ["MATCH (m:Disease) where m.name = '{0}' return m.name, m.prevent".format(i) for i in entities]

# 查询疾病的持续时间
elif question_type == 'disease_lasttime':
sql = ["MATCH (m:Disease) where m.name = '{0}' return m.name, m.cure_lasttime".format(i) for i in entities]

# 查询疾病的治愈概率
elif question_type == 'disease_cureprob':
sql = ["MATCH (m:Disease) where m.name = '{0}' return m.name, m.cured_prob".format(i) for i in entities]

# 查询疾病的治疗方式
elif question_type == 'disease_cureway':
sql = ["MATCH (m:Disease) where m.name = '{0}' return m.name, m.cure_way".format(i) for i in entities]

# 查询疾病的易发人群
elif question_type == 'disease_easyget':
sql = ["MATCH (m:Disease) where m.name = '{0}' return m.name, m.easy_get".format(i) for i in entities]

# 查询疾病的相关介绍
elif question_type == 'disease_desc':
sql = ["MATCH (m:Disease) where m.name = '{0}' return m.name, m.desc".format(i) for i in entities]

# 查询疾病有哪些症状
elif question_type == 'disease_symptom':
sql = ["MATCH (m:Disease)-[r:has_symptom]->(n:Symptom) where m.name = '{0}' return m.name, r.name, n.name".format(
i) for i in entities]

# 查询症状会导致哪些疾病
elif question_type == 'symptom_disease':
sql = ["MATCH (m:Disease)-[r:has_symptom]->(n:Symptom) where n.name = '{0}' return m.name, r.name, n.name".format(
i) for i in entities]

# 查询疾病的并发症
elif question_type == 'disease_acompany':
sql1 = ["MATCH (m:Disease)-[r:acompany_with]->(n:Disease) where m.name = '{0}' return m.name, r.name, n.name".format(
i) for i in entities]
sql2 = ["MATCH (m:Disease)-[r:acompany_with]->(n:Disease) where n.name = '{0}' return m.name, r.name, n.name".format(
i) for i in entities]
sql = sql1 + sql2
# 查询疾病的忌口
elif question_type == 'disease_not_food':
sql = ["MATCH (m:Disease)-[r:no_eat]->(n:Food) where m.name = '{0}' return m.name, r.name, n.name".format(i)
for i in entities]

# 查询疾病建议吃的东西
elif question_type == 'disease_do_food':
sql1 = ["MATCH (m:Disease)-[r:do_eat]->(n:Food) where m.name = '{0}' return m.name, r.name, n.name".format(i)
for i in entities]
sql2 = ["MATCH (m:Disease)-[r:recommand_eat]->(n:Food) where m.name = '{0}' return m.name, r.name, n.name".format(
i) for i in entities]
sql = sql1 + sql2

# 已知忌口查疾病
elif question_type == 'food_not_disease':
sql = ["MATCH (m:Disease)-[r:no_eat]->(n:Food) where n.name = '{0}' return m.name, r.name, n.name".format(i)
for i in entities]

# 已知推荐查疾病
elif question_type == 'food_do_disease':
sql1 = [ "MATCH (m:Disease)-[r:do_eat]->(n:Food) where n.name = '{0}' return m.name, r.name, n.name".format(i)
for i in entities]
sql2 = ["MATCH (m:Disease)-[r:recommand_eat]->(n:Food) where n.name = '{0}' return m.name, r.name, n.name".format(
i) for i in entities]
sql = sql1 + sql2

# 查询疾病常用药品-药品别名记得扩充
elif question_type == 'disease_drug':
sql1 = ["MATCH (m:Disease)-[r:common_drug]->(n:Drug) where m.name = '{0}' return m.name, r.name, n.name".format(
i) for i in entities]
sql2 = ["MATCH (m:Disease)-[r:recommand_drug]->(n:Drug) where m.name = '{0}' return m.name, r.name, n.name".format(
i) for i in entities]
sql = sql1 + sql2

# 已知药品查询能够治疗的疾病
elif question_type == 'drug_disease':
sql1 = ["MATCH (m:Disease)-[r:common_drug]->(n:Drug) where n.name = '{0}' return m.name, r.name, n.name".format(
i) for i in entities]
sql2 = ["MATCH (m:Disease)-[r:recommand_drug]->(n:Drug) where n.name = '{0}' return m.name, r.name, n.name".format(
i) for i in entities]
sql = sql1 + sql2
# 查询疾病应该进行的检查
elif question_type == 'disease_check':
sql = ["MATCH (m:Disease)-[r:need_check]->(n:Check) where m.name = '{0}' return m.name, r.name, n.name".format(
i) for i in entities]

# 已知检查查询疾病
elif question_type == 'check_disease':
sql = ["MATCH (m:Disease)-[r:need_check]->(n:Check) where n.name = '{0}' return m.name, r.name, n.name".format(
i) for i in entities]

return sql

对问题进行解析

害,这个也是,都写在代码注释里了,不再赘述,主要作用是将问题转换为sql并返回查询结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# 解析主函数
def parser_main(self, res_classify):
'''
后续这个文件要在chat_bot中进行查询使用
这里的参数 res_classify,来自于question_classifier.py中def classify的结果
结果形式:{'args': {'白菜': ['food']}, 'question_types': ['food_do_disease']}
args包括的是实体名称和实体类型
question_types则是疾病宜吃的食物
'''
# 获取实体及实体类型
args = res_classify['args']
# 构建实体字典
entity_dict = self.build_entitydict(args)
# 获取关系类型
question_types = res_classify['question_types']
sqls = []
for question_type in question_types:
sql_ = {}
sql_['question_type'] = question_type
sql = []
if question_type == 'disease_symptom':
sql = self.sql_transfer(question_type, entity_dict.get('disease'))
elif question_type == 'symptom_disease':
sql = self.sql_transfer(question_type, entity_dict.get('symptom'))

elif question_type == 'disease_cause':
sql = self.sql_transfer(question_type, entity_dict.get('disease'))

elif question_type == 'disease_acompany':
sql = self.sql_transfer(question_type, entity_dict.get('disease'))

elif question_type == 'disease_not_food':
sql = self.sql_transfer(question_type, entity_dict.get('disease'))

elif question_type == 'disease_do_food':
sql = self.sql_transfer(question_type, entity_dict.get('disease'))

elif question_type == 'food_not_disease':
sql = self.sql_transfer(question_type, entity_dict.get('food'))

elif question_type == 'food_do_disease':
sql = self.sql_transfer(question_type, entity_dict.get('food'))

elif question_type == 'disease_drug':
sql = self.sql_transfer(question_type, entity_dict.get('disease'))

elif question_type == 'drug_disease':
sql = self.sql_transfer(question_type, entity_dict.get('drug'))

elif question_type == 'disease_check':
sql = self.sql_transfer(question_type, entity_dict.get('disease'))

elif question_type == 'check_disease':
sql = self.sql_transfer(question_type, entity_dict.get('check'))

elif question_type == 'disease_prevent':
sql = self.sql_transfer(question_type, entity_dict.get('disease'))

elif question_type == 'disease_lasttime':
sql = self.sql_transfer(question_type, entity_dict.get('disease'))

elif question_type == 'disease_cureway':
sql = self.sql_transfer(question_type, entity_dict.get('disease'))

elif question_type == 'disease_cureprob':
sql = self.sql_transfer(question_type, entity_dict.get('disease'))

elif question_type == 'disease_easyget':
sql = self.sql_transfer(question_type, entity_dict.get('disease'))

elif question_type == 'disease_desc':
sql = self.sql_transfer(question_type, entity_dict.get('disease'))

if sql:
sql_['sql'] = sql

sqls.append(sql_)

return sqls