开发者

Why does the 'from' keyword iterate backwards?

开发者 https://www.devze.com 2023-02-06 01:21 出处:网络
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 behavi

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
0

精彩评论

暂无评论...
验证码 换一张
取 消