DroolsFusion文档翻译整理

版权声明:本文可以自由转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
作者:forge(作者的Blog:[url]http://forge.iteye.com[/url])
原文:[url]http://forge.iteye.com/blog/571047[/url]


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个
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值