Chinaunix首页 | 论坛 | 博客
  • 博客访问: 521677
  • 博文数量: 60
  • 博客积分: 1445
  • 博客等级: 上尉
  • 技术积分: 507
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-14 19:15
文章分类

全部博文(60)

文章存档

2012年(1)

2011年(7)

2010年(52)

我的朋友

分类:

2010-12-26 15:17:13

2.5    事件处理模式 

通常,规则引擎具有一个众所周知的处理数据和规则的方法,并且把结果提供给应用程序。此外,有关事实应该如何被提交给规则引擎并没有太多要求,尤其因为通常情况下,处理本身是时间无关的。对多数场景这是一个好的假定,但并不是所有都是。在要求包含实时或接近实时事件时,时间就成为了推理过程的一个重要变量。 

下面的章节会解释在规则推理中的时间影响,以及Drools提供的用于推理过程的两个模式。 

2.5.1    云(Cloud)模式 

Cloud处理模式是默认处理模式。规则引擎的用户是熟悉这种模式的,因为它的行为是与包含在前面的Drools版本中的任何纯正向链接规则引擎的行为完全相同。 

当运行在Cloud模式时,作为一个整体,引擎了解工作内存中的所有事实,无论是正规事实还是事件。没有时间流的概念,尽管事件象平时一样有一个时间戳。换言之,尽管引擎知道一个给定的事件被创建了,例如,在200911日,09:35:40.767,引擎不可能确定事件是多“老”了,因为没有“现在”的概念。 

在这种模式中,引擎通常会使用多对多模式匹配算法,使用规则约束找到匹配的元组,如平时一样激活并引发规则。 

这种模式并不会对事实强加任何种类的其他要求,因此,例如: 

l  没有时间概念,不要求时钟同步。

l  不要求事件顺序,引擎看事件象一个无序的云,引擎根据它们尝试匹配规则。 

另一方面,因为没有要求,某些好处也是不可用。例如,在Cloud模式中,不可能使用滑动窗口,因为滑动窗口是基于“现在”概念的,而在在Cloud模式中没有“现在”的概念。 

因为不要求事件顺序,所以引擎不可能确定什么时候事件不再匹配,以及没有事件的自动生命周期管理,即当事件不再匹配时,应用程序必须显式的收回它们,而且应用程序用相同的方法处理正规事实。 

DroolsCloud模式是默认执行模式,但是在任何情况下,象在Drools中的其他配置一样,通过设置一个系统属性,使用配置属性文件或使用API,也可以改变这种行为。相应的属性是: 

KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( EventProcessingOption.CLOUD );

等价的属性是: 

drools.eventProcessingMode = cloud

 

2.5.2    流(Stream)模式 

流模式是当应用程序需要处理事件流时选择的模式。它为常规处理增加一些共同要求,但是却启用了一整套让事件流处理更简单的功能。 

使用流模式的主要要求有: 

l 在每个流中的事件是有时序的,即在一个给定的流内部,第一个发生的事件必须是第一个被插入到引擎中的。

l 引擎会通过使用会话时钟在流之间强制执行同步,所以,虽然应用程序不需要在流之间强制执行时序,但是非时间同步流(non-time-synchronized streams)的使用可能导致一些意想不到的结果。 

上面给出的要求满足了,应用程序可以使用下面的API启用流模式: 

KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );

或,等价的属性: 

drools.eventProcessingMode = stream

在使用流模式时,引擎知道时间流的概念和“现在”的概念,即引擎根据从会话时钟读取的时间戳知道事件是多老了。这个特性允许为应用程序提供以下额外的功能: 

l 滑动窗口支持。

l 自动事件生命周期管理。

l 在使用非模式(Negative Patterns)时,自动规则延迟。 

所有这些功能在下面的章节中解释。 

2.5.2.1     在流模式中的会话时钟角色 

