Spis treści

Export page to Open Document format

MIW 2009 XTT_DROOLS

Analyze how to design Drools rules with XTT2

Prezentacja

Prezentacja wyników projektowych

Sprawozdanie

1. Przykłady systemów ekspertowych w Drools

Zastosowanie w zarządzaniu produkacją

www.ibm.com/developerworks/java/library/j-drools

The problem to solve



rule "Tests for type1 machine"
 
salience 100
when
	machine : Machine( type == "Type1" )
then	
	Test test1 = testDAO.findByKey(Test.TEST1);
	Test test2 = testDAO.findByKey(Test.TEST2);
	Test test5 = testDAO.findByKey(Test.TEST5);
	machine.getTests().add(test1);
	machine.getTests().add(test2);
	machine.getTests().add(test5);
	insert( test1 );
	insert( test2 );
	insert( test5 );
end
 
rule "Tests for type2, DNS server machine"
salience 100
when
	machine : Machine( type == "Type2", functions contains "DNS Server")
then	
	Test test5 = testDAO.findByKey(Test.TEST5);
	Test test4 = testDAO.findByKey(Test.TEST4);
	machine.getTests().add(test5);
	machine.getTests().add(test4);
	insert( test4 );
	insert( test5 );		
end
 
rule "Tests for type2, DDNS server machine"
salience 100
when
	machine : Machine( type == "Type2", functions contains "DDNS Server")
then	
	Test test2 = testDAO.findByKey(Test.TEST2);
	Test test3 = testDAO.findByKey(Test.TEST3);
	machine.getTests().add(test2);
	machine.getTests().add(test3);
	insert( test2 );
	insert( test3 );		
end
 
rule "Tests for type2, Gateway machine"
salience 100
when
	machine : Machine( type == "Type2", functions contains "Gateway")
then		
	Test test3 = testDAO.findByKey(Test.TEST3);
	Test test4 = testDAO.findByKey(Test.TEST4);
	machine.getTests().add(test3);
	machine.getTests().add(test4);
	insert( test3 );
	insert( test4 );		
end
 
rule "Tests for type2, Router machine"
salience 100
when
	machine : Machine( type == "Type2", functions contains "Router")
then	
	Test test3 = testDAO.findByKey(Test.TEST3);
	Test test1 = testDAO.findByKey(Test.TEST1);
	machine.getTests().add(test3);
	machine.getTests().add(test1);
	insert( test1 );
	insert( test3 );					
end
 
rule "Due date for Test 5"
salience 50
when
	machine : Machine()
	Test( id == Test.TEST5 )
then	
	setTestsDueTime(machine, 14);				
end
 
rule "Due date for Test 4"
salience 40
when
	machine : Machine()
	Test( id == Test.TEST4 )
then	
	setTestsDueTime(machine, 12);				
end
 
rule "Due date for Test 3"
salience 30
when
	machine : Machine()
	Test( id == Test.TEST3 )
then	
	setTestsDueTime(machine, 10);				
end
 
rule "Due date for Test 2"
salience 20
when
	machine : Machine()
	Test( id == Test.TEST2 )
then	
	setTestsDueTime(machine, 7);				
end
 
Rule "Due date for Test 1"
salience 10
when
	machine : Machine()
	Test( id == Test.TEST1 )
then	
	setTestsDueTime(machine, 3);				
end

Przykład systemu dla firmy

www.onjava.com/pub/a/onjava/2007/01/17/building-enterprise-services-with-drools-rule-engine.html?page=4

