版权声明:本文可以自由转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
作者:forge(作者的Blog:http://forge.iteye.com)
原文:http://forge.iteye.com/blog/571047
Drools Fusion Features
Fusion 是业务逻辑集成平台(Business Logic Integration Platform)一部分,是一个CEP/ESP引擎。
事件,是指在应用程序域中有意义状态改变的记录
一个复杂事件是简单事件的集合。CEP(Complex Event Processing) 处理复杂事件-从事件云中检测并选择事件,根据选择的事件和他们建立的关系发现他们的关系推理出新的数据。
比如,一系列的巨额提款激发可疑交易事件的发生。一个复杂事件的发生是由一系列简单事件的引导形成的。
ESP(Event Stream Processing) 是更实时(real-time)的大量事件处理。例如,根据时间计算实时平均交易量。
一、事件(Events).
从drools视图来看,事件就是一个特殊的事实(fact)。我们说,所有的事件都是事实,但是所有的事实并不都是事件。
1.事件和事实不同特征:
(1)通常不可变:事件是在应用程序域中状态改变的记录,记录已经发生的事情,可变的事件是没有意义的。
应用程序允许给没有赋值的事件属性赋值,但是已经赋值的属性是不应该被改变的。
(2)强时间约束:规则涉及的事件通常需要多个事件的相互关系,尤其某个事件相对其他事件发生的时间点的时间关系。
(3)可管理的生命周期:由于上两个事件特征的原因,事件通常在一个有限的时间窗(Time Window)匹配事件和事实,
这就让引擎管理事件的生命周期成为可能。一个事件插入working memory,引擎有能力发现一个不在匹配
其他事实的事件,然后自动回收它,释放相关的资源。
(4)滑动窗( sliding windows)的使用:由于所有的事件都有关联的时间戳,可以定义并使用滑动窗,让事件在特定的一段时间有效。
2.事件声明:
import some.package.StockTick
declare StockTick
@role( event )
end
将一个已有的StockTick(类)事实生命为事件类型
@role 元数据接受2个值:
fact:默认值,声明为常规的事实
event:声明为事件
由于Drools支持在DRL中声明一个事实,可以去掉StockTick(类),还可以这样:
declare StockTick
@role( event )
datetime : java.util.Date
symbol : String
price : double
end
3.事件元数据
所有的事件都有一个事件元数据集合。当事件插入working memory,事件元数据会自动赋予默认值,我们可以用元数据标签改变他们的默认值。
假设我们有这样的一个实体类:
/**
* A class that represents a voice call in
* a Telecom domain model
*/
public class VoiceCall {
private String originNumber;
private String destinationNumber;
private Date callDateTime;
private long callDuration; // in milliseconds
// constructors, getters and setters
}
(1) @timestamp
默认的,当事件插入working memory,会读取(会话时钟)Session Clock的timestamp赋值给事件的startTimestamp。
@timestamp( <attributeName> ) //以毫秒计算
表示把事件的attributeName属性值赋给事件元数据startTimestamp
declare VoiceCall
@role( event )
@timestamp( callDateTime )
end
(2) @duration
Drools支持时间点(point-in-time)事件和时间间隔(interval-based)事件,一个时间点事件可以理解为时间间隔为0。默认,所有的事件的持续时间(duration)为0.我们可以通过@duration标签来修改事件的duration属性值。
@duration( <attributeName> )// 以毫秒计算。
表示把事件的attributeName属性值赋给事件元数据duration
declare VoiceCall
@role( event )
@timestamp( callDateTime )
end
(3)@expires
这个标签在引擎为Stream模式下才有效。默认的,当一个事件不在匹配(match)事实,激活规则(有活化的规则),事件自动失效(回收).
@expires( <timeOffset> )
显示的定义事件的失效时间。
timeOffset可以是下列形式:
[#d][#h][#m][#s][#[ms]]
[]表示是可选参数
declare VoiceCall
@role( event )
@timestamp( callDateTime )
@duration( callDuration )
@expires( 1h35m )
end
VoiceCall事件在1小时35分钟后过期。
二、会话时钟(Session Clock)
Drools 5提供2种时钟。默认的是基于系统时间的即时时钟(real time clock)。另一个是虚拟(pseudo clock)时钟,可以手动控制。
1. 即时时钟(Real Time Clock)
虽然Drools默认使用即时时钟,我们仍然可以显示的配置:
KnowledgeSessionConfiguration config = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
config.setOption( ClockTypeOption.get("realtime") );
2. 配置虚拟时钟(Pseudo Clock)
KnowledgeSessionConfiguration config = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
config.setOption( ClockTypeOption.get("pseudo") );
怎样控制虚拟时钟的例子:
KnowledgeSessionConfiguration conf = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
conf.setOption( ClockTypeOption.get( "pseudo" ) );
StatefulKnowledgeSession session = kbase.newStatefulKnowledgeSession( conf, null );
SessionPseudoClock clock = session.getSessionClock();
// then, while inserting facts, advance the clock as necessary:
FactHandle handle1 = session.insert( tick1 );
clock.advanceTime( 10, TimeUnit.SECONDS );
FactHandle handle2 = session.insert( tick2 );
clock.advanceTime( 30, TimeUnit.SECONDS );
FactHandle handle3 = session.insert( tick3 );
新的SessionPseudoClock时间值为0毫秒,new Date(0) 为GMT 1970 年 1 月 1 日 00:00:00 ,
clock.advanceTime( 10, TimeUnit.SECONDS ); SessionPseudoClock时间值+10秒。
三、Entry Points
一个entry point是事实(facts)或者事件(events)进入引擎的入口点。
1.声明Entry Points
rule "authorize withdraw"
when
WithdrawRequest( $ai : accountId, $am : amount ) from entry-point "ATM Stream"
CheckingAccount( accountId == $ai, balance > $am )
then
// authorize withdraw
end
只有账户的余额大于提款请求的金额,规则才被激活
2.使用Entry Points
// create your rulebase and your session as usual
StatefulKnowledgeSession session = ...
// get a reference to the entry point
WorkingMemoryEntryPoint atmStream = session.getWorkingMemoryEntryPoint( "ATM Stream" );
// and start inserting your facts into the entry point
atmStream.insert( aWithdrawRequest );
通常情况下,我们不需要硬编码把事实插入到WorkingMemory中,通过Drools pipeline,
将从JMS或者 其他非java对象的数据源 中获得信息(对象)插入到WorkingMemory。
默认的entry point是"DEFAULT",是事实进入WorkingMemory的入口点。
session.insert(fact)实际上是session.getWorkingMemoryEntryPoint("DEFAULT").insert(fact)。
四、时间推理(Temporal Reasoning)
Drools 实现了由Allen定义的13种时间操作运算
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
Temporal Operators ┃ Illustration ┃ Interpretation
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x before y ┃ ___y___ ┃ X发生在y之前
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___y___ ┃
x after y ┃ ___x___ ┃ X发生在y之后
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x meets y ┃ ___y___ ┃ x结束时y开始
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___y___ ┃
x metby y ┃ ___x___ ┃ y结束时x开始
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x overlaps y ┃ ______y______ ┃ x开始在y之前,结束在y之后
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x overlappedby y ┃ ______y______ ┃ x开始在y之后,结束在y之前
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x starts y ┃ ______y______ ┃ x和y同时开始,结束在y之前
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x startedby y ┃ ___y___ ┃ x和y同时开始,结束在y之后
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x during y ┃ ______y______ ┃ x发生在y期间
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x includes y ┃ ___y___ ┃ y发生在x期间
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x finishes y ┃ ______y______ ┃X开始在y之后,同y一起结束
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x finishedby y ┃ ___y___ ┃X开始在y之前,同y一起结束
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x coincides y ┃ y ┃ X和y同时发生
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
1.before
$eventA : EventA( this before[ 3m30s, 4m ] $eventB )
也就是:
3m30s <= $eventB.startTimestamp - $eventA.endTimeStamp <= 4m
before操作符的时间间隔距离是可选的:
如果2个值都被定义了,间隔开始于第1个值,结束于第2个值。
如果只有1个值被定义,间隔开始于该值,结束于正无穷大。
如果没有值定义,间隔开始于1毫秒,结束于正无穷大。
时间间隔距离也可以是负数的,例:
$eventA : EventA( this before[ -3m30s, -2m ] $eventB )
注意:当时间间隔第1个值大于第2个值时,引擎会自动的调换他们。
2.After
$eventA : EventA( this after[ 3m30s, 4m ] $eventB )
也就是:
3m30s <= $eventA.startTimestamp - $eventB.endTimeStamp <= 4m
after操作符的时间间隔距离是可选的:
如果2个值都被定义了,间隔开始于第1个值,结束于第2个值。
如果只有1个值被定义,间隔开始于该值,结束于正无穷大。
如果没有值定义,间隔开始于1毫秒,结束于正无穷大。
时间间隔距离也可以是负数的,例:
$eventA : EventA( this after[ -3m30s, -2m ] $eventB )
注意:当时间间隔第1个值大于第2个值时,引擎会自动的调换他们。
3.meets
$eventA : EventA( this meets $eventB )
也就是:
abs( $eventB.startTimestamp - $eventA.endTimestamp ) == 0
meets操作符有1个可选参数
$eventA : EventA( this meets[ 5s ] $eventB )
也就是:
abs( $eventB.startTimestamp - $eventA.endTimestamp) <= 5s
注意:时间间隔不能为负
4.metby
$eventA : EventA( this metby $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.endTimestamp ) == 0
metby操作符有1个可选参数
$eventA : EventA( this metby[ 5s ] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.endTimestamp) <= 5s
注意:时间间隔不能为负
5.overlaps
$eventA : EventA( this overlaps $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp < $eventA.endTimestamp < $eventB.endTimestamp
overlaps操作符有1个/2个可选参数
$eventA : EventA( this overlaps[ 5s ] $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp < $eventA.endTimestamp < $eventB.endTimestamp &&
0 <= $eventA.endTimestamp - $eventB.startTimestamp <= 5s
$eventA : EventA( this overlaps[ 5s, 10s ] $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp < $eventA.endTimestamp < $eventB.endTimestamp &&
5s <= $eventA.endTimestamp - $eventB.startTimestamp <= 10s
6.overlappedby
eventA : EventA( this overlappedby $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp < $eventB.endTimestamp < $eventA.endTimestamp
overlappedby操作符有1个/2个可选参数
$eventA : EventA( this overlappedby[ 5s ] $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp < $eventB.endTimestamp < $eventA.endTimestamp &&
0 <= $eventB.endTimestamp - $eventA.startTimestamp <= 5s
$eventA : EventA( this overlappedby[ 5s, 10s ] $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp < $eventB.endTimestamp < $eventA.endTimestamp &&
5s <= $eventB.endTimestamp - $eventA.startTimestamp <= 10s
7.starts
$eventA : EventA( this starts $eventB )
也就是:
$eventA.startTimestamp == $eventB.startTimestamp &&
$eventA.endTimestamp < $eventB.endTimestamp
starts操作符有1个可选参数
$eventA : EventA( this starts[ 5s ] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.startTimestamp ) <= 5s &&
$eventA.endTimestamp < $eventB.endTimestamp
注意:时间间隔不能为负
8.startedby
$eventA : EventA( this startedby $eventB )
也就是:
$eventA.startTimestamp == $eventB.startTimestamp &&
$eventA.endTimestamp > $eventB.endTimestamp
starts操作符有1个可选参数
$eventA : EventA( this starts[ 5s ] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.startTimestamp ) <= 5s &&
$eventA.endTimestamp > $eventB.endTimestamp
注意:时间间隔不能为负
9.during
$eventA : EventA( this during $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp <= $eventA.endTimestamp < $eventB.endTimestamp
during操作符有1个/2个/4个可选参数
$eventA : EventA( this during[ 5s ] $eventB )
也就是:
0 < $eventA.startTimestamp - $eventB.startTimestamp <= 5s &&
0 < $eventB.endTimestamp - $eventA.endTimestamp <= 5s
$eventA : EventA( this during[ 5s, 10s ] $eventB )
也就是:
5s <= $eventA.startTimestamp - $eventB.startTimestamp <= 10s &&
5s <= $eventB.endTimestamp - $eventA.endTimestamp <= 10s
$eventA : EventA( this during[ 2s, 6s, 4s, 10s ] $eventB )
也就是:
2s <= $eventA.startTimestamp - $eventB.startTimestamp <= 6s &&
4s <= $eventB.endTimestamp - $eventA.endTimestamp <= 10s
10.includes
$eventA : EventA( this includes $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp <= $eventB.endTimestamp < $eventA.endTimestamp
includes操作符有1个/2个/4个可选参数
$eventA : EventA( this includes[ 5s ] $eventB )
也就是:
0 < $eventB.startTimestamp - $eventA.startTimestamp <= 5s &&
0 < $eventA.endTimestamp - $eventB.endTimestamp <= 5s
$eventA : EventA( this includes[ 5s, 10s ] $eventB )
也就是:
5s <= $eventB.startTimestamp - $eventA.startTimestamp <= 10s &&
5s <= $eventA.endTimestamp - $eventB.endTimestamp <= 10s
$eventA : EventA( this includes[ 2s, 6s, 4s, 10s ] $eventB )
也就是:
2s <= $eventB.startTimestamp - $eventA.startTimestamp <= 6s &&
4s <= $eventA.endTimestamp - $eventB.endTimestamp <= 10s
11.finishes
$eventA : EventA( this finishes $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp &&
$eventA.endTimestamp == $eventB.endTimestamp
finishes操作符有1个可选参数
$eventA : EventA( this finishes[ 5s ] $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp &&
abs( $eventA.endTimestamp - $eventB.endTimestamp ) <= 5s
注意:时间间隔不能为负
12.finishedby
$eventA : EventA( this finishedby $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp &&
$eventA.endTimestamp == $eventB.endTimestamp
finishedby操作符有1个可选参数
$eventA : EventA( this finishedby[ 5s ] $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp &&
abs( $eventA.endTimestamp - $eventB.endTimestamp ) <= 5s
注意:时间间隔不能为负
13.coincides
$eventA : EventA( this coincides $eventB )
也就是:
$eventA.startTimestamp ==$eventB.startTimestamp &&
$eventA.endTimestamp == $eventB.endTimestamp
finishedby操作符有1个/2个可选参数
$eventA : EventA( this coincides[15s] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.startTimestamp ) <= 15s &&
abs( $eventA.endTimestamp - $eventB.endTimestamp ) <= 15s
$eventA : EventA( this coincides[15s, 10s] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.startTimestamp ) <= 15s &&
abs( $eventA.endTimestamp - $eventB.endTimestamp ) <= 10s
注意:时间间隔不能为负
五、事件处理模式(Event Processing Modes)
Drools支持2种事件处理模式:云模式(Cloud Mode)和流模式(Stream Mode)
1.云模式(Cloud Mode)
云(Cloud)处理模式是默认的处理方式。
在云模式下,不会区分事实和事件,都看成是事实。
(1)没有时间的概念。尽管事件在插入引擎被赋予了时间戳,也不能判断该事件“多大了”,因为没有“现在”的概念。滑动窗(sliding windows)基于“现在”的概念,所以在云模式下无法使用。
(2)无序的事件云。由于事件无序,没有自动的生命周期管理,需要像正常的事实一样显示的删除事件。
云模式虽然是默认的执行模式,我们也可以配置它:
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( EventProcessingOption.CLOUD );
等同系统属性配置:
drools.eventProcessingMode = cloud
2.流模式(Stream Mode)
当处理事件流的时候需要选择流处理模式。
在流模式下:
(1) 插入到引擎里的事件必须是时间顺序的。
(2) 引擎强制性的和使用的会话时钟session clock同步。
配置流模式:
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );
等同配置系统属性:
drools.eventProcessingMode = stream
使用流(STREAM)模式,引擎有时间流和"现在"的概念(通过读取Session Clock的时间戳),
提供了以下3种支持:
(1) 滑动窗的支持
(2) 自动的时间生命周期管理
(3) 使用消极模式(Negative Patterns)自动的规则延迟
3.会话时钟(Session Clock)在流模式(Stream mode)中的作用
在云模式下,会话时钟只有一个作用,就是给插入到working momery 的事件赋予时间戳的值(如果规则没有定义时间戳属性)
在流模式下,会话时钟负责维护当前时间戳,基于当前的时间戳,引擎根据事件的年龄计算所有时间运算,从多种源同步流,安排未来任务等等。
4.流模式(in Stream Mode)中的消极模式(Negative Patterns)
消极模式在流模式和云模式意义是不同的。
在云模式下,所有的事实和事件都是预先知道的,消极模式立即计算执行
//a rule that activates immediately upon matching
rule "Sound the alarm"
when
$f : FireDetected( )
not( SprinklerActivated( ) )
then
// sound the alarm
end
在流模式下,带有时间约束的消极模式可以要求引擎等待一段时间后激活规则。
//a rule that automatically delays activation due to temporal constraints
rule "Sound the alarm"
when
$f : FireDetected( )
not( SprinklerActivated( this after[0s,10s] $f ) )
then
// sound the alarm
end
六. 滑动窗(Sliding Windows)
滑动窗是一种选择事件范围的方式。
滑动窗有2种实现方式:滑动时间窗(Sliding Time Windows),滑动长度窗(Sliding Length Windows)。
注意:滑动窗只有在引擎为(STREAM)流模式下才是可用的
1.滑动时间窗(Sliding Time Windows)
滑动时间窗(允许我们的规则)仅仅匹配发生在最近X时间单元的事件。
例如,如果只关心最近2分钟的股票行情,模式(pattern)可以这样写:
StockTick() over window:time( 2m )
更复杂的例子:
如果最近10分钟从传感器读来的温度高于最大的临界值,发出警报。
rule "Sound the alarm in case temperature rises above threshold"
when
TemperatureThreshold( $max : max )
Number( doubleValue > $max ) from accumulate(
SensorReading( $temp : temperature ) over window:time( 10m ),
average( $temp ) )
then
// sound the alarm
end
2.滑动长度窗(Sliding Length Windows)
滑动长度窗(允许我们的规则)仅仅匹配发生在最近X个的事件。
例如,如果只关心最近10个IBM股票的行情,模式(pattern)可以这样写:
StockTick( company == "IBM" ) over window:length( 10 )
更复杂的例子:
如果最近100次从传感器读来的温度高于最大的临界值,发出警报。
rule "Sound the alarm in case temperature rises above threshold"
when
TemperatureThreshold( $max : max )
Number( doubleValue > $max ) from accumulate(
SensorReading( $temp : temperature ) over window:length( 100 ),
average( $temp ) )
then
// sound the alarm
end
七.Knowledgebase分割(Partitioning)
(注意:这是个实验性的特征,将来可能会发生变化)
传统的Rete算法通常一个线程在执行,也是Drools默认的。但是,该算法本身是可平行(化)的。Drools执行的ReteOO算法通过Knowledgebase分割支持粗粒度的平行执行。
当这个选项可用,Knowledgebase分割成若干个独立的区域,然后用线程池通过这些区域传播事实。该实现保证最多有一个线程在给定的一个区域执行。
要点:这个特征只在LHS平行执行可用,不会改变规则激活行为。
1.平行执行在什么时候有益:
(1)多处理器
(2)knowledge session处理大量的事实
(3)规则的LHS计算量大
(4)knowledge base包含数百或者更多的规则
如果以上条件都符合,这个特征可能会提高knowledgebase计算总性能。
2.配置Knowledgebase分割
//enabling multithread evaluation (partitioning)
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( MultithreadEvaluationOption.YES );
等同系统属性配置:
drools.multithreadEvaluation = <true|false>
3.多线程管理
配置线程池:
//setting the maximum number of threads for rule evaluation to 5
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( MaxThreadsOption.get(5) );
等同系统属性配置:
drools.maxThreads = <-1|1..n>
配置默认值是3,负数值表示在Knowledgebase中有多少分区,引擎就会产生多少线程,使用负数值是很危险的。
八.事件的内存管理
要点:自动的事件内存管理只有在引擎为Stream模式下才有效。
引擎在Steam模式下的好处之一是引擎能够根据时间约束检测出不再匹配任何规则的事件,然后引擎可以没有负作用的安全地回收事件并释放其相关的资源。
引擎有2种基本方式计算一个事件有效期:
(1)显式,使用过期(expiration)策略
(2)隐式,分析事件的时间约束
1.显式的过期偏移量(有效期)
//explicitly defining an expiration offset of 30 minutes for StockTick events
declare StockTick
@expires( 30m )
end
当StockTick事件持续30分钟后,如果没有规则需要该事件,引擎将自动的回收该事件。
2.推知的过期偏移量
//example rule with temporal constraints
rule "correlate orders"
when
$bo : BuyOrderEvent( $id : id )
$ae : AckEvent( id == $id, this after[0,10s] $bo )
then
// do something
end
引擎需要保存BuyOrderEvent 10秒以匹配AckEvent。
BuyOrderEvent隐式的过期偏移量是10秒,AckEvent隐式的过期偏移量是0。
引擎会分析整个Knowledgebase,找出每个事件类型的过期偏移量。当隐式过期偏移量和显式过期偏移量冲突时,引擎会选择2个值中最大的1个
作者:forge(作者的Blog:http://forge.iteye.com)
原文:http://forge.iteye.com/blog/571047
Drools Fusion Features
Fusion 是业务逻辑集成平台(Business Logic Integration Platform)一部分,是一个CEP/ESP引擎。
事件,是指在应用程序域中有意义状态改变的记录
一个复杂事件是简单事件的集合。CEP(Complex Event Processing) 处理复杂事件-从事件云中检测并选择事件,根据选择的事件和他们建立的关系发现他们的关系推理出新的数据。
比如,一系列的巨额提款激发可疑交易事件的发生。一个复杂事件的发生是由一系列简单事件的引导形成的。
ESP(Event Stream Processing) 是更实时(real-time)的大量事件处理。例如,根据时间计算实时平均交易量。
一、事件(Events).
从drools视图来看,事件就是一个特殊的事实(fact)。我们说,所有的事件都是事实,但是所有的事实并不都是事件。
1.事件和事实不同特征:
(1)通常不可变:事件是在应用程序域中状态改变的记录,记录已经发生的事情,可变的事件是没有意义的。
应用程序允许给没有赋值的事件属性赋值,但是已经赋值的属性是不应该被改变的。
(2)强时间约束:规则涉及的事件通常需要多个事件的相互关系,尤其某个事件相对其他事件发生的时间点的时间关系。
(3)可管理的生命周期:由于上两个事件特征的原因,事件通常在一个有限的时间窗(Time Window)匹配事件和事实,
这就让引擎管理事件的生命周期成为可能。一个事件插入working memory,引擎有能力发现一个不在匹配
其他事实的事件,然后自动回收它,释放相关的资源。
(4)滑动窗( sliding windows)的使用:由于所有的事件都有关联的时间戳,可以定义并使用滑动窗,让事件在特定的一段时间有效。
2.事件声明:
import some.package.StockTick
declare StockTick
@role( event )
end
将一个已有的StockTick(类)事实生命为事件类型
@role 元数据接受2个值:
fact:默认值,声明为常规的事实
event:声明为事件
由于Drools支持在DRL中声明一个事实,可以去掉StockTick(类),还可以这样:
declare StockTick
@role( event )
datetime : java.util.Date
symbol : String
price : double
end
3.事件元数据
所有的事件都有一个事件元数据集合。当事件插入working memory,事件元数据会自动赋予默认值,我们可以用元数据标签改变他们的默认值。
假设我们有这样的一个实体类:
/**
* A class that represents a voice call in
* a Telecom domain model
*/
public class VoiceCall {
private String originNumber;
private String destinationNumber;
private Date callDateTime;
private long callDuration; // in milliseconds
// constructors, getters and setters
}
(1) @timestamp
默认的,当事件插入working memory,会读取(会话时钟)Session Clock的timestamp赋值给事件的startTimestamp。
@timestamp( <attributeName> ) //以毫秒计算
表示把事件的attributeName属性值赋给事件元数据startTimestamp
declare VoiceCall
@role( event )
@timestamp( callDateTime )
end
(2) @duration
Drools支持时间点(point-in-time)事件和时间间隔(interval-based)事件,一个时间点事件可以理解为时间间隔为0。默认,所有的事件的持续时间(duration)为0.我们可以通过@duration标签来修改事件的duration属性值。
@duration( <attributeName> )// 以毫秒计算。
表示把事件的attributeName属性值赋给事件元数据duration
declare VoiceCall
@role( event )
@timestamp( callDateTime )
end
(3)@expires
这个标签在引擎为Stream模式下才有效。默认的,当一个事件不在匹配(match)事实,激活规则(有活化的规则),事件自动失效(回收).
@expires( <timeOffset> )
显示的定义事件的失效时间。
timeOffset可以是下列形式:
[#d][#h][#m][#s][#[ms]]
[]表示是可选参数
declare VoiceCall
@role( event )
@timestamp( callDateTime )
@duration( callDuration )
@expires( 1h35m )
end
VoiceCall事件在1小时35分钟后过期。
二、会话时钟(Session Clock)
Drools 5提供2种时钟。默认的是基于系统时间的即时时钟(real time clock)。另一个是虚拟(pseudo clock)时钟,可以手动控制。
1. 即时时钟(Real Time Clock)
虽然Drools默认使用即时时钟,我们仍然可以显示的配置:
KnowledgeSessionConfiguration config = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
config.setOption( ClockTypeOption.get("realtime") );
2. 配置虚拟时钟(Pseudo Clock)
KnowledgeSessionConfiguration config = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
config.setOption( ClockTypeOption.get("pseudo") );
怎样控制虚拟时钟的例子:
KnowledgeSessionConfiguration conf = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
conf.setOption( ClockTypeOption.get( "pseudo" ) );
StatefulKnowledgeSession session = kbase.newStatefulKnowledgeSession( conf, null );
SessionPseudoClock clock = session.getSessionClock();
// then, while inserting facts, advance the clock as necessary:
FactHandle handle1 = session.insert( tick1 );
clock.advanceTime( 10, TimeUnit.SECONDS );
FactHandle handle2 = session.insert( tick2 );
clock.advanceTime( 30, TimeUnit.SECONDS );
FactHandle handle3 = session.insert( tick3 );
新的SessionPseudoClock时间值为0毫秒,new Date(0) 为GMT 1970 年 1 月 1 日 00:00:00 ,
clock.advanceTime( 10, TimeUnit.SECONDS ); SessionPseudoClock时间值+10秒。
三、Entry Points
一个entry point是事实(facts)或者事件(events)进入引擎的入口点。
1.声明Entry Points
rule "authorize withdraw"
when
WithdrawRequest( $ai : accountId, $am : amount ) from entry-point "ATM Stream"
CheckingAccount( accountId == $ai, balance > $am )
then
// authorize withdraw
end
只有账户的余额大于提款请求的金额,规则才被激活
2.使用Entry Points
// create your rulebase and your session as usual
StatefulKnowledgeSession session = ...
// get a reference to the entry point
WorkingMemoryEntryPoint atmStream = session.getWorkingMemoryEntryPoint( "ATM Stream" );
// and start inserting your facts into the entry point
atmStream.insert( aWithdrawRequest );
通常情况下,我们不需要硬编码把事实插入到WorkingMemory中,通过Drools pipeline,
将从JMS或者 其他非java对象的数据源 中获得信息(对象)插入到WorkingMemory。
默认的entry point是"DEFAULT",是事实进入WorkingMemory的入口点。
session.insert(fact)实际上是session.getWorkingMemoryEntryPoint("DEFAULT").insert(fact)。
四、时间推理(Temporal Reasoning)
Drools 实现了由Allen定义的13种时间操作运算
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
Temporal Operators ┃ Illustration ┃ Interpretation
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x before y ┃ ___y___ ┃ X发生在y之前
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___y___ ┃
x after y ┃ ___x___ ┃ X发生在y之后
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x meets y ┃ ___y___ ┃ x结束时y开始
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___y___ ┃
x metby y ┃ ___x___ ┃ y结束时x开始
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x overlaps y ┃ ______y______ ┃ x开始在y之前,结束在y之后
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x overlappedby y ┃ ______y______ ┃ x开始在y之后,结束在y之前
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x starts y ┃ ______y______ ┃ x和y同时开始,结束在y之前
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x startedby y ┃ ___y___ ┃ x和y同时开始,结束在y之后
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x during y ┃ ______y______ ┃ x发生在y期间
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x includes y ┃ ___y___ ┃ y发生在x期间
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x finishes y ┃ ______y______ ┃X开始在y之后,同y一起结束
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x finishedby y ┃ ___y___ ┃X开始在y之前,同y一起结束
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x coincides y ┃ y ┃ X和y同时发生
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
1.before
$eventA : EventA( this before[ 3m30s, 4m ] $eventB )
也就是:
3m30s <= $eventB.startTimestamp - $eventA.endTimeStamp <= 4m
before操作符的时间间隔距离是可选的:
如果2个值都被定义了,间隔开始于第1个值,结束于第2个值。
如果只有1个值被定义,间隔开始于该值,结束于正无穷大。
如果没有值定义,间隔开始于1毫秒,结束于正无穷大。
时间间隔距离也可以是负数的,例:
$eventA : EventA( this before[ -3m30s, -2m ] $eventB )
注意:当时间间隔第1个值大于第2个值时,引擎会自动的调换他们。
2.After
$eventA : EventA( this after[ 3m30s, 4m ] $eventB )
也就是:
3m30s <= $eventA.startTimestamp - $eventB.endTimeStamp <= 4m
after操作符的时间间隔距离是可选的:
如果2个值都被定义了,间隔开始于第1个值,结束于第2个值。
如果只有1个值被定义,间隔开始于该值,结束于正无穷大。
如果没有值定义,间隔开始于1毫秒,结束于正无穷大。
时间间隔距离也可以是负数的,例:
$eventA : EventA( this after[ -3m30s, -2m ] $eventB )
注意:当时间间隔第1个值大于第2个值时,引擎会自动的调换他们。
3.meets
$eventA : EventA( this meets $eventB )
也就是:
abs( $eventB.startTimestamp - $eventA.endTimestamp ) == 0
meets操作符有1个可选参数
$eventA : EventA( this meets[ 5s ] $eventB )
也就是:
abs( $eventB.startTimestamp - $eventA.endTimestamp) <= 5s
注意:时间间隔不能为负
4.metby
$eventA : EventA( this metby $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.endTimestamp ) == 0
metby操作符有1个可选参数
$eventA : EventA( this metby[ 5s ] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.endTimestamp) <= 5s
注意:时间间隔不能为负
5.overlaps
$eventA : EventA( this overlaps $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp < $eventA.endTimestamp < $eventB.endTimestamp
overlaps操作符有1个/2个可选参数
$eventA : EventA( this overlaps[ 5s ] $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp < $eventA.endTimestamp < $eventB.endTimestamp &&
0 <= $eventA.endTimestamp - $eventB.startTimestamp <= 5s
$eventA : EventA( this overlaps[ 5s, 10s ] $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp < $eventA.endTimestamp < $eventB.endTimestamp &&
5s <= $eventA.endTimestamp - $eventB.startTimestamp <= 10s
6.overlappedby
eventA : EventA( this overlappedby $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp < $eventB.endTimestamp < $eventA.endTimestamp
overlappedby操作符有1个/2个可选参数
$eventA : EventA( this overlappedby[ 5s ] $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp < $eventB.endTimestamp < $eventA.endTimestamp &&
0 <= $eventB.endTimestamp - $eventA.startTimestamp <= 5s
$eventA : EventA( this overlappedby[ 5s, 10s ] $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp < $eventB.endTimestamp < $eventA.endTimestamp &&
5s <= $eventB.endTimestamp - $eventA.startTimestamp <= 10s
7.starts
$eventA : EventA( this starts $eventB )
也就是:
$eventA.startTimestamp == $eventB.startTimestamp &&
$eventA.endTimestamp < $eventB.endTimestamp
starts操作符有1个可选参数
$eventA : EventA( this starts[ 5s ] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.startTimestamp ) <= 5s &&
$eventA.endTimestamp < $eventB.endTimestamp
注意:时间间隔不能为负
8.startedby
$eventA : EventA( this startedby $eventB )
也就是:
$eventA.startTimestamp == $eventB.startTimestamp &&
$eventA.endTimestamp > $eventB.endTimestamp
starts操作符有1个可选参数
$eventA : EventA( this starts[ 5s ] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.startTimestamp ) <= 5s &&
$eventA.endTimestamp > $eventB.endTimestamp
注意:时间间隔不能为负
9.during
$eventA : EventA( this during $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp <= $eventA.endTimestamp < $eventB.endTimestamp
during操作符有1个/2个/4个可选参数
$eventA : EventA( this during[ 5s ] $eventB )
也就是:
0 < $eventA.startTimestamp - $eventB.startTimestamp <= 5s &&
0 < $eventB.endTimestamp - $eventA.endTimestamp <= 5s
$eventA : EventA( this during[ 5s, 10s ] $eventB )
也就是:
5s <= $eventA.startTimestamp - $eventB.startTimestamp <= 10s &&
5s <= $eventB.endTimestamp - $eventA.endTimestamp <= 10s
$eventA : EventA( this during[ 2s, 6s, 4s, 10s ] $eventB )
也就是:
2s <= $eventA.startTimestamp - $eventB.startTimestamp <= 6s &&
4s <= $eventB.endTimestamp - $eventA.endTimestamp <= 10s
10.includes
$eventA : EventA( this includes $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp <= $eventB.endTimestamp < $eventA.endTimestamp
includes操作符有1个/2个/4个可选参数
$eventA : EventA( this includes[ 5s ] $eventB )
也就是:
0 < $eventB.startTimestamp - $eventA.startTimestamp <= 5s &&
0 < $eventA.endTimestamp - $eventB.endTimestamp <= 5s
$eventA : EventA( this includes[ 5s, 10s ] $eventB )
也就是:
5s <= $eventB.startTimestamp - $eventA.startTimestamp <= 10s &&
5s <= $eventA.endTimestamp - $eventB.endTimestamp <= 10s
$eventA : EventA( this includes[ 2s, 6s, 4s, 10s ] $eventB )
也就是:
2s <= $eventB.startTimestamp - $eventA.startTimestamp <= 6s &&
4s <= $eventA.endTimestamp - $eventB.endTimestamp <= 10s
11.finishes
$eventA : EventA( this finishes $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp &&
$eventA.endTimestamp == $eventB.endTimestamp
finishes操作符有1个可选参数
$eventA : EventA( this finishes[ 5s ] $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp &&
abs( $eventA.endTimestamp - $eventB.endTimestamp ) <= 5s
注意:时间间隔不能为负
12.finishedby
$eventA : EventA( this finishedby $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp &&
$eventA.endTimestamp == $eventB.endTimestamp
finishedby操作符有1个可选参数
$eventA : EventA( this finishedby[ 5s ] $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp &&
abs( $eventA.endTimestamp - $eventB.endTimestamp ) <= 5s
注意:时间间隔不能为负
13.coincides
$eventA : EventA( this coincides $eventB )
也就是:
$eventA.startTimestamp ==$eventB.startTimestamp &&
$eventA.endTimestamp == $eventB.endTimestamp
finishedby操作符有1个/2个可选参数
$eventA : EventA( this coincides[15s] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.startTimestamp ) <= 15s &&
abs( $eventA.endTimestamp - $eventB.endTimestamp ) <= 15s
$eventA : EventA( this coincides[15s, 10s] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.startTimestamp ) <= 15s &&
abs( $eventA.endTimestamp - $eventB.endTimestamp ) <= 10s
注意:时间间隔不能为负
五、事件处理模式(Event Processing Modes)
Drools支持2种事件处理模式:云模式(Cloud Mode)和流模式(Stream Mode)
1.云模式(Cloud Mode)
云(Cloud)处理模式是默认的处理方式。
在云模式下,不会区分事实和事件,都看成是事实。
(1)没有时间的概念。尽管事件在插入引擎被赋予了时间戳,也不能判断该事件“多大了”,因为没有“现在”的概念。滑动窗(sliding windows)基于“现在”的概念,所以在云模式下无法使用。
(2)无序的事件云。由于事件无序,没有自动的生命周期管理,需要像正常的事实一样显示的删除事件。
云模式虽然是默认的执行模式,我们也可以配置它:
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( EventProcessingOption.CLOUD );
等同系统属性配置:
drools.eventProcessingMode = cloud
2.流模式(Stream Mode)
当处理事件流的时候需要选择流处理模式。
在流模式下:
(1) 插入到引擎里的事件必须是时间顺序的。
(2) 引擎强制性的和使用的会话时钟session clock同步。
配置流模式:
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );
等同配置系统属性:
drools.eventProcessingMode = stream
使用流(STREAM)模式,引擎有时间流和"现在"的概念(通过读取Session Clock的时间戳),
提供了以下3种支持:
(1) 滑动窗的支持
(2) 自动的时间生命周期管理
(3) 使用消极模式(Negative Patterns)自动的规则延迟
3.会话时钟(Session Clock)在流模式(Stream mode)中的作用
在云模式下,会话时钟只有一个作用,就是给插入到working momery 的事件赋予时间戳的值(如果规则没有定义时间戳属性)
在流模式下,会话时钟负责维护当前时间戳,基于当前的时间戳,引擎根据事件的年龄计算所有时间运算,从多种源同步流,安排未来任务等等。
4.流模式(in Stream Mode)中的消极模式(Negative Patterns)
消极模式在流模式和云模式意义是不同的。
在云模式下,所有的事实和事件都是预先知道的,消极模式立即计算执行
//a rule that activates immediately upon matching
rule "Sound the alarm"
when
$f : FireDetected( )
not( SprinklerActivated( ) )
then
// sound the alarm
end
在流模式下,带有时间约束的消极模式可以要求引擎等待一段时间后激活规则。
//a rule that automatically delays activation due to temporal constraints
rule "Sound the alarm"
when
$f : FireDetected( )
not( SprinklerActivated( this after[0s,10s] $f ) )
then
// sound the alarm
end
六. 滑动窗(Sliding Windows)
滑动窗是一种选择事件范围的方式。
滑动窗有2种实现方式:滑动时间窗(Sliding Time Windows),滑动长度窗(Sliding Length Windows)。
注意:滑动窗只有在引擎为(STREAM)流模式下才是可用的
1.滑动时间窗(Sliding Time Windows)
滑动时间窗(允许我们的规则)仅仅匹配发生在最近X时间单元的事件。
例如,如果只关心最近2分钟的股票行情,模式(pattern)可以这样写:
StockTick() over window:time( 2m )
更复杂的例子:
如果最近10分钟从传感器读来的温度高于最大的临界值,发出警报。
rule "Sound the alarm in case temperature rises above threshold"
when
TemperatureThreshold( $max : max )
Number( doubleValue > $max ) from accumulate(
SensorReading( $temp : temperature ) over window:time( 10m ),
average( $temp ) )
then
// sound the alarm
end
2.滑动长度窗(Sliding Length Windows)
滑动长度窗(允许我们的规则)仅仅匹配发生在最近X个的事件。
例如,如果只关心最近10个IBM股票的行情,模式(pattern)可以这样写:
StockTick( company == "IBM" ) over window:length( 10 )
更复杂的例子:
如果最近100次从传感器读来的温度高于最大的临界值,发出警报。
rule "Sound the alarm in case temperature rises above threshold"
when
TemperatureThreshold( $max : max )
Number( doubleValue > $max ) from accumulate(
SensorReading( $temp : temperature ) over window:length( 100 ),
average( $temp ) )
then
// sound the alarm
end
七.Knowledgebase分割(Partitioning)
(注意:这是个实验性的特征,将来可能会发生变化)
传统的Rete算法通常一个线程在执行,也是Drools默认的。但是,该算法本身是可平行(化)的。Drools执行的ReteOO算法通过Knowledgebase分割支持粗粒度的平行执行。
当这个选项可用,Knowledgebase分割成若干个独立的区域,然后用线程池通过这些区域传播事实。该实现保证最多有一个线程在给定的一个区域执行。
要点:这个特征只在LHS平行执行可用,不会改变规则激活行为。
1.平行执行在什么时候有益:
(1)多处理器
(2)knowledge session处理大量的事实
(3)规则的LHS计算量大
(4)knowledge base包含数百或者更多的规则
如果以上条件都符合,这个特征可能会提高knowledgebase计算总性能。
2.配置Knowledgebase分割
//enabling multithread evaluation (partitioning)
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( MultithreadEvaluationOption.YES );
等同系统属性配置:
drools.multithreadEvaluation = <true|false>
3.多线程管理
配置线程池:
//setting the maximum number of threads for rule evaluation to 5
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( MaxThreadsOption.get(5) );
等同系统属性配置:
drools.maxThreads = <-1|1..n>
配置默认值是3,负数值表示在Knowledgebase中有多少分区,引擎就会产生多少线程,使用负数值是很危险的。
八.事件的内存管理
要点:自动的事件内存管理只有在引擎为Stream模式下才有效。
引擎在Steam模式下的好处之一是引擎能够根据时间约束检测出不再匹配任何规则的事件,然后引擎可以没有负作用的安全地回收事件并释放其相关的资源。
引擎有2种基本方式计算一个事件有效期:
(1)显式,使用过期(expiration)策略
(2)隐式,分析事件的时间约束
1.显式的过期偏移量(有效期)
//explicitly defining an expiration offset of 30 minutes for StockTick events
declare StockTick
@expires( 30m )
end
当StockTick事件持续30分钟后,如果没有规则需要该事件,引擎将自动的回收该事件。
2.推知的过期偏移量
//example rule with temporal constraints
rule "correlate orders"
when
$bo : BuyOrderEvent( $id : id )
$ae : AckEvent( id == $id, this after[0,10s] $bo )
then
// do something
end
引擎需要保存BuyOrderEvent 10秒以匹配AckEvent。
BuyOrderEvent隐式的过期偏移量是10秒,AckEvent隐式的过期偏移量是0。
引擎会分析整个Knowledgebase,找出每个事件类型的过期偏移量。当隐式过期偏移量和显式过期偏移量冲突时,引擎会选择2个值中最大的1个
相关推荐
毕业设计-多商家营销活动平台V1.3.9小程序前后端完整全开源解密源码-整站商业源码.zip
内容概要:本文探讨了电力系统动态状态估计中扩展卡尔曼滤波(EKF)和无迹卡尔曼滤波(UKF)的应用。电力系统状态的精确估计对于提升系统的可靠性、弹性和安全性至关重要。尽管现代测量技术和传输手段的进步减少了误差,但仍存在测量噪声。文中详细介绍了这两种滤波方法的工作原理及其在39节点系统中的实际应用效果。EKF通过线性化处理非线性模型,而UKF则利用Sigma点采样更好地适应强非线性情况。实验结果显示,在面对较大角度变化时,UKF表现出更高的准确性,但在计算效率方面略逊于EKF。 适用人群:从事电力系统研究的专业人士、高校相关专业师生以及对电力系统状态估计感兴趣的科研工作者。 使用场景及目标:适用于希望深入了解电力系统状态估计技术的研究人员和技术人员。目标是在理论层面掌握EKF和UKF的区别与联系,并能够在实践中选择合适的方法应用于具体的电力系统中。 其他说明:为了确保程序能够正常运行,需要提前安装Matpower工具箱。此外,建议读者根据自身需求权衡EKF的速度优势和UKF的精度优势,探索二者结合使用的可能性。
实训商业源码-135k代驾1.2.5 小程序前端+后端-论文模板.zip
实训商业源码-恋爱-论文模板.zip
毕业论文-炫酷微砍价3.0.7开源-整站商业源码.zip
实训商业源码-PHP开发的QQ互联分发源码V1.0 无需申请对接QQ登陆-论文模板.zip
毕业设计-erphpdown9.82美化版-整站商业源码.zip
实训商业源码-淡绿唯美小说网站源码-论文模板.zip
毕业论文-新麦客服 1.2.8-整站商业源码.zip
内容概要:本文探讨了利用粒子群优化(PSO)算法进行微电网系统的优化调度。微电网系统由多个电力发电和储能组件构成,如燃气发电机、锅炉、热回收系统、吸收制冷机、电制冷机和蓄电池储能系统。研究旨在通过PSO算法,在不同时间段找到各组件的最优功率输出,从而最小化运行成本并满足电力、供热和供冷的需求。文中详细介绍了PSO算法的工作机制,包括粒子初始化、位置更新规则以及成本函数的设计。此外,还展示了具体的Python实现代码,讨论了算法的实际表现和一些非直观现象,如最优解倾向于集中负载而非均匀分配,以及储能行为的特殊规律。最后提到了算法的局限性和未来改进方向。 适合人群:对智能优化算法、微电网系统感兴趣的科研人员和技术开发者。 使用场景及目标:适用于希望深入了解微电网优化调度方法的研究者,以及寻求提高微电网运行效率的技术团队。目标是掌握PSO算法的应用技巧,理解微电网调度中的关键因素,进而应用于实际项目中。 其他说明:文中提供的Python代码片段可以帮助读者快速上手实践,而对算法细节的深入剖析则有助于进一步优化和扩展解决方案。
毕业设计-导航网原程序-整站商业源码.zip
Fastdata极数:中国旅游行业年度报告2024.pdf
linux后门权限维持
实训商业源码-小鬼授权源码系统解密版-论文模板.zip
内容概要:本文详细介绍了如何使用FPGA和Verilog硬件描述语言实现一维8点离散余弦变换(DCT),并将其与Matlab的计算结果进行了对比。文中解释了DCT的基本概念及其在信号处理、图像和音频压缩等领域的应用。重点讨论了FPGA实现的优势,包括高灵活性、低功耗和低成本。此外,文章提供了详细的实现步骤,包括定义输入输出数据格式、编写Verilog代码、创建Testbench以及在Vivado环境中进行编译和仿真的具体操作。 适合人群:对FPGA开发和数字信号处理感兴趣的电子工程师、研究人员及高校学生。 使用场景及目标:适用于希望通过FPGA实现高效DCT变换的研究项目和技术开发,旨在提升对DCT算法的理解和实际应用能力。 其他说明:附带的操作视频有助于初学者快速上手,确保工程路径为英文路径以保障Vivado的正常运行。
毕业设计-集字福袋 1.4.8-整站商业源码.zip
WTO最新报告:2025年全球商品贸易量将下降0.2%,中国商品出口将在北美以外地区增长4%至9.pdf
毕业论文-自适应多引擎搜索单页html源码-整站商业源码.zip
毕业论文-无后台版-整站商业源码.zip
实训商业源码-【超人】积分商城 5.2.26-论文模板.zip