我有三个表(现在),一个有2000行,另外两个有大约160万行。它们具有相互关联的列,但它们不是正式的FK字段。我编写了一个C ++程序来生成基于源MySQL数据的规则文件,如下所示:
if T{ C1, C2...Cn } is the table definition
then the rule would be:
T(C1, C2, Cn).
我的转换实用程序将整数展开,其他任何内容都放在单引号内,因此INT(n),DECIMAL等成为Prolog数字,其他所有内容都是原子。
我的问题是:如果我想为包含26个字段的表/规则编写搜索规则,是否有“元级别”表达方式:
findStuffById(I,FieldIWant1,FieldIwant2etc) :-
tablename(_,_,I,_,FieldIWant1,_,_,_FieldIWant2etc,_,_,....).
还是我必须创建“更简单”的规则,然后必须使用“_”或变量来捕捉我想要的东西?
编写像...这样的规则的前景。
findThisById(X) :- tablename(X,_,_,_,_,This,_,_).
findThatById(X) :- tablename(X,_,_,That,_,_,_,_).
findTheOtherById(X) :- tablename(X,_,_,_,_,_,_,TheOther).
... ad adause ...令人不安!
到目前为止,我唯一的想法是,我可能需要在规则中创建复合术语以将事物分组在一起,即减少规则中的变量数量,但这可能会限制未来查询的“自由”?我不是Prolog专家;我已经玩了好几个小时了,并渴望在我自己的日常工作中找到真实世界的用途。
我想我的转换程序也可以编码生成苦差规则,以便我不必手动编码。大表每个有26和28列,所以你可以看到它的发展方向!
欢迎任何关于如何进行的建议;我不像我想的那样使用Prolog,而且我总是想学习更多!
我想创建一个SWI-Prolog Web服务器,该服务器将使用相同的原始数据与ElasticSearch服务器正面交锋,以查看哪些是响应ad-hoc查询的快速响应。除非你预先创建一个嵌入了索引的复合文档,否则ES似乎不会做传统连接,这也可能有利于使用Prolog。
感谢。 肖恩。
答案 0 :(得分:2)
您可以使用nth1/1
和“univ”运算符,执行以下操作:
fieldnames(t, [id,this,that]).
get_field(Field, Tuple, Value) :-
Tuple =.. [Table|Fields],
fieldnames(Table, Names),
nth1(Idx, Names, Field),
nth1(Idx, Fields, Value).
您需要为每个表结构创建fieldnames/2
条记录,并且必须将表结构传递给此查询。它不会非常有效,但它会起作用。
?- get_field(this, t(testId, testThis, testThat), Value)
Value = testThis
然后,您可以轻松地在此基础上构建访问者:
findThisById(X, This) :- get_field(this, X, This).
修改:Boris正确地指出arg/3
将以更少的工作完成此任务:
get_field(Field, Tuple, Value) :-
functor(Tuple, Table, _),
fieldnames(Table, Names),
nth1(Idx, Names, Field),
arg(Idx, Tuple, Value).
Prolog太棒了。
答案 1 :(得分:1)
在实际的电子商务数据库中,我使用了像
这样的代码update_price(File, Pid, Cn, Manu) :-
product(Pid, [tax_class_id = Tid, /*cost = Cost,*/ price = CurrPrice]),
tax_rate(_, [tax_class_id = Tid, rate = R]),
manufacturer(Manu, name = NameM),
( ( NameM == 'Gruppo Aboca' ; NameM == 'L\'Amande' )
-> % Pr is Cost * 3 / 2
togli_iva(R, Cn, Pr)
; togli_iva(R, Cn, NoIva),
Pr is NoIva * 2
),
Delta is abs(CurrPrice - Pr),
( Delta > 0.01
-> Prx is round(Pr * 100) / 100,
format(File, 'update product set price=~w where product_id=~d~@', [Prx, Pid, eol])
; true
).
product,tax_rate,manufacturer是具有已知结构的实际表名。例如,产品有26列,tax_rate有8,....
我有声明
:- dynamic
...
product/2,product/26,
...
tax_rate/2,tax_rate/8,
...
从SQL转储中读取数据,当在内存中声明时,我构建了product / 2访问器,负责从名称到位置的字段转换。
我不建议使用这种方法,因为对你的数据来说太慢了。相反,您可以使用goal_expansion/2并在编译时将任何对表的调用(field1 = Value1,field2 = Value2)转换为对应的表调用(,,Value1,_,Value2) ) - Prolog的位置方式。
这应该会从SWI-Prolog索引中挤出最佳性能,最近更新后可用于所有列。
当然,要获得更多细节,您应该发布元数据格式......
编辑:如果您对简单的单字段访问者感兴趣(正如我从评论中理解为Daniel的答案),您可以尝试使用库(record)。