问题
One of the no-nos in drools includes manually iterating over collections in the consequence (then clause). I need to write a drool which is effectively iterating over a map while doing something for each key value pair in that map. In other words, I need to duplicate the behavior of a for-each loop in drools without actually writing a for-each loop.
Now, I realize I could just write a for-each loop in the consequence. I want to keep my code as close to drools-standard as possible. I have included a more concrete example below.
I have a map of strings and colors.
Map<String, Color> colorMap
For every color in the map, I want to check a different collection to find the exact code for that color.
Map<Color, ColorCode> colorCodes
A Java dialect approach would be something like the following:
for (Map.Entry<String, Color> entry : colorMap.entrySet())
{
ColorCode code = colorCodes.get(entry.getValue());
thenconsequence.do(code);
}
How would something similar be done using the drools dialect?
Update: The more I think about this problem, the more I am concerned I shouldn't be doing this sort of map lookup/iterating in the context of drools. The right way of doing it may instead be to insert fact object representations of these collections into the working memory. For example, I might wrap each color in a colorFact which has the Color wrapped up in and a field indicating the color name. Same with the codes. I could then write a drool along the lines of:
when
Color(name=="blue", $c:color)
ColorCode(name == "blue", $code:colorCode)
then
$code.printCode();
end
If this is the best way to go about it, I'm concerned about the sheer number of facts I am going to have to add. I already have thousands. This will create tens of thousands more. I'm not worried about memory. Rather, I'm worried about the time required to iterate through all these collections and adding their elements to working memory. Can anyone comment on if this is the best way to do this, or if a better way exists?
回答1:
Although this can be done using a simple set of Java statements, here's how to do it in a single rule, with the least (I think) amount of overhead for insertion etc:
rule "matchcolorcode"
when
$cm: ColorMap()
Map.Entry( $key: key, $color: value ) from $cm.entrySet()
$ccm: ColorCodeMap( $ccm.containsKey($key) )
then
System.out.println( $key + ": " + $color + ", " + $ccm.get($key) );
end
The facts are simple wrappers for generic instantiations of HashMap, e.g.:
class ColorMap extends HashMap<String,Color> {}
来源:https://stackoverflow.com/questions/22547374/drools-mvel-for-each-element-in-a-map