I have an ArrayList in working memory that I am iterating with a 'from' statement in my when clause. However, the rule is iterating backwards through the array. Is there a way to control this behavior?
List Creation:
List<Map<String,String>> list = new ArrayList<Map<String,String>>();
Map<String,String> m1 = ...
Map<String,String> m2 = ...
list.add(m1);
list.add(m2);
ImportItem item = new ImportItem(list); //model object. Constructor arg returned by getInput()
Sta开发者_如何学CtelessKnowledgeSession session = knowledgeBase.newStatelessKnowledgeSession();
session.insert(item);
session.fireAllRules();
Drools rules:
rule "My Rule"
dialect "java"
when
item : ImportItem(ignore == false) //model object that holds the input
map : Map() from item.getInput() // == the ArrayList from above
then
System.out.println(map);
end
Produces
<output of m2>
<output of m1>
The iteration is not backwards, as you can see if you attach an audit log to your session. The execution of the rules is what follows, by default, a LIFO order (in case you are not using any other conflict resolution strategy).
My suggestion for you is don't try to encapsulate the objects in data structures. If you are reading lines of a file and you need to process these lines in order, just use a class to represent the line and insert the lines directly into the session. To guarantee execution order, you can use the line number as a parameter to salience.
For instance:
rule "Process lines in order"
// salience executes from higher number to lowest number, so using the
// negative value you will executem them from the first to the last
salience (- $lineNumber )
when
$line : Line( $lineNumber : lineNumber )
then
// do something with $line
end
Obviously the same trick can be used with the "from" approach you took, but the engine is much more efficient matching facts in the working memory than it is iterating over collections of objects.
Hope it helps. Edson
You should always try to write the rules so that the order doesn't count. If however, you really really need to have rules firing in certain order, or in this case, get the facts from a list in a certain order. Make sure that whatever changes in the rule engine internals doesn't break up your rules when you update to a newer version of the engine.
You can't trust the "from" even if it did the iteration the other way around.
There is one problem with this solution. If you update the ImportItem and need to iterate through the input again, you need to retract the MyIterator that is related to it.
declare MyIterator
index:int
lastIndex:int
importItem:ImportItem
end
rule "Insert ImportItem iterator"
when
item : ImportItem()
not MyIterator( importItem == item )
then
MyIterator myIterator = new MyIterator();
myIterator.setImportItem( item );
myIterator.setIndex( 0 );
myIterator.setLastIndex( item.getInput().size() );
insert( myIterator );
end
rule "My Rule"
when
myIterator :MyIterator( index < lastIndex )
item : ImportItem( this == myIterator.importItem,
ignore == false )
map : Map() from item.getInput().get( myIterator.getIndex() )
then
System.out.println(map);
myIterator.setIndex( myIterator.getIndex() + 1 );
update( myIterator );
end
精彩评论