Reguły opisują podejmowanie decyzji przyznania pożyczki na podstawie określonych kryteriów.


    rule "Age verification"
        when
            Borrower(age < 18)
            $loanApp : LoanApplication()
        then
            $loanApp.addFeedbackMessage(FeedbackMessages.MIN_AGE);
    end
 
    rule "Credit score"
 
        when
            Borrower(creditScore <= 600)
            $loanApp : LoanApplication()
        then
            $loanApp.addFeedbackMessage(FeedbackMessages.MIN_CREDIT_SCORE);
    end
 
    rule "Loan Amount limits"
        when
            $loanApp : (LoanApplication(loanAmount <= 100000.0) or
            LoanApplication(loanAmount >= 400000.0))
        then
            $loanApp.addFeedbackMessage(FeedbackMessages.LOAN_AMOUNT_LIMITS);
    end
 
    rule "Maximum Loan-to-value ratio"
        when
            $loanApp : LoanApplication(loanToValueRatio > 80.0)
        then
            $loanApp.addFeedbackMessage(FeedbackMessages.LTV);
    end
 
    rule "Income multiples"
        salience -3
        when
            Borrower( $grossIncome : grossIncome )
            Property( value > (new Double($grossIncome.doubleValue()*3)))
            $loanApp : LoanApplication()
        then
            $loanApp.setAffordabilityFlag(Flag.NOT_AFFORDABLE);
    end
 
    rule "Affordability Model"
        salience -4
        when
            Borrower( $affordableLoanAmount : affordableLoanAmount )
            Property( value > (new Double($affordableLoanAmount.doubleValue())))
            $loanApp : LoanApplication()
        then
            $loanApp.setAffordabilityFlag(Flag.NOT_AFFORDABLE);
    end
 
    rule "Property type"
        when
            Property(purpose != Flag.OWNER_OCCUPIED)
            $loanApp : LoanApplication()
        then
            $loanApp.addFeedbackMessage(FeedbackMessages.PROP_TYPE);
    end
 
    rule "Property age"
        when
            Property(yearBuilt < 1965)
            $loanApp : LoanApplication()
        then
            $loanApp.addFeedbackMessage(FeedbackMessages.PROP_YEAR_BUILT);
    end
    rule "Underwriting decision"
 
        when
            $loanApp : (LoanApplication(affordabilityFlag == Flag.NOT_AFFORDABLE) or
            LoanApplication( feedbackMsgSize > 0))
        then
            $loanApp.setStatus(Flag.FAILED);
    end

Przykład reguł w XMLu

www.onjava.com/pub/a/onjava/2005/08/03/drools.html?page=5

Przykład zapisania reguł Drools w XMLu


<?xml version="1.0"?>
<rule-set>
  <!-- Ensure stock price is not too high-->      
  <rule name="Stock Price Low Enough">
    <!-- Params to pass to business rule -->
    <parameter identifier="stockOffer">
      <class>StockOffer</class>
    </parameter>
    <!-- Conditions or 'Left Hand Side' 
        (LHS) that must be met for 
         business rule to fire -->
    <!-- note markup -->
    <java:condition>
      stockOffer.getRecommendPurchase() == null
    </java:condition>
    <java:condition>
      stockOffer.getStockPrice() < 100
    </java:condition>
    <!-- What happens when the business 
                      rule is activated -->
    <java:consequence>
        stockOffer.setRecommendPurchase(
                              StockOffer.YES);  
          printStock(stockOffer);
    </java:consequence>
  </rule>
</rule-set>

Bilety

http://downloads.jboss.com/drools/docs/4.0.7.19894.GA/html/ch10.html#d0e6737

Prosty systemie przydzielania biletów klientom, wykorzystuje zależności czasowe.


rule "New Ticket"
	salience 10
	when
		customer : Customer( )
		ticket : Ticket( customer == customer, status == "New" )	
	then
		System.out.println( "New : " + ticket );		
end
 
rule "Silver Priority"
	duration 3000
	when
		customer : Customer( subscription == "Silver" )	
		ticket : Ticket( customer == customer, status == "New" )	
	then
		modify( ticket ) {setStatus( "Escalate" )} 		
end
 
rule "Gold Priority"
	duration 1000
	when
		customer : Customer( subscription == "Gold" )	
		ticket : Ticket( customer == customer, status == "New" )	
	then
		modify( ticket ) {setStatus( "Escalate" )}	
end
 
