原文地址:这里写链接内容
DDlog是一种语法为datalog式,用来编写DeepDive应用的语言。一个ddlog程序会被编译成deepdive格式下的配置文件,我们通常用这个文件来运行我们的应用。
一个ddlog程序由一组声明组成,这些声明由dots分割,而状态的顺序是无关紧要的。一个声明可以是一个模式声明,一个datalog函数声明,一个函数调用规则,一个监管规则,或者一条推理规则。
每个模式声明(schema declaration)在一个关系(relation)中声明了关系的每一列的类型以及列的顺序。其语法类似于SQL里的schema:
relation_name(
column1_name column1_type,
column2_name column2_type,
...).
relation_name
是数据库中一个指明关系的名字的标识符。类似的, column_name
s 和 column_type
s 是数据库中与列名称和列类型相匹配的字符串。ddlog使用与SQL相同的类型集合。
例如:
sentences(
doc_id text,
sent_id int,
text text,
words text[]).
它定义了一个包含了4列的关系articles:doc_id
, sent_id
, text
, 和 words
, 他们的类型分别是text
, int
, text
, text[]
,其中text[]
代表了 text
数组.
一个在关系名后的问号指出了这是一个包含了随机变量(random variable)的变量关系(variable relation),这些随机变量被包含在因子图(factor graph)中。例如,
has_spouse?(relation_id text).
定义了一个变量关系has_spouse
,并且每个不同的 relation_id
代表了一个不同的变量。
典型的datalog规则可以被用来定义一个关系是如何被其他关系驱动的。一个规则的head被定义的规则,body则是一个合取查询体的合取式(conjunction),由逗号进行分割。析取的情况则被多个由分号分割body表达。
例如,下列程序表示了 元组Q是由R和S派生的,其中R的第二列和S的第一列是统一的,也就是说,这个body是一个等值连接。
Q(x, y) :- R(x, y), S(y).
在这里,Q(x, y)
是头部head, 而 R(x, y)
和 S(y)
是body原子. x
和 y
是规则的变量。
表达式可以在原子column中被使用。head atom中的表达式会被输出到头部关系。而在body atom中的表达式则会成为一个条件。注意datalog的语义是基于变量和表达式的统一:有相同名字的变量是统一的,body atom中则是根据相应的column统一的。下面是一个便于理解的例子:
a(k int).
b(k int, p text, q text, r int).
c(s text, n int, t text).
Q("test", f(123), id) :- a(id), b(id, x,y,z), c(x || y,10,"foo").
这里的输出是一个字符串“text”逐字形成的元组,一个函数f在根据输入的参数123完成操作,而id则由body产生,在body中,条件被编译为:
a.k = b.k -- unifying variable id in a(id) and b(id, ...)
AND c.n = 10 -- unifying literal 10 with the column in c(...,10,...)
AND c.t = 'foo' -- unifying literal "foo" with the column in c(...,"foo")
AND b.p || b.q = c.s -- unifying expression x||y with the column in c(x||y,...)
值得一提的是,表达式可以被随意嵌套。
条件(conditions)出现在在body atoms的同一层,和body atoms一起定义了对head的输出。合取(conjunction)条件由逗号分隔,析取(Disjunction)条件则由分号分隔。条件可以通过放置内部方括号(”[]”)来任意嵌套。例如,
Q(x) :- b(x,y,z,w), [x + w = 100; [!x > 50, w < 10]].
这个条件是 (x + w = 100) OR ((NOT x > 50) AND w < 10)
。
占位符”_”可以用在body atoms的各个列中,表明输出和这个列是不相关的。
在head atom columns中使用聚合函数表示在其他列上做了一个group by的分组操作,以及一个聚合操作。现在DDlog支持的函数有 SUM, MAX, MIN, ARRAY_AGG, COUNT. 例如,
Q(a,b,MAX(c)) :- R(a,b,c).
会根据R的第一列和第二列进行分组,然后在第三列上选择最大值。
监督规则被用来考量和监督随机变量,也就是定义变量集合和训练数据。它的语法和normal datalog rule是一样的,但是多了一个注解 @label(column_variable)
。例如,
@label(is_true)
has_spouse(rid) :- has_spouse_candidates(_, _, _, _, rid, is_true).
这个规则使用has_spouse_candidates
里的 is_true
这一列来监督has_spouse
里的随机变量。
推理规则是用来表达如何推理随机规则的。一个推理规则的head式定义了因子图里的一个因子。head里的的atom必须是变量关系。权重绑定(weight tying)表示在规则前,使用了@weight(expression)
的语法,其中expression
可以是任意的表达式。例如,
@weight(3)
smoke(x) => cancer(x) :- person(x).
@weight(feature)
smoke(x) = smoke(y) :- friend(x, y, feature).
第一个规则表示了一个人抽烟影响了他/她患上癌症的概率。第二个规则表示了如果x和y是朋友,他们要么都抽烟和要么都不抽烟,权重被捆绑在friend关系中的feature列。权重也可以是一个字符串常量,意味着规则的因子都有相同的权重。被支持的deepdive因子函数和相应的head语法如下:
Imply : A1, A2, ... => An
Equal : A1 = A2 = ... = An
And : A1 ^ A2 ^ ... ^ An
Or : A1 v A2 v ... v An
IsTrue : A
Multinomial: Multinomial(A1, A2, ..., An)
其中 A
s 是atoms。
给定ddlog编译器 ddlog.jar
, 一个ddlog程序 app.ddlog
可以这样编译:
java -jar ddlog.jar compile app.ddlog > deepdive.conf
这一节描述了更多ddlog合取查询表达。
量化的body指出了一个量化的条件,语法是
quantifier(atom_or_condition, ...)
支持的量词有 EXISTS
, ALL
, OPTIONAL
。前两个类似于相应的SQL中的量词,第三个对应于SQL里一个outer join(外接)中的outer relation。例如,
Q(a) :- R(a,b), EXISTS[S(c, a)].
Q(a) :- R(a,b), EXISTS[S(c, d), b > d].
Q(a) :- R(a,b), OPTIONAL[S(c, d), a > d].
每个函数声明给出了用户定义函数(UDF)的input和output每个列的类型,以及它如何被实现和执行。语法:
function function_name function_input_type function_return_type implemetation
function
是关键字, function_type
和 function_return_type
可以是
over relation_type_declaration
或者是
returns relation_type_declaration
relation_type_declaration
也可以是一个类型名和类型的列表,或者让 像 relation_name
这样的行使用同样的关系. implementation
是这样的,
implementation "path_to_udf" handles tsv lines
它用来指出一个tsv函数,或者说 handles tsv lines
被替换为 runs as plpy
来表示一个 plpy
提取器函数。例如,
Q(x int).
function ext_people over (a int, b int) returns like Q
implementation "udf/ext_people.py" handles tsv lines.
如上述声明的函数只能在函数调用规则中使用。用户自定义规则可以从合取查询中派生出关系。语法是:
output_relation += user_defined_function(x, y) :- relation1(x, y), relation2(y, z).
body关系中的元组(x, y)
会被输入到 user_defined_function
, 而输出会被送到output_relation
。例如,
has_spouse_candidates += ext_has_spouse(s, p1_id, p1_text, p2_id, p2_text) :-
people_mentions(s, _, _, p1_text, p1_id),
people_mentions(s, _, _, p2_text, p2_id).