Wykład 4

Transkrypt

Wykład 4
Informatyzacja przedsiębiorstw
WYKŁAD
dr inż. Piotr Zabawa
IBM/Rational Certified Consultant
[email protected]
wersja 0.1.0
07.10.2010
Wykład 4
Mechanizm zdarzeń biznesowych
w środowisku Jboss Drools
Wstęp
Aby zrozumieć wyraźnie znaczenie praktyczne pojęcia
zdarzeń biznesowych posłużymy się na wstępie
uproszczonymi (co nie znaczy – zupełnie prostymi)
przykładami HelloWorld od 05 do 07.
Przykłady te zostały wymyślone i opracowane przez autora
wykładu.
Wstęp
Wspomniane przykłady HelloWorld nawiązują do powitań
pokazując kolejno jak:
• Wyzwolić aktywność (powitanie) zdarzeniem biznesowym
• Wyznaczyć autorytet grupy ludzi mierzony średnią
długością sentencji powitalnych skierowanych do
poszczególnych członków tej grupy wyliczoną dla
wszystkich przedstawicieli grupy łącznie
• Wyznaczyć autorytet poszczególnych członków grupy
mierzony średnią długością sentencji powitalnych
wyliczoną dla każdego członka grupy osobno
Zdarzenia w Drools
Omówimy następujące zagadnienia ilustrując je przykładami
HelloWorld:
• Jak zdefiniować zdarzenie
• Jak wysłać zdarzenie
• Jak kanalizować rozpływ zdarzeń – organizacja pamięci
• Jak korzystać ze zdarzeń w regułach
• Jak przeprowadzać analizę statystyczną zdarzeń w
oderwaniu od czasu
• Jak współdzielić dane statystyczne pomiędzy regułami
Zdarzenia w Drools
Fakty stanowią dane statyczne, jednak często w modelowaniu
procesów biznesowych istnieje potrzeba zdefiniowania
relacji pomiędzy tymi elementami w czasie. Jest to
nazywane Complex Event Processing (CEP) lub Event
Sream Processing (ESP). Wsparcie dla tego mechanizmu
w Drools oferuje Drools Fusion.
Na razie jednak skupimy się na samych zdarzeniach w
oderwaniu od osi czasu, tzn. kolejność zdarzeń, ani ich
specyficzne sekwencje nie będą na razie miały dla nas
znaczenia.
Zdarzenia w Drools
Podejście związane z przetwarzaniem zdarzeń nawiązuje do
pojęcia Event Driven Architecture. Warto się przy okazji z
nim zapoznać (dla zainteresowanych osób - poza
wykładem).
Zdarzenia w Drools
Zdarzenie składa się z:
• Nagłówka zawierającego meta-dane (nazwa, czas
zgłoszenia, czas trwania,…)
• Ciała zawierającego informacje o zdarzeniu (UUID
transakcji bakowej, kwota przelewu, konto źródłowe,
docelowe,…)
Pojęcie CEP odnosi się do sekwencji zdarzeń a nie do
zdarzeń pojedynczych.
DroolsHelloWorld_05
Przykład ten pokazuje jak utworzyć, wysłać i przechwycić
event.
Zdarzenia w Drools
Czym jest event?
Klasa Java POJO ewentualnie z finalnymi polami
prywatnymi (zdarzenie nie powinno się zmieniać!)
ustawianymi tylko w konstruktorze, np.
public class NotificationEvent implements Serializable {
private static final long serialVersionUID = 1L;
public NotificationEvent(){
}
@Override
public String toString(){
return null;
}
}
Zdarzenia w Drools
Event jest szczególnym rodzajem faktu, który należy
umieścić w sesji z silnikiem reguł. Reguła może być np.
taka:
// modyfikacja istniejącego faktu
declare NotificationEvent
@role( event )
end
rule "Event notification"
when
NotificationEvent()
from entry-point NotificationStream;
then
System.out.println( "Hello World!" );
end
Zdarzenia w Drools
Co to jest entry-point?
Pamięć sesji może/powinna zostać podzielona na strumienie
zdarzeń – daje to możliwość separacji i lepszego
wykorzystania współbieżności mechanizmu obsługi
zdarzeń przez silnik reguł biznesowych.
entry-point wiąże zdarzenie ze strumieniem zdarzeń, do
którego chcemy żeby było przypisane
Zdarzenia w Drools
Jak umieścić zdarzenie w sesji?
Przed utworzeniem bazy wiedzy:
KnowledgeBaseConfiguration config =
KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption(EventProcessingOption.STREAM);
Po utworzeniu sesji:
WorkingMemoryEntryPoint entry =
ksession.getWorkingMemoryEntryPoint("NotificationStream");
entry.insert(new NotificationEvent());
ksession.fireAllRules();
DroolsHelloWorld_06
Zdarzenia w Drools
Obliczanie statystyk może dotyczyć np. policzenia prestiżu
grupy ludzi mierzonego średnią wartością długości
sekwencji powitalnych przypisanych każdemu z tych ludzi
– czyli średnia dla grupy.
Zdarzenia w Drools
Do wyliczenia tej informacji statystycznej użyjemy query:
query "averagePrestigeQuery"
Number( $averagePrestige : doubleValue ) from accumulate(
$receiver : GreetingsReceiver(),
average($receiver.getLength()))
end
Zdarzenia w Drools
W ramach collect lub accumulate można użyć też:
• count
• min
• max
• sum
Zdarzenia w Drools
GreetingsReceiver tomek = new GreetingsReceiver("Tomek");
ksession.insert(tomek);
tomek.receiveGreeting("Hi");
GreetingsReceiver janek = new GreetingsReceiver("Janek");
ksession.insert(janek);
janek.receiveGreeting("Hello");
GreetingsReceiver staszek = new GreetingsReceiver("Staszek");
ksession.insert(staszek);
staszek.receiveGreeting("Good morning");
ksession.fireAllRules();
System.out.println(getAveragePrestige(ksession));
Zdarzenia w Drools
private static BigDecimal getAveragePrestige(StatefulKnowledgeSession ksession){
QueryResults queryResults = ksession.getQueryResults("averagePrestigeQuery");
return BigDecimal.valueOf((Double)
queryResults.iterator().next().get("$averagePrestige"));
}
Zdarzenia w Drools
Chcemy teraz sięgnąć do HelloWorld07. Postaramy się w nim
wyliczyć średnią długość sentencji powitalnych
kierowanych do każdego z uczestników grupy ludzi przez
inne osoby z ich otoczenia.
Przy okazji zobaczymy jak definiować w Drools własne typy
danych i jak można obiekty tych typów przekazywać
pomiędzy regułami. Mamy zatem współdzielone dane:
declare GreetingsInfo
name: String
averageLength: Double
end
Typy zostały tak dobrane,
aby uniknąć konwersji
Zdarzenia w Drools
Zastosujemy dwie reguły, aby pokazać komunikację między
nimi:
• Pierwsza reguła wyznacza wartości średnie per człowiek i
zapisuje je we współdzielonych obiektach natywnych
Drools
• Druga reguła korzysta z wyników statystyk zapisanych w
obiektach natywnych Drools i wypisuje wynik do konsoli
(wykorzystuje ona zresztą te dane w swoich warunkach)
Zdarzenia w Drools
// reguła wylicza średnią długość powitania
rule "Average greetings length"
dialect "mvel"
no-loop true
when
$receiver : GreetingsReceiver()
$averageLength : Double() from accumulate(
GreetingReceivedEvent(receiver == $receiver.name)
from entry-point GreetingsStream,
average($receiver.getLength()) )
$greetingsInfo : GreetingsInfo(name == $receiver.name)
then
modify($greetingsInfo){
setAverageLength($averageLength)
};
end
Zdarzenia w Drools
// reguła korzysta z wyliczonych wartości
// tutaj wypisuje imię kaŜdego członka grupy
// wraz z wyliczoną dla niego
// średnią długością powitania
rule "Report greetings"
dialect "mvel"
when
$info : GreetingsInfo()
then
System.out.println( "name = "+$info.name );
System.out.println( "average = "
+$info.getAverageLength() );
end
Zdarzenia w Drools
public class GreetingsReceiver {
private String name;
private String greetings = "";
public GreetingsReceiver(String name){
this.name = name;
}
public String getName(){
return name;
}
public void receiveGreeting(String greeting){
greetings = greeting;
}
@Override
public boolean equals(final Object other){
if (this==other) return true;
if (!(other instanceof GreetingsReceiver)) return false;
GreetingsReceiver castOther = (GreetingsReceiver) other;
return name.equals(castOther.name);
}
public long getLength(){
long counter = 0;
for (int i=0; i<greetings.length(); i++)
if (greetings.charAt(i) != ' ') counter++;
return counter;
}
}
Zdarzenia w Drools
public class GreetingReceivedEvent implements Serializable {
private static final long serialVersionUID = 1L;
private final String receiver;
public GreetingReceivedEvent(GreetingsReceiver receiver, String greeting){
this.receiver = receiver.getName();
receiver.receiveGreeting(greeting);
}
public String getReceiver(){
return receiver;
}
@Override
public String toString(){
return null;
}
}
Zdarzenia w Drools
FactType greetingsInfoFactType = kbase.getFactType("com.sample", "GreetingsInfo");
// wstawienie do sesji odbiorców powitań
// i obiektu natywnego Drools do przehowywania statystyk dla kaŜdego z odbiorców
GreetingsReceiver tomek = new GreetingsReceiver("Tomek");// 2
ksession.insert(tomek);
Object greetingsInfoTomek = greetingsInfoFactType.newInstance();
greetingsInfoFactType.set(greetingsInfoTomek, "name", tomek.getName());
greetingsInfoFactType.set(greetingsInfoTomek, "averageLength", 0.0);
ksession.insert(greetingsInfoTomek);
GreetingsReceiver janek = new GreetingsReceiver("Janek");// 8
ksession.insert(janek);
Object greetingsInfoJanek = greetingsInfoFactType.newInstance();
greetingsInfoFactType.set(greetingsInfoJanek, "name", janek.getName());
greetingsInfoFactType.set(greetingsInfoJanek, "averageLength", 0.0);
ksession.insert(greetingsInfoJanek);
GreetingsReceiver staszek = new GreetingsReceiver("Staszek");// 6
ksession.insert(staszek);
Object greetingsInfoStaszek = greetingsInfoFactType.newInstance();
greetingsInfoFactType.set(greetingsInfoStaszek, "name", staszek.getName());
greetingsInfoFactType.set(greetingsInfoStaszek, "averageLength", 0.0);
ksession.insert(greetingsInfoStaszek);
Zdarzenia w Drools
// wstawienie do sesji zdarzeń róŜnych powitań
// skierowanych do róŜnych osób
// średnia długość powitania = (2+5+11)/3 = 6;
String shortGreeting = "Hi";
// 2
String mediumGreeting = "Hello";
// 5
String longGreeting = "Good morning"; // 11
Zdarzenia w Drools
WorkingMemoryEntryPoint entry =
ksession.getWorkingMemoryEntryPoint("GreetingsStream");
// wysyłanie eventów
entry.insert(new GreetingReceivedEvent(tomek, shortGreeting));
entry.insert(new GreetingReceivedEvent(janek, mediumGreeting));
entry.insert(new GreetingReceivedEvent(janek, longGreeting));
entry.insert(new GreetingReceivedEvent(staszek, shortGreeting));
entry.insert(new GreetingReceivedEvent(staszek, mediumGreeting));
entry.insert(new GreetingReceivedEvent(staszek, longGreeting));
ksession.fireAllRules();
Zdarzenia w Drools
Wynik działania programu w konsoli:
name = Staszek
average = 6.0
name = Janek
average = 8.0
name = Tomek
average = 2.0
Zdarzenia w Drools
Drools Fusion oferuje możliwość pracy ze zdarzeniami w
powiązaniu z upływem czasu.
Robi się to przez określanie ramek czasowych. W
zastosowaniu do systemów bankowych pozwala to na
wykrycie podejrzanych transakcji (mogących świadczyć
np. o tym, że kto inny posługuje się kartą płatniczą lub
poznał login i hasło do serwisu internetowego klienta
banku).
Zdarzenia w Drools
rule twoLargeWithdrawals
dialect „mvel”
when
$account : Account()
Number($averageAmount : doubleValue) from accumulate(
TransactionCompletedEvent(fromAccountNumber ==
$account.number, $ammount : ammount)
over window:time(30d) from entry-point
TransactionStream, average($ammount))
$t1 : TransactionCreatedEvent(fromAccountNumber ==
$account.number, amount > ($averageAmmount * 3.00)) over
window:time(90s) from entry-point TransactionStream
$t2 : TransactionCreatedEvent(this!=$t1,
fromAccountNumber ==
$account.number, amount > ($averageAmmount * 3.00)) over
window:time(90s) from entry-point TransactionStream
then…
Zdarzenia w Drools
Są dwa rodzaje okien:
• sliding time window (tylko te zdarzenia, które zaczęły się
w określonym przedziale czasu)
• sliding length window (tylko ostatnich N zdarzeń)
Pozwalają one w warunkach reguł dopasowywać tylko te
zdarzenia, które rozpoczęły się w oknie.
Dodatkowo Drools w przypadku zastosowania time window
w trybie STREAM usuwa te zdarzenia, które znajdują się
poza oknem.
Zdarzenia w Drools
Drools Fusion oferuje też możliwość sprawdzania kolejności
zdarzeń:
this
after[0, 3m] $t1
Zdarzenie $t1 miało miejsce nie później niż zaszło zdarzenie,
w którym sprawdzamy ten warunek.
Jest to tzw. temporal operator
Zdarzenia w Drools
Oprócz okien mamy w Drools Fusion do dyspozycji timery:
• Real-time clock (do wykorzystania w aplikacjach)
• Pseudo clock (do testowania ze względu na pełną kontrolę
nad tym timerem)
Zdarzenia w Drools
Jeśli chodzi o testy, to oprócz wsparcia przez specjalny timer
można wykorzystać też:
• AgendaEventListener
• AgendaFilter
private void assertFired(String ruleName){
session.fireAllRules(new RuleNameEqualsAgendaFilter(ruleName));
assertTrue(trackingAgendaEventLitener.isRuleFired(ruleName))
}
gdzie
Zdarzenia w Drools
public class TrackingAgendaListener extends DefaultAgendaListener{
List<String> rulesFiredList = new ArrayList<String>();
@Override
public void afterActivationFired(AfterActivationFiredEvent event){
rulesFiredList.add(event.getActivation().getRule().getName());
}
public boolean isRuleFired(String ruleName){
for(String firedRuleName : rulesFiredList)
if(firedRuleName.equals(ruleName)) return true;
return false;
}
public void reset(){
rulesFiredList.clear();
}
}
Zdarzenia w Drools
Kolejnym przykładem, tym razem związanym z upływem
czasu towarzyszącym zdarzeniom może być decyzja o
wyeliminowaniu z grupy człowieka, którego zbyt często
inni pozdrawiają – pewnie robią to dla żartu, co raczej nie
świadczy o jego wysokich notowaniach.
Pokusimy się więc o napisanie programu, który ustali regułę
eliminacji, a następnie przetestujemy go.

Podobne dokumenty