rule "Platinum Priority"
	when
		customer : Customer( subscription == "Platinum" )	
		ticket : Ticket( customer == customer, status == "New" )	
	then
		ticket.setStatus( "Escalate" );
		modify ( ticket ) {setStatus( "Escalate" )}
end
 
rule "Escalate"
	when
		customer : Customer( )	
		ticket : Ticket( customer == customer, status == "Escalate" )	
	then
		sendEscalationEmail( customer, ticket );
end
 
rule "Done"
	when
		customer : Customer( )	
		ticket : Ticket( customer == customer, status == "Done" )	
	then
		System.out.println( "Done : " + ticket );		
end

2. Testowanie systemów Drools

Wstęp

W celu sprawdzenia poprawności przedstawionych w poprzednim rozdziale systemów Drools przeprowadzono testy ich działania. Wykorzystano do tego środowisko programistyczne Eclipse z pluginem do obługi Drools - opis jego instalacji został zaprezentowany na stronie pokrewnego projektu - Drools_X

System 1

Testowano przykładowy system dla firmy.
Systemu jest napisany we wcześniejszej wersji Drools, zatem nie funkcjonuje prawidłowo na używanej do testów wersji Drools - 4.0.7.19894.
Po ściągnięciu źródeł systemu spod adresu http://www.onjava.com/onjava/2007/01/17/examples/src_code.zip i stworzeniu na tej podstawie nowego projektu Drools w Eclipse'ie wystąpiły następują błędy:

Errors (6 items)
Severity and Description	Path	Resource	Location	Creation	Time	Id \\
Cannot invoke doubleValue() on the primitive type double system3/src/main/rules/rules Underwriting.drl line 38 1243455362182 3459 \\
Cannot invoke doubleValue() on the primitive type double system3/src/main/rules/rules Underwriting.drl line 49	1243455362182	13460 \\
The method assertObject(Borrower) is undefined for the type WorkingMemory system3/src/main/java/com/birali/engine UnderwritingService.java line 29 1243455345587 3457 \\
The method assertObject(LoanApplication) is undefined for the type WorkingMemory system3/src/main/java/com/birali/engine UnderwritingService.java line 28 1243455345587 13456 \\
The method assertObject(Property) is undefined for the type WorkingMemory system3/src/main/java/com/birali/engine UnderwritingService.java line 30 1243455345587 13458 \\
The method newWorkingMemory() is undefined for the type RuleBase system3/src/main/java/com/birali/engine UnderwritingService.java line 27 1243455345586 13455'' 

Kiedy wprowadzono zmiany dostosowujących do Drools 4.0, udało się wyeliminować powyższe błędy. Kolejny błędu wystąpiły po uruchomieniu narzędzia do testowania JUnit, tym razem w pliku reguł:

org.drools.rule.InvalidRulePackage: Rule Compilation error : [Rule name=Income multiples, agendaGroup=MAIN, salience=-3, no-loop=false]
	com/birali/underwriting/Rule_Income_multiples_0.java (9:434) : Cannot invoke doubleValue() on the primitive type double
Rule Compilation error : [Rule name=Affordability Model, agendaGroup=MAIN, salience=-4, no-loop=false]
	com/birali/underwriting/Rule_Affordability_Model_0.java (9:446) : Cannot invoke doubleValue() on the primitive type double

Gdy usunięto wywołania funkcji „doubleValue”, test przeszedł poprawnie z wynikiem na konsoli:

==>Income multiples fired. Flag=NOT_AFFORDABLE

Testing all feedback messages
=============================
Property should be built after 1965
Type of property should be Owner Occupied
Credit score should be geater than 600
Borrower minimum age should be 18
Loan to value ratio should not be greater than 80
Loan Amount should be between $100,000 and $400,000

Feedback message size=6
Affordability Flag=NOT_AFFORDABLE
Underwriting Decision=FAILED

Zastosowane modyfikacje w kodzie źródłowym:

