我尝试将一个CEP示例从Drools 5X转换为6X时遇到奇怪的错误: - Drool 6.1.0.Final确切。
我对这个小项目的灵感来源可以在以下链接找到:=> PlugTree
我得到的错误表明Drools 无法创建Field Extractor - 当他们忘记在他们的域POJO中创建setter / getter时会出现错误。
严重:无法构建KieBaseModel:规则 无法为'金额'字段/方法'金额'创建字段提取器没有找到课程' com.sample.Sale' :[规则名称=' StoreOne - 已通过它的销售记录'] java.lang.RuntimeException:字段/方法'金额'没有找到课程' com.sample.Sale'
我已将此问题追溯到“声明”状态。规则文件中的陈述(我将进一步列出完整的列表):
declare Sale
@role(event)
end
使用这个导致错误(在V5顺便说一句不会发生),但是使用下一个"改变了#34;声明语句不会导致错误。它什么都不做......
declare Sale
@role(event)
article : String
amount : long
quantity : int
end
它做了什么 - 什么都不是。它编译,运行,但事实不会被插入(或识别)。
这是我的Java测试工具:
package com.sample.cep;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices;
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.event.rule.DebugAgendaEventListener;
import org.kie.api.event.rule.DebugRuleRuntimeEventListener;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.conf.ClockTypeOption;
import org.kie.api.runtime.rule.EntryPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CEPExample {
public static void main(String[] args) {
try {
// load up the knowledge base & get the kSession
KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
KieSession kSession = kContainer.newKieSession("ksession-rules");
// CEP - get the KIE related configuration container and set the EventProcessing (from default cloud) to Stream
KieBaseConfiguration config = ks.newKieBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );
// Listeners
kSession.addEventListener( new DebugAgendaEventListener() );
kSession.addEventListener( new DebugRuleRuntimeEventListener() );
// To setup a file based audit logger, uncomment the next line
// KieRuntimeLogger loggerKie = ks.getLoggers().newFileLogger( kSession, "./logger" );
// KieRuntimeLogger consoleLogger = ks.getLoggers().newConsoleLogger(kSession);
Logger logger = LoggerFactory.getLogger(CEPExample.class);
logger.info("\n*********************************>>>> Drools CEP Example \n");
// Each Event is Inserted into WorkingMemory through an *EntryPoint*
EntryPoint entryPointStoreOne = kSession.getEntryPoint( "StoreOne" );
EntryPoint entryPointStoreTwo = kSession.getEntryPoint( "StoreTwo" );
// Insert EventData into WM for StoreOne
entryPointStoreOne.insert(new Sale("meat", 40, 5) );
entryPointStoreOne.insert(new Sale("bananna", 5, 10) );
entryPointStoreOne.insert(new Sale("pear", 5, 10) );
entryPointStoreOne.insert(new Sale("yogurt", 5, 50) );
entryPointStoreOne.insert(new Sale("led TV", 10000, 1) );
// Insert EventData into WM for StoreTwo
entryPointStoreTwo.insert(new Sale("meat", 40, 5) );
entryPointStoreTwo.insert(new Sale("bananna", 5, 10) );
entryPointStoreTwo.insert(new Sale("pear", 5, 10) );
entryPointStoreTwo.insert(new Sale("yogurt", 5, 50) );
// Fire all Rules
kSession.fireAllRules();
// Close Logger
//logger.close();
// Close the session
kSession.destroy();
System.out.println("*** DONE *** ");
} catch (Throwable t) {
t.printStackTrace();
}
} // End Method - MAIN
// // Helper Class to INSERTEVENT
// private static void insertEvent(EntryPoint entryPoint, Sale sale, String article, long amount, int quantity) {
//
// sale.setArticle(article);
// sale.setAmount(amount);
// sale.setQuantity(quantity);
// entryPoint.insert(sale);
//
// } // End Class insertEvent
}// End Class CEPExample
这是我的规则文件:
//created on: Nov 28, 2014
package com.sample
import com.sample.Sale;
// Declarations
declare Sale
@role(event)
//article : String
//amount : long
//quantity : int
end
rule "StoreOne - Has Passed it's Sales Record"
when
Number( $totalSalesAmount : intValue, intValue > 1000 )
from accumulate ( Sale($amount : amount, $quantity : quantity)
from entry-point "StoreOne", sum( $amount*$quantity ))
then
System.out.println("StoreOne - Has passed its Sales Record!");
end
rule "StoreTwo - has Passed its Sales Record"
when
Number( $totalSalesAmount : intValue, intValue > 1000 )
from accumulate ( Sale($amount : amount, $quantity : quantity) from entry-point "StoreTwo", sum( $amount * $quantity ))
then
System.out.println("StoreTwo - Has passed its Sales Record!");
end
我的kmodule.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
<kbase name="rules" packages="rules">
<ksession name="ksession-rules"/>
</kbase>
</kmodule>
我认为这也是相关的 - 使用监听器的Consult输出(用于更改的声明语句(列出属性)):
Nov 29, 2014 4:31:10 PM org.drools.compiler.kie.builder.impl.ClasspathKieProject notifyKieModuleFound
INFO: Found kmodule: file:/C:/Users/versaggi/workspace-spring-framework/CEPProject/target/classes/META-INF/kmodule.xml
Nov 29, 2014 4:31:10 PM org.drools.compiler.kie.builder.impl.KieRepositoryImpl addKieModule
INFO: KieModule was added:FileKieModule[ ReleaseId=com.versaggi:CEPProject:0.0.1-SNAPSHOTfile=C:\Users\versaggi\workspace-spring-framework\CEPProject\target\classes]
Nov 29, 2014 4:31:14 PM com.sample.cep.CEPExample main
INFO:
*********************************>>>> Drools CEP Example
==>[ObjectInsertedEventImpl: getFactHandle()=[fact 0:1:24780333:24780333:1:StoreOne:NON_TRAIT:com.sample.cep.Sale@17a1e2d], getObject()=com.sample.cep.Sale@17a1e2d, getKnowledgeRuntime()=org.drools.core.impl.StatefulKnowledgeSessionImpl@527389, getPropagationContext()=PhreakPropagationContext [entryPoint=EntryPoint::StoreOne, factHandle=[fact 0:1:24780333:24780333:1:StoreOne:NON_TRAIT:com.sample.cep.Sale@17a1e2d], leftTuple=null, originOffset=-1, propagationNumber=2, rule=null, type=0]]
==>[ObjectInsertedEventImpl: getFactHandle()=[fact 0:2:20723018:20723018:2:StoreOne:NON_TRAIT:com.sample.cep.Sale@13c354a], getObject()=com.sample.cep.Sale@13c354a, getKnowledgeRuntime()=org.drools.core.impl.StatefulKnowledgeSessionImpl@527389, getPropagationContext()=PhreakPropagationContext [entryPoint=EntryPoint::StoreOne, factHandle=[fact 0:2:20723018:20723018:2:StoreOne:NON_TRAIT:com.sample.cep.Sale@13c354a], leftTuple=null, originOffset=-1, propagationNumber=3, rule=null, type=0]]
==>[ObjectInsertedEventImpl: getFactHandle()=[fact 0:3:16489063:16489063:3:StoreOne:NON_TRAIT:com.sample.cep.Sale@fb9a67], getObject()=com.sample.cep.Sale@fb9a67, getKnowledgeRuntime()=org.drools.core.impl.StatefulKnowledgeSessionImpl@527389, getPropagationContext()=PhreakPropagationContext [entryPoint=EntryPoint::StoreOne, factHandle=[fact 0:3:16489063:16489063:3:StoreOne:NON_TRAIT:com.sample.cep.Sale@fb9a67], leftTuple=null, originOffset=-1, propagationNumber=4, rule=null, type=0]]
==>[ObjectInsertedEventImpl: getFactHandle()=[fact 0:4:33509294:33509294:4:StoreOne:NON_TRAIT:com.sample.cep.Sale@1ff4fae], getObject()=com.sample.cep.Sale@1ff4fae, getKnowledgeRuntime()=org.drools.core.impl.StatefulKnowledgeSessionImpl@527389, getPropagationContext()=PhreakPropagationContext [entryPoint=EntryPoint::StoreOne, factHandle=[fact 0:4:33509294:33509294:4:StoreOne:NON_TRAIT:com.sample.cep.Sale@1ff4fae], leftTuple=null, originOffset=-1, propagationNumber=5, rule=null, type=0]]
==>[ObjectInsertedEventImpl: getFactHandle()=[fact 0:5:27946348:27946348:5:StoreOne:NON_TRAIT:com.sample.cep.Sale@1aa6d6c], getObject()=com.sample.cep.Sale@1aa6d6c, getKnowledgeRuntime()=org.drools.core.impl.StatefulKnowledgeSessionImpl@527389, getPropagationContext()=PhreakPropagationContext [entryPoint=EntryPoint::StoreOne, factHandle=[fact 0:5:27946348:27946348:5:StoreOne:NON_TRAIT:com.sample.cep.Sale@1aa6d6c], leftTuple=null, originOffset=-1, propagationNumber=6, rule=null, type=0]]
==>[ObjectInsertedEventImpl: getFactHandle()=[fact 0:6:26643062:26643062:6:StoreTwo:NON_TRAIT:com.sample.cep.Sale@1968a76], getObject()=com.sample.cep.Sale@1968a76, getKnowledgeRuntime()=org.drools.core.impl.StatefulKnowledgeSessionImpl@527389, getPropagationContext()=PhreakPropagationContext [entryPoint=EntryPoint::StoreTwo, factHandle=[fact 0:6:26643062:26643062:6:StoreTwo:NON_TRAIT:com.sample.cep.Sale@1968a76], leftTuple=null, originOffset=-1, propagationNumber=7, rule=null, type=0]]
==>[ObjectInsertedEventImpl: getFactHandle()=[fact 0:7:26870209:26870209:7:StoreTwo:NON_TRAIT:com.sample.cep.Sale@19a01c1], getObject()=com.sample.cep.Sale@19a01c1, getKnowledgeRuntime()=org.drools.core.impl.StatefulKnowledgeSessionImpl@527389, getPropagationContext()=PhreakPropagationContext [entryPoint=EntryPoint::StoreTwo, factHandle=[fact 0:7:26870209:26870209:7:StoreTwo:NON_TRAIT:com.sample.cep.Sale@19a01c1], leftTuple=null, originOffset=-1, propagationNumber=8, rule=null, type=0]]
==>[ObjectInsertedEventImpl: getFactHandle()=[fact 0:8:1161635:1161635:8:StoreTwo:NON_TRAIT:com.sample.cep.Sale@11b9a3], getObject()=com.sample.cep.Sale@11b9a3, getKnowledgeRuntime()=org.drools.core.impl.StatefulKnowledgeSessionImpl@527389, getPropagationContext()=PhreakPropagationContext [entryPoint=EntryPoint::StoreTwo, factHandle=[fact 0:8:1161635:1161635:8:StoreTwo:NON_TRAIT:com.sample.cep.Sale@11b9a3], leftTuple=null, originOffset=-1, propagationNumber=9, rule=null, type=0]]
==>[ObjectInsertedEventImpl: getFactHandle()=[fact 0:9:2257152:2257152:9:StoreTwo:NON_TRAIT:com.sample.cep.Sale@227100], getObject()=com.sample.cep.Sale@227100, getKnowledgeRuntime()=org.drools.core.impl.StatefulKnowledgeSessionImpl@527389, getPropagationContext()=PhreakPropagationContext [entryPoint=EntryPoint::StoreTwo, factHandle=[fact 0:9:2257152:2257152:9:StoreTwo:NON_TRAIT:com.sample.cep.Sale@227100], leftTuple=null, originOffset=-1, propagationNumber=10, rule=null, type=0]]
*** DONE ***
由于很少有关于V5中的CEP在网络上浮动的例子,甚至更少的V6 KIE,我对这个错误的起源以及如何纠正错误表示赞赏。
答案 0 :(得分:2)
DRL语言的declare
语句可用于两个相当不同的目的:
@role
)添加到POJO 区别源于declare
语句中存在一个或多个字段。
使用第二种形式时,Java代码无法以通常的方式创建声明的类的对象。您将不得不使用环绕式技术从包中使用(KieBase.getFactType())定位类,创建实例(FactType.newInstance())并使用通用设置器添加属性值(FactType.set(),setFromMap())。
如果您同时拥有POJO Sale 和宣布的类Sale,那么很可能会出现问题。我没有尝试使用kmodule.xml进行构建(我从来没有尝试过),但是从Java调用KieBuilder并检查错误产生(销售字段不评论):
[main] ERROR org.drools.compiler.kie.builder.impl.AbstractKieModule - Unable to build KieBaseModel:defaultKieBase
New declaration of sale.Sale can't declaredeclares a different set of fields
existing : ...
declared : ...
BTW,此示例未使用任何事件处理功能,该问题与cEP无关。
<强>后来强>
插入“标准事实”和“事件事实”的唯一区别是引擎可能必须添加时间戳字段(除非您的元数据表明它已作为属性存在)。
从技术上讲,对于代码插入的方式,它取决于事实类型的定义方式:由Java类(声明根据“声明”添加“事件”味道)项目1)或通过全面宣布,如前所述。没有进一步的区别w.r.t.明确的事实和事件之间的插入。
此外,访问(检索模式评估的属性)没有区别,除了事件具有额外的时间戳属性(除非映射到显式属性),当临时运算符是隐式检索时应用
处理存在差异,最明显的是时间运算符适用于事件本身(与属性相对)。此外,事件可能有资格进行自动撤消,并且可以在窗口中进行选择。
答案 1 :(得分:1)
我在Google Drools Board上发布了这个并得到了一个不错的答案 - 这是转贴:
David Sottara:
需要一点历史。截至6.2及以前的版本: 不幸的是,“声明”历史上已经超载了两个非常(!)不同的用例。一种是在DRL中定义新的内联类。另一种是 redeclare 预先存在的扩展和注释类。 在前者中,生成新的字节码。在后者中,Drools使用现有的字节码并简单地收集有关该类用法的元数据。
不幸的是,出于兼容性原因,我们无法使用两个关键字来区分用例。唉,付出的代价是含糊不清的 - 为什么我们试图弃用整个功能以支持更强大的功能。 此外,在他们不属于的包中声明“外国”类的历史能力使事情变得更糟。
我们用来消除歧义的(弱)策略基本上如下。如果声明无法跟踪类路径中的任何现有类,则将其视为“定义”并生成字节码。如果存在潜在的名称冲突, 以下规则适用。如果声明没有任何字段,则将其视为“重新声明”。如果声明与类路径中的类完全相同,则认为它是“重新声明”。否则,出错 生成并报告。
这就是说,你的代码中可能会发生很多事情。 - 如果规则是根据类路径上的“Sale”类编写的,并且该类没有所有必需的getter / setter,声明将无法帮助您,因为您的主java代码仍将实例化该类 - 无字段声明将被视为“重新声明”,因此DRL将使用类路径上的类。可能是5.5只是在寻找getter,而后来的版本需要两个getter和setter。 - 我想知道带有属性的声明是否实际上被认为是“定义”,导致一个具有相同名称和属性的类,但它与您从java代码提供的实例不匹配。
[编辑:检查Plugtree网站并仔细检查您的代码]
“Sale”类过去曾在org.nicozan.examples.droolsfusion中。你在com.sample.cep.CEPExample类中使用它而没有导入,所以我假设它存在于com.sample.cep(!由监听器跟踪确认!); 但是,您的DRL使用包com.sample AND导入com.sample.Sale而不是com.sample.cep.Sale。 所以,你的声明总是“定义”:第一个创建一个没有属性的com.sample.Sale,并且编译器会抱怨。 在第二种情况下,使用com.sample.Sale(具有适当的属性)编译规则,但是插入com.sample.cep.Sale的实例 - 一个不同的类,因此不会触发规则。
导入在本地定义的类上自行循环,因此您不会收到任何编译时错误。这可能是我们可以解决的问题。 @Mario,您可以根据后续情况帮助跟踪吗?
在我写作时进行诊断,我希望这也澄清了列表中其他人“声明”的当前行为 谢谢你的报道 的Davide
解决方案:
在规则文件中我改变了:
**import com.sample.Sale;**
为:
**import com.sample.cep.Sale;**
修复了它。但是,我在这个过程中学到的东西比简单的修复更有价值。我希望将它传递给其他人......