簡體   English   中英

Drools:獲取 3 個最近的事件

[英]Drools: get the 3 most recent Events

我正在從事一個小型 Drools 項目,因為我想了解有關使用規則引擎的更多信息。 我有一個名為Event的類,它具有以下字段:

  • String tag; 可以是任何字符串的標簽。
  • long millis; 一個時間戳。 (實際上,這是從同樣在Event的 JodaTime LocalDate字段轉換而來的。)
  • int value; 我想要推理的值。

我將數百個Event實例插入到我的知識庫中,現在我想獲取標記為"OK"的 3 個最新事件。 我想出了以下代碼,該代碼有效:

rule "Three most recent events tagged with 'OK'"
when
    $e1 : Event( tag == "OK",
                 $millis1 : millis )
    $e2 : Event( tag == "OK",
                 millis < $millis1, $millis2 : millis )
    $e3 : Event( tag == "OK",
                 millis < $millis2, $millis3 : millis )

    not Event( tag == "OK",
               millis > $millis1 )
    not Event( tag == "OK",
               millis > $millis2 && millis < $millis1 )
    not Event( tag == "OK",
               millis > $millis3 && millis < $millis2 )
then
  # Do something with $e1.value, $e2.value and $e3.value
end

但我覺得應該有更好的方法來做到這一點。 這是非常冗長的並且不容易重用:例如,如果我想獲取value > 10的五個最近事件怎么辦? 我最終會復制粘貼很多代碼,我不想這樣做:)。 此外,代碼對我來說看起來不是很“漂亮”。 我真的不喜歡重復的not Event...約束,而且我也不喜歡一遍又一遍地重復相同的標簽條件。 (這個例子是我真實應用程序的一個大大簡化的版本,其中的條件實際上要復雜得多。)

如何改進此代碼?

假設您正在使用 STREAM 事件處理模式並且您的事件在流中排序:

rule "3 most recent events"
when
    accumulate( $e : Event( tag == "OK" ) over window:length(3),
                $events : collectList( $e ) )
then
    // $events is a list that contains your 3 most recent 
    // events by insertion order
end

======編輯====

根據您的評論,以下是如何在 Drools 5.4+ 中實現您想要的:

declare window LastEvents
    Event() over window:length(3)
end

rule "OK events among the last 3 events"
when
    accumulate( $e : Event( tag == "OK" ) from window LastEvents,
                $events : collectList( $e ) )
then
    // $events is a list that contains the OK events among the last 3 
    // events by insertion order
end

只需仔細檢查語法,因為我正在做這件事,但它應該接近於此。

我能夠像這樣簡化“非邏輯”

rule "Three most recent events tagged with 'OK'"
when
    $e1 : Event( tag == "OK")
    $e2 : Event( tag == "OK", millis < $e1.millis )
    $e3 : Event( tag == "OK", millis < $e2.millis )
    not Event( this != $e2, tag == "OK", $e3.millis < millis, millis < $e1.millis )
then
    System.out.printf("%s - %s - %s%n", $e1, $e2, $e3);
end

沒有提到清潔活動。 通常這是可取的,因此您可以通過刪除最后一個事件來實現相同的邏輯:

rule "Three most recent events tagged with 'OK'"
when
    $e1 : Event( tag == "OK")
    $e2 : Event( tag == "OK", millis < $e1.millis )
    $e3 : Event( tag == "OK", millis < $e2.millis )
then
    System.out.printf("%s - %s - %s%n", $e1, $e2, $e3);
    retract ($e3)
end

假設每一秒你都會插入一個事件一個'OK'另一個空'',這是測試:

@DroolsSession("classpath:/test3.drl")
public class PlaygroundTest {
    
    @Rule
    public DroolsAssert drools = new DroolsAssert();
    
    @Test
    public void testIt() {
        for (int i = 0; i < 10; i++) {
            drools.advanceTime(1, SECONDS);
            drools.insertAndFire(new Event(i % 2 == 0 ? "OK" : "", i));
        }
    }
}

所有三個變體都會產生相同的觸發邏輯:

00:00:01 --> inserted: Event[tag=OK,millis=0]
00:00:01 --> fireAllRules
00:00:02 --> inserted: Event[tag=,millis=1]
00:00:02 --> fireAllRules
00:00:03 --> inserted: Event[tag=OK,millis=2]
00:00:03 --> fireAllRules
00:00:04 --> inserted: Event[tag=,millis=3]
00:00:04 --> fireAllRules
00:00:05 --> inserted: Event[tag=OK,millis=4]
00:00:05 --> fireAllRules
00:00:05 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [Event, Event, Event]
OK4 - OK2 - OK0
00:00:06 --> inserted: Event[tag=,millis=5]
00:00:06 --> fireAllRules
00:00:07 --> inserted: Event[tag=OK,millis=6]
00:00:07 --> fireAllRules
00:00:07 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [Event, Event, Event]
OK6 - OK4 - OK2
00:00:08 --> inserted: Event[tag=,millis=7]
00:00:08 --> fireAllRules
00:00:09 --> inserted: Event[tag=OK,millis=8]
00:00:09 --> fireAllRules
00:00:09 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [Event, Event, Event]
OK8 - OK6 - OK4
00:00:10 --> inserted: Event[tag=,millis=9]
00:00:10 --> fireAllRules

帶有window:length(3)變體也將處理最后 3 個 OK 事件。 但是一開始就不一樣了:它也會被第 1 個和第 2 個 OK 事件觸發。 如果會話不包含任何事件,它也會在開始時以空列表觸發一次。 根據文檔,滑動窗口立即開始匹配,定義滑動窗口並不意味着規則必須等待滑動窗口“滿”才能匹配。 例如,計算 window:length(10) 上事件屬性平均值的規則將立即開始計算平均值,對於無事件,它將從 0(零)開始,並在事件到達時更新平均值逐個。

00:00:01 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [InitialFactImpl, UnmodifiableRandomAccessList]
[]
00:00:01 --> inserted: Event[tag=OK,millis=0]
00:00:01 --> fireAllRules
00:00:01 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [InitialFactImpl, UnmodifiableRandomAccessList]
[OK0]
00:00:02 --> inserted: Event[tag=,millis=1]
00:00:02 --> fireAllRules
00:00:03 --> inserted: Event[tag=OK,millis=2]
00:00:03 --> fireAllRules
00:00:03 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [InitialFactImpl, UnmodifiableRandomAccessList]
[OK0, OK2]
00:00:04 --> inserted: Event[tag=,millis=3]
00:00:04 --> fireAllRules
00:00:05 --> inserted: Event[tag=OK,millis=4]
00:00:05 --> fireAllRules
00:00:05 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [InitialFactImpl, UnmodifiableRandomAccessList]
[OK0, OK2, OK4]
00:00:06 --> inserted: Event[tag=,millis=5]
00:00:06 --> fireAllRules
00:00:07 --> inserted: Event[tag=OK,millis=6]
00:00:07 --> fireAllRules
00:00:07 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [InitialFactImpl, UnmodifiableRandomAccessList]
[OK2, OK4, OK6]
00:00:08 --> inserted: Event[tag=,millis=7]
00:00:08 --> fireAllRules
00:00:09 --> inserted: Event[tag=OK,millis=8]
00:00:09 --> fireAllRules
00:00:09 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [InitialFactImpl, UnmodifiableRandomAccessList]
[OK4, OK6, OK8]
00:00:10 --> inserted: Event[tag=,millis=9]
00:00:10 --> fireAllRules

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM