2

我在尝试将 CEP 示例从 Drools 5X 转换为 6X 时遇到了一个奇怪的错误: - 准确地说是 Drool 6.1.0.Final。

我对这个小项目的灵感来源可以在以下链接中找到:=> PlugTree

我得到的错误表明 Drools无法创建字段提取器- 当他们忘记在其域 POJO 中创建 setter/getter 时会出现错误。

严重:无法构建 KieBaseModel:规则 无法为类“com.sample.Sale”找不到“amount”字段/方法“amount”创建字段提取器:[Rule name='StoreOne - Has Passed it's Sales Record'] java .lang.RuntimeException:找不到类“com.sample.Sale”的字段/方法“金额”

我已经将问题追溯到规则文件中的“声明”语句(我将在下面列出完整列表):

declare Sale
    @role(event)
end

仅使用它会导致错误(顺便说一句,在 V5 中不会发生),但是使用下一个“更改的”声明语句不会导致错误。它只是什么都不做......

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>

我确实认为这也是相关的 - 使用侦听器的咨询输出(用于更改的声明语句(列出属性):

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 中则更少,我会很感激有关此错误的起源以及如何纠正它的任何想法。

4

2 回答 2

2

DRL 语言的declare语句可以用于两个完全不同的目的:

  1. 将元数据(例如@role)添加到 POJO
  2. 声明一个类(不需要任何 Java 代码)以在规则(和 Java 应用程序代码)中使用

区别源于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 : ...

顺便说一句,这个例子没有使用任何事件处理功能,这个问题根本与 cEP 无关。

之后

插入“标准事实”和“事件事实”的唯一区别是引擎可能必须添加时间戳字段(除非您的元数据表明它已经作为属性存在)。

从技术上讲,对于插入代码的方式,它取决于事实类型的定义方式:通过 Java 类(根据第 1 项的声明添加“事件”风格)或通过成熟的声明,如前所述。普通事实和事件事实之间的插入没有进一步的区别。

此外,访问(检索用于模式评估的属性)没有区别,除了事件具有附加的时间戳属性(除非映射到显式属性),该属性在应用时间运算符时隐式检索。

处理方面存在差异,最值得注意的是时间运算符适用于事件本身(与属性相反)。此外,事件可能符合自动撤回的条件,并且可以在窗口中选择。

于 2014-11-30T09:11:13.880 回答
2

我在 Google Drools Board 上发布了这个并得到了一个不错的答案 - 这是转贴:

大卫·索塔拉:

需要一点历史。从 6.2 和以前的版本开始:不幸的是,“declare”历来被两个非常(!)不同的用例超载。一种是在 DRL中定义新的内联类。另一种是为扩展和注释重新声明预先存在的类。在前者中,会生成新的字节码。在后者中,Drools 使用现有的字节码并简单地收集有关类使用的元数据。

不幸的是,出于兼容性原因,我们无法使用两个关键字来区分用例。唉,要付出的代价就是模棱两可——我们为什么要弃用整个功能而支持更强大的功能的原因。此外,在它们不属于的包中声明“外来”类的历史能力使事情变得更糟。

我们用来消除歧义的(弱)策略基本上如下。如果声明无法追踪到类路径中的任何现有类,则将其视为“定义”并生成字节码。如果存在潜在的名称冲突,则适用以下规则。如果声明没有任何字段,则视为“重新声明”。如果声明与类路径中的类具有完全相同的字段,则将其视为“重新声明”。否则会产生并报告错误。

这就是说,您的代码中可能会发生许多事情。- 如果规则是根据类路径上的“Sale”类编写的,并且该类没有所有必需的 getter/setter,则声明将无济于事,因为您的主 java 代码仍将实例化该类 - 否-field declare 将被视为“重新声明”,因此 DRL 将使用类路径上的类。可能是 5.5 只是在寻找 getter,而更高版本需要 getter 和 setter。- 我想知道带有属性的声明是否实际上被认为是“定义”,导致一个具有相同名称和属性的类,但它与您从 java 代码中提供的实例并不真正匹配。

[编辑:检查 Plugtree 站点并仔细检查您的代码后]

“销售”类曾经在 org.nicozan.examples.droolsfusion 中。您在没有导入的情况下在 com.sample.cep.CEPExample 类中使用它,所以我假设它存在于 com.sample.cep 中(!由侦听器跟踪确认!);但是,您的 DRL 使用包 com.sample 并导入 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;**

那解决了它。然而,我在这个过程中学到的东西远比简单的修复更有价值。我希望把它传递给其他人......

于 2014-12-01T18:14:41.630 回答