如何使用已声明的事实类型动态重新加载规则?
我在尝试动态重新加载规则时遇到问题。 从上下文开始:我们有 DRL 文件,其中总共包含 10000 条规则和各种类型。由于编译和重新部署规则的过程开始很长(超过几分钟),我们希望编译和重新部署规则。仅重新部署修改后的规则。
为了符合 DRL,我们必须在 DRL 中声明以重新部署修改后的规则以及所有使用的类型。
我们的问题是,新 DRL 中声明的类型不会与已部署的类型合并,因此在匹配这些类型时新规则不会激活。
我在查看 ReteoRuleBase 对象时发现 TypeDeclaration 列表包含两个以“Item”命名的类,这肯定是重新部署的规则与正确的对象不匹配的原因。
首先,我的单元测试揭示了我们部署和重新部署的方式:
@Test
public void test_hot_deploy() throws FileNotFoundException {
File drl1 = new File("src/test/resources/essai-drools/hot-deploy-1.drl");
Resource resource1 = ResourceFactory.newInputStreamResource(new FileInputStream(drl1));
File drl2 = new File("src/test/resources/essai-drools/hot-deploy-2.drl");
Resource resource2 = ResourceFactory.newInputStreamResource(new FileInputStream(drl2));
KnowledgeBuilder builder = KnowledgeBuilderFactory.newKnowledgeBuilder();
builder.add(resource1, ResourceType.DRL);
KnowledgeBase kb = builder.newKnowledgeBase();
StatefulKnowledgeSession session = kb.newStatefulKnowledgeSession();
int fired = session.fireAllRules();
Assert.assertEquals(2, fired);
System.out.println("--- redeploy ---");
KnowledgeBuilder builder2 = KnowledgeBuilderFactory.newKnowledgeBuilder();
builder2.add(resource2, ResourceType.DRL);
kb.addKnowledgePackages(builder2.getKnowledgePackages());
session = kb.newStatefulKnowledgeSession();
fired = session.fireAllRules();
Assert.assertEquals(2, fired);
}
原始 DRL(第一个部署的):
package test;
declare Item
value : String
end
rule "insertion"
when
then
Item $item = new Item();
$item.setValue("A");
insert($item);
System.out.println("Object A inserted");
end
rule "modification"
when
$item: Item(value == "A")
then
$item.setValue("B");
update($item);
System.out.println("Object A -> B");
end
重新部署的 DRL:
package test;
declare Item
value : String
end
rule "modification"
when
$item : Item(value == "A")
then
$item.setValue("C");
update($item);
System.out.println("Object A -> C");
end
输出:
Object A inserted
Object A -> B
--- redeploy ---
Object A inserted
缺少的输出(如您所见,重新部署规则未执行)
Object A -> C
知道我们如何能够处理这种类型哪个不合并?
希望你有一个想法,我来这里只是为了提供信息。
I am facing an issue while trying to reload rules dynamically.
Starting with the context : we have DRLs files which contains a total of 10000 rules, and various types. As the process of compiling and redeploying rules is starting to be long (over than a couple of minutes), we would like to compile & redeploy ONLY the modified rule.
To be DRL-compliant, we have to declare in the DRL to redeploy the modified rule, AND all used types.
Our problem is that types declared in the new DRL are not merged with types already deployed, so new rules do not activate when matching those types.
I found while looking at the ReteoRuleBase object that the list of TypeDeclaration contains two class named after "Item", and that's surely why the redeployed rule did not match the right object.
First, my unit test exposing the way we deploy and redeploy :
@Test
public void test_hot_deploy() throws FileNotFoundException {
File drl1 = new File("src/test/resources/essai-drools/hot-deploy-1.drl");
Resource resource1 = ResourceFactory.newInputStreamResource(new FileInputStream(drl1));
File drl2 = new File("src/test/resources/essai-drools/hot-deploy-2.drl");
Resource resource2 = ResourceFactory.newInputStreamResource(new FileInputStream(drl2));
KnowledgeBuilder builder = KnowledgeBuilderFactory.newKnowledgeBuilder();
builder.add(resource1, ResourceType.DRL);
KnowledgeBase kb = builder.newKnowledgeBase();
StatefulKnowledgeSession session = kb.newStatefulKnowledgeSession();
int fired = session.fireAllRules();
Assert.assertEquals(2, fired);
System.out.println("--- redeploy ---");
KnowledgeBuilder builder2 = KnowledgeBuilderFactory.newKnowledgeBuilder();
builder2.add(resource2, ResourceType.DRL);
kb.addKnowledgePackages(builder2.getKnowledgePackages());
session = kb.newStatefulKnowledgeSession();
fired = session.fireAllRules();
Assert.assertEquals(2, fired);
}
The original DRL (the first deployed) :
package test;
declare Item
value : String
end
rule "insertion"
when
then
Item $item = new Item();
$item.setValue("A");
insert($item);
System.out.println("Object A inserted");
end
rule "modification"
when
$item: Item(value == "A")
then
$item.setValue("B");
update($item);
System.out.println("Object A -> B");
end
The redeployed DRL :
package test;
declare Item
value : String
end
rule "modification"
when
$item : Item(value == "A")
then
$item.setValue("C");
update($item);
System.out.println("Object A -> C");
end
The output :
Object A inserted
Object A -> B
--- redeploy ---
Object A inserted
The missing output (as you see, the redeploy rule was not executed)
Object A -> C
Any idea of how we could deal with this type which do not merge ?
Hope you got an idea, I am here for mere informations.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
从版本 5.2 开始,Drools 不支持类型声明的重新部署。原因是在java中,一个类是通过classloader+class来标识的。部署类型声明时,将需要刷新类加载器,从而有效地创建新的类加载器。正如您所注意到的,所有现有规则仍然需要旧的类加载器+类,并且不会匹配新的类加载器+类。
因此,我给您的建议是,如果您需要热重新部署规则,请将类型声明保存在单独的 DRL 文件中,并且仅重新部署规则文件。或者,您可以动态生成新规则或从文件中提取更改的规则并仅重新部署它们。
As of version 5.2, Drools does not support redeployment of type declarations. The reason is that in java, a class is identified by classloader+class. When a type declaration is deployed, it will require a classloader refresh, creating effectively a new classloader. As you've noted, all existing rules will still expect the old classloader+class and will not match the new classloader+class.
So, my suggestion for you is, if you need to hot-redeploy rules, to keep your type declarations in a separate DRL file and only redeploy the rules files. Alternatively, you can generate the new rules on the fly or extract the changed rules from a file and only redeploy them.