首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

使用 Excel 表单辅助 AQL 规则定义和开发(3)

使用 Excel 表单辅助 AQL 规则定义和开发(3)

包含 union all 的 view
当两个 select 或 extract 语句被 union all 时,表示这两个子句所得到的结果将会被合入同一个 view,类似于两个 select 或 extract 结果的并集。多个 select 或 extract 可以并联在一起,也可以和 minus 的结果相互嵌套,select 或 extract 语句的先后顺序并不影响结果。
包含 minus 的 view
与 union all 不同,minus 的先后顺序决定了结果,并且 minus 不可以级联嵌套。(select A)minus(select B)表示取 A 并去除掉 A 中与 B 相同的项。而(select B)minus(select A ) 则表示取 B 并去除 B 中与 A 相同的项。
使用 AQL 实现 Baby Stuff 公司需求通过 excel 表单我们定义了 AQL 脚本所需要实现的规则,以下我们将讲解如何实现这些脚本。由于规则的定义的规范化,每一个规则的实现也将类似,这也为我们开发自动化 AQL 脚本生成器打定了基础。
首先定义该 AQL module 的名称,通过关键字 module 指定。
清单 7. 设定 AQL 文件的 module 名称
1
module babyStuff;




以图 2 所示的规则 preg_1 为例,对于 preg_1 的每一列,我们都需要定义一个 dictionary,而对于所有的“包含”列,还需要定义一个 view。代码如清单 8 示例:
清单 8. 定义 preg_1 所需的 dictionary 和 dictionary view
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
create dictionary preg1_att_exclude_dict
from file 'dict/preg1_adv_exclude.dict'
with language as 'en';
create dictionary preg1_sub_dict
from file 'dict/preg1_sub.dict'
with language as 'en';
create dictionary preg1_adv_exclude_dict
from file 'dict/preg1_adv_exclude.dict'
with language as 'en';
create dictionary preg1_verb_dict
from file 'dict/preg1_verb.dict'
with language as 'en';
create view preg1_sub_view as
extract
dictionary 'preg1_sub_dict' on D.text as sub
from Document D;
create view preg1_verb_view as
extract
dictionary 'preg1_verb_dict'on D.text as verb
from Document D;




对于一条规则来说,以上的 dictionary 和 view 是构建这条规则的基础。之前描述过 select 子句和 extract 子句,这里通过给出两个子句分别的实现,来阐述 select 和 extract 的应用。清单 9 给出了使用 select 子句来实现 preg_1 规则的代码,而清单 10 给出了使用 extract 来实现 preg_1 规则的代码。
清单 9. 使用 select 子句实现 preg_1 规则
1
2
3
4
5
6
7
8
9
10
11
12
create view preg1 as
select
S.sub as sub,
V.verb as verb,
CombineSpans(S.sub, V.verb) as match
from preg1_sub_view S, preg1_verb_view V
where And (
Not(ContainsDict('preg1_att_exclude_dict', LeftContextTok(S.sub, 3))),
Not(ContainsDict('preg1_adv_exclude_dict', SpanBetween(S.sub, V.verb))),
FollowsTok(S.sub, V.verb, 0, 4)
)
;




清单 10. 使用 extract 子句实现 preg_1 规则
1
2
3
4
5
6
7
8
9
10
11
12
13
create view preg1 as
extract
LeftContextTok(S.sub, 3) as first,
pattern (<S.sub>) <Token>{0, 4} (<V.verb>)
return group 0 as match
group 1 as sub
group 2 as verb
from preg1_sub_view S, preg1_verb_view V
having And (
Not(ContainsDict('preg1_att_exclude_dict', first)),
Not(ContainsDict('preg1_adv_exclude_dict', SpanBetween(sub, verb)))
)
;




LeftContextTok() 函数是 AQL 提供的内置函数,它的作用是取主语左边的 3 个单词作为 first,这样我们就可以通过对 first 的判断,来剔除掉“if I ……”这样的句子。与 LeftContextToken() 函数类似的是 RightContextToken() 函数,一般使用 RightContextToken() 来获得匹配字段最后的字符串。
ContainsDict() 函数包括两个参数,第一个是一个 dictionary,第二个是一个 span,包含一个或多个单词。其作用是用来判断第二个输出参数是否包含在第一个输入参数的字典中。
对比清单 9 和清单 10 可以发现,select 子句和 extract 子句调用的 AQL 内置函数是相同的,只是使用方式不同。在 select 子句中,对主语和谓语之间的跨度是通过调用 FollowsTok() 这个函数实现的,而在 extract 子句中则是使用 pattern 来实现。pattern 中需要匹配的是所有“包含”列的 view,而 having 短语则用来剔除“不包含”的列。
我们选择使用 extract 子句来实现 baby_1 规则,这是因为 baby_1 规则中多了谓语,使用 select 语句时需要多调用一次 FollowsTok() 函数,而 extract 子句则相对简单些。清单 11 给出了 baby_1 规则的实现。
清单 11. 实现 baby_1 规则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
create view baby1 as
extract
LeftContextTok(S.sub, 3) as first,
RightContextTok(O.obj, 3) as last,
pattern (<S.sub>) <Token>{0, 4} (<V.verb>) <Token>{0, 3} (<O.obj>)
return group 0 as match
group 1 as sub
group 2 as verb
group 3 as obj
from baby1_sub_view S, baby1_verb_view V, baby1_obj_view O
having And (
Not(ContainsDict('baby1_att_exclude_dict', first)),
Not(ContainsDict('baby1_com_exclude_dict', last)),
Not(ContainsDict('baby1_adv_exclude_dict', SpanBetween(sub, verb)))
)
;




当实现了所有的规则之后,我们需要将它们合成为一个 output view,通过 AQL 的 union all 来实现,代码如清单 12 所示:
清单 12. 最终的 babyStuff output view
1
2
3
4
5
6
7
8
9
10
11
12
13
14
create view babyStuff_output as
( select
D.text as text,
P.match as match
from preg1 P, Document D
)
union all
( select
D.text as text,
B.match as match
from baby1 B, Document D
)
;
output view babyStuff_output;




测试与优化本文使用 JAQL 脚本来对 AQL module 进行编译和测试。使用 systemT::compileAQL() 函数进行编译,systemT::annotateDocument() 函数进行调用,这里我们不在累述 JAQL 的语法,只给出调用以及测试的脚本。
清单 13. 使用 JAQL 调用 AQL module
1
2
3
4
5
6
7
8
9
10
11
import systemT;
extern AQLPath;
extern TAM;
systemT::compileAQL(["babyStuff"], TAM);
doc = [ { text: "I am pregnant." }, {text: "I'm not pregnant."},
{text: "my friend is pregnant"}, {text: "my wife is preg"}];
doc -> transform {
$.text,
annotation: systemT::annotateDocument({label:"", text: $.text},
["babySutff"], [TAM], "toJsonString", "standard")
};




当得到测试的结果后,根据测试结果可以发现一些错误的项,通过调整 pattern 语句中的<Token>{0, 4},以及添加不同的 having 项来过滤错误选项,从而优化 AQL module。需要注意的是,每一次 AQL 脚本的改动或者 dictionary 文件的改动都需要重新编译 AQL module。
结束语本文描述了一种使用 excel 表格来辅助 AQL 规则设计的方法,通过这种方法,不但可以规范 AQL 规则,同样方便语言专家和 AQL 开发者之间的沟通,使得 AQL 规则清晰明了,便于开发和维护。
返回列表