当引擎运行在云模式时,会话时钟仅被用于到达事件的时间戳,到达事件并没有一个先前定义的时间戳属性。但是,在流模式中,会话时钟承担了一个更为重要的角色。 

在流模式中,会话时钟负责保持当前的时间戳,并且根据它,在事件的老化时、在多源同步流时、在时间表远期任务时,等等,引擎进行所有的时间计算。 

要了解如何配置和使用会话时钟的实现,请查看文档有关会话时钟的部分。 

2.5.2.2        在流模式中的非模式(Negative Patterns 

与云模式相比较,云模式的非模式(Negative Patterns)行为不同于流模式中的。在云模式中,引擎假定所有的事实和事件是提前知道的(没有时间流的概念)。因此,非模式(Negative Patterns)是立即被运算的。 

当运行在流模式时,具有时间约束的非模式(Negative Patterns)可能要求引擎在激活一个规则前等待一个时间段。时间段由引擎用一种方法自动计算出来,用户不需要使用任何技巧来达到预期的效果。 

例如: 

例子 2.11 在匹配后,马上激活规则。 

rule "Sound the alarm"
when
    $f : FireDetected( )
    not( SprinklerActivated( ) )
then
    // sound the alarm
end

上面的规则,没有要求延迟规则的时间约束,因此,规则立即激活。另一方面,下面的规则,必须在激活前等待10秒,因为它需要花10秒用于激活洒水装置(sprinklers)。 

例子 2.12  一条规则,由于时间约束,自动延迟激活。 

rule "Sound the alarm"
when
    $f : FireDetected( )
    not( SprinklerActivated( this after[0s,10s] $f ) )
then
    // sound the alarm
end

这种行为允许引擎在同时处理非模式(Negative Patterns)和时间约束时保持一致性。上面的与下面编写的规则是一样的,但不承担用户计算和显式编写适当的限期参数: 

例子 2.13   使用显式期限(duration)参数的相同规则。 

rule "Sound the alarm"
    duration( 10s )
when
    $f : FireDetected( )
    not( SprinklerActivated( this after[0s,10s] $f ) )
then
    // sound the alarm
end

 

2.6     滑动窗口 

滑动窗口是一种方法,用于限定有趣事件范围作为一个属于一个不断移动窗口的整体。最常见的两种滑动窗口实现是基于时间的窗口和基于长度的窗口。 

下面的章节会详细说明它们。 

重要:滑动窗口只当引擎运行在流模式时可用。有关流模式如何工作的详情,请查看事件处理模式章节。 

2.6.1    滑动时间窗口 

滑动时间窗口允许用户编写规则,其将仅匹配在最近的X时间单元内发生的事件。 

例如,如果用户希望只考虑发生在最近2分钟内发生的股票记号(Stock ticks),该模式是这样的: 

StockTick() over window:time( 2m )

Drools使用 "over"关键字关联窗口到模式。 

一个更精细的例子,如果用户希望在过去最近的10分钟从一个传感器中读取的平均温度高于阀值时用声音报警,该规则是这样的: 

例子 2.14 整个时间窗口的累积值 

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

引擎会自动丢弃任何超过10分钟的传感器阅读(SensorReading),并保持计算的平均一致。 

2.6.2    滑动长度窗口 

滑动长度窗口工作的方式与时间窗口相同,但丢弃事件是根据到达的新事件而不是时间流。 

例如,如果用户希望只考虑发生在最近的10IBM股票记号(Stock ticks),它们与多老是无关的,该模式是这样的: 

StockTick( company == "IBM" ) over window:length( 10 )

正如你所见,模式是与上面章节的表示是相似的,然而不是使用了window:time 定义滑动窗口,而是使用了window:length 

使用上面章节中一个相似的例子,如果用户希望在过去最近的100阅读从一个传感器中读取的平均温度高于阀值时用声音报警,该规则是这样的: 

例子 2.15 整个长度窗口的累积值 

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

引擎只保持最近的100个阅读。 

2.7    知识库分割 

警告:这是一个试验功能,在将来会有所变动。 

典型的Rete算法通常使用单线程被执行。如 Dr. Forgy在几次机会中证实一样,该算法本身是可以并行的。Drools实现的ReteOO算法通过规则库分割支持粗粒度并行。

当应用这个选项时,规则库会被分割成几个独立的分割,并且通过分割一个工作者线程池会被用来传播事实。该实现保证,对一个给定的分割至多有一个工作者线程被用来执行任务,但是在一个时间可能有多个分割是“活动”的。 

这一切对用户都是透明的,但除了异步执行的所有工作内存的动作(插入/撤销/修改)。 

重要:该功能启用了并行的LHS计算,但是没有改变规则引发的行为,即,根据冲突解决方案策略,规则将按顺序连续引发。 

2.7.1     什么时候分割是有用的 

知识库分割对特殊情况是一个非常强大的功能,但它不是一个普通情况的解决方案。要清楚是否这个功能对一个给定的情况有用,用户可以按照以下的清单: 

1.  你的硬件包含多个处理器吗?

2.  你的知识库会话处理高容量的事实吗?

3.  你的规则的LHS计算开销高吗?(例如:开销高的“from”表达式)

4.  你的知识库包含成百或更多的规则吗? 

如果上面的答案都是“yes”,那么这个功能将可能全面提高你的规则库的计算性能。 

2.7.2     如何配置分割 

要启用知识库分割,设置下面的选项: 

例子 2.16 启用多线程计算(分割) 

KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( MultithreadEvaluationOption.YES );

等价的属性是: 

drools.multithreadEvaluation = 

这个选项的默认值为"false"(禁用) 

2.7.3     多线程管理 

Drools为用户提供了一个简单的配置选项,用于控制工作者线程池的大小。 

要定义线程池的最大值,用户可以使用下面的配置选项: 

例子 2.17 设置用于规则计算的最大线程数为5 

KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( MaxThreadsOption.get(5) );

等价的属性为: 

drools.maxThreads = <-1|1..n>

这个配置的默认值为3,而一个负数意味着引擎会按规则库中存在的分割尽可能繁殖线程。 

警告:使用一个负数设置这个选项通常是危险的。所以,始终用一个合理的线程正数设置它。 

2.8     事件的内存管理 

重要:事件的自动内存管理,只当引擎运行在流模式时才被执行。有关流模式如何工作的详情,请查看事件处理模式章节。 

引擎运行在流模式的好处之一是:当一个事件的由于时间约束可能不再匹配任何规则时,引擎可以侦测到它。当发生这种情况时,引擎可以无副作用从会话中安全地撤销事件,并释放该事件使用的资源。 

有两种基本方法,用于引擎计算一个给定事件的匹配窗口: 

l 显式地,使用到期策略。

l 隐式地,分析有关事件的时间约束。 

2.8.1    显式到期偏移量 

第一种方法,允许引擎计算一个给定事件类型感兴趣的窗口是通过显式设置它。要做它,只使用声明语句,并为事实类型定义一个到期: 

例子 2.18 显式为StockTick事件定义一个30分钟的到期偏移量。 

declare StockTick
    @expires( 30m )
end

上面的例子显式为StockTick事件定义一个30分钟的到期偏移量。在这个时间之后,假定没有规则仍然需要该事件,引擎会终止并自动从会话中删除该事件。 

2.8.2     推理到期偏移量 

另外一个方法,引擎为一个给定事件计算到期偏移量是隐式,通过在该规则中的时间约束。例如,假设以下规则: 

例子 2.19  使用时间约束的例子规则 

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,只能匹配现有的BuyOrderEvent,因此它的到期偏移量将会是0秒。 

引擎将会对整个规则库做这种分析,并且为每个事件类型找出偏移量。只要一个隐式的到期偏移量与显式的到期偏移量相冲突,那么引擎会使用两个中的大者。

阅读(4787) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~