com/birali/engine/UnderwritingService.java
27,30c27,30
< 	    WorkingMemory wm = ruleBase.newWorkingMemory();
< 	    wm.assertObject(la);
< 	    wm.assertObject(la.getBorrower());
< 	    wm.assertObject(la.getProperty());
---
> 	    WorkingMemory wm = ruleBase.newStatefulSession();
> 	    wm.insert(la);
> 	    wm.insert(la.getBorrower());
> 	    wm.insert(la.getProperty());
Underwriting.drl
42c42
< 	   	Property( value > (new Double($grossIncome.doubleValue()*3)))
---
> 	   	Property( value > (new Double($grossIncome*3)))
53c53
< 	   	Property( value > (new Double($affordableLoanAmount.doubleValue())))		
---
> 	   	Property( value > (new Double($affordableLoanAmount)))	

System 2

Testowano system do zarządzania w produkcji.
Po ściągnięciu kodu źródłowego projektu Drools, dostępnego na stronie http://www.ibm.com/developerworks/java/library/j-drools, można bardzo łatwo stworzyć projekt w Eclipse'ie, ponieważ archiwum zawiera plik projektu gotowy do zaimportowania.
Następnie uruchomiono przygotowany test JUnit (TestsRulesEngineTest.java), który sprawdza poprawność działania systemu. Przeprowadzony test nie wykazał żadnych błędów w działaniu.

System 3

Testowano system biletowy.
Po ściągnięciu plików źródłowych systemu ze strony http://downloads.jboss.com/drools/docs/4.0.7.19894.GA/html/ch10.html#d0e6737 i stworzeniu nowego projektu Drools umieszczono pliki Javy i reguł w odpowiednich katalogach. Problemy pojawiły się z pierwszym uruchomieniem - program nie mógł odczytać pliku reguł:

Exception in thread "main" java.lang.NullPointerException
	at java.io.Reader.<init>(Reader.java:61)
	at java.io.InputStreamReader.<init>(InputStreamReader.java:55)
	at com.sample.TroubleTicketExample.main(TroubleTicketExample.java:20)

Dodanie jednego znaku '/' przed nazwą pliku rozwiązało ten problem:

TroubleTicketExample.java
20c20
<         builder.addPackageFromDrl( new InputStreamReader( TroubleTicketExample.class.getResourceAsStream( "TroubleTicket.drl" ) ) );
---
>         builder.addPackageFromDrl( new InputStreamReader( TroubleTicketExample.class.getResourceAsStream( "/TroubleTicket.drl" ) ) );

System zaczął działań, ale na końcu symulacji dał o sobie znać kolejny błąd, również dotyczący ścieżki do pliku, tym razem z plikiem z logami:

Exception in thread "main" java.lang.RuntimeException: Could not create the log file.  Please make sure that directory that the log file should be placed in does exist.
	at org.drools.audit.WorkingMemoryFileLogger.writeToDisk(WorkingMemoryFileLogger.java:96)
	at com.sample.TroubleTicketExample.main(TroubleTicketExample.java:72)

Podanie ścieżki bezwzględnej do pliku naprawiło błąd:

TroubleTicketExample.java
28c28
<         logger.setFileName( "log/trouble_ticket" );
---
>         logger.setFileName( "/tmp/log_trouble_ticket" );

Ostatecznie na konsoli otrzymano wynik działania systemu:

New : [Ticket [Customer D : Silver] : New]
New : [Ticket [Customer C : Silver] : New]
New : [Ticket [Customer B : Platinum] : New]
New : [Ticket [Customer A : Gold] : New]
Email : [Ticket [Customer B : Platinum] : Escalate]
[[ Sleeping 5 seconds ]]
Email : [Ticket [Customer A : Gold] : Escalate]
Done : [Ticket [Customer C : Silver] : Done]
Email : [Ticket [Customer D : Silver] : Escalate]
[[ awake ]]

Przebieg symulacji zapisany w logu , który można wygodnie oglądnąć w zakładce „Audit View” Eclipse'a.

3. Modelowanie diagramów ARD

Wstęp

Diagram ARD

Diagram TPH

XML

ard.xml

Spotkania

Notatki ze spotkań projektowych

Materiały

Dokumentacja Drools