I have a situation, I need to dynamically add rules in drools. If its a simple rule I can create a string for the same and add it into knowledgebase, but there is a situation where I need to include a list as part of the rule, which will also be created dynamically. Adding the rule and adding the list will happen as different events.
I thought of having a hashmap<String, List<String>> where key is the name of the list, now I want to know, is there way to access the hashmap, retrieve the list using the list name, and use in when criteria of drools as:
$pojo:Pojo($listOfString : list1, $listOfString contains input)
while adding the rule into drools.
And far as I know, even having a general name for the list in pojo wont work, as during fireRule, the drools will be totally confused in choosing the list to be used, and if I assign value to the list while firing rule, then for each rule he will use same list, and result will be as not expected.
Or if there is any other way of achieving the same, please tell me.
I am using drools 5.1
You can launch a query for an element in one of the lists by inserting a Query fact containing the list identification and the element value. eval should work in 5.1.1, IIRC. You may have to guard against there being no List for key x to avoid a NPE.
rule "is element y in list with key x"
when
Query( $x: key, $y: element )
Pojo( $map: map )
eval( $map.get($x).contains( $y ) )
then
...
end
Finally I was able to achieve the same with a slightly different rule formation, but all thanks to #laune for showing the right way. The rule can be written as:
rule "is element value in list with key key1"
when
pojo: Pojo($map:map)
entry: Entry() from $map.entrySet()
value : String() from entry.getValue()
key1 : String() from entry.getKey()
Boolean(booleanValue == true) from (value == pojo.input && key1 == pojo.key)
then
........
end
here input is the element we want to search in the list, and key1 is the name of the list in which the input has to be searched.
EDIT
pojo.key wont be used, as the list name will be already set when creating the rule, so the only variable will be String(pojo.value) against which the List has to be evaluated.
Related
Is there a way to find the Mean of a named property in a LinkedHashMap belonging to each of a Collection of Agents, without iterating the collection?
In plain Java terms, that could be restated as "find the Mean of a property stored in a LinkedHashMap belonging to each item of a List". Indeed, it has to be done from a List, as the Agent collection has to be filtered first, based upon the value of a variable.
Duplicating the LinkedHashMap property in a standalone parameter is not an option, as there are actually 135 of them, which is one reason why they're in the LinkedHashMap, and it would therefore negate any performance benefit when compared to iterating the one for which the mean is required at any given point.
In response to Benjamin's question, here's my current code to do it manually, where sParam is the stub of the LinkedHashMap item name and iSegment is the unique:
// Iterate the Products:
for (Product oProduct : Products.findAll(
p -> p.v_active == true
)) {
// Add the Segment value for this Param:
iCountProducts++;
dblTotal += oProduct.v_paramMap.getOrDefault(sParam + Integer.toString(iSegment), 0.0);
}
// Calculate the mean:
dblReturn = dblTotal / iCountProducts;
I'm simply wondering if there's an averageWhere style that can be adapted to this situation. No biggie if not - the above runs 1000 times in 0.008 seconds.
I have a pretty large list containing many instances of one class, this class has many attributes(member variables). My problem is to find a feasible data structure to store these instances that allow searches based on multiple attributes like database search(i.e. A Student class, each student has age, date of birth, grade and GPA.find all 2nd year students whose ages are between 20 and 23). The Map seems not applicable as it only allow single key and if I create multi attribute index for searching, the big O is still not decreased. I also considered using trees like AVL tree, and I don't think it would work.
I'd be grateful if someone could give me some hints.
I think what you are looking for is an Inverted Index (using attribute name + value as keys) or possibly one Inverted Index per attribute. A search would build the intersection of all results found for each attribute.
You could do this:
Build an AVL tree with objects sorted by the most recurrent attribute (just one, e.g. "id" or "name").
Then create a search function that instead of taking a value, takes a Java lambda expression F (so your seacrh condition must be something like F(myObj) == true instead of myObj.deFaultAttribute == searchParameter)
For the example you gave, F could be something like ((myObj) -> myObj.year==2 && myObj.age>=20 && myObj.age<=23)
I hope it helps.
Lets say I do Map<String, Integer> map = new HashMap<String, Integer>();
map.containsValue(value) returns true whether or not the value is found in the hashmap. But I found that there is no way to remove a value. Like map.removeValue(value). You can only remove the key, as in, map.removeKey(key).
Now, my question is, does removing the key also remove the value?
So when I search map.containsValue(value), will it return false if I deleted the key associated with the value with map.removeKey?
Now, my question is, does removing the key also remove the value?
Yes. Sort of.
Actually, it removes the specific entry that consists of the key and the value.
If the value is also used in another entry, then that other entry is unaffected, and the value will still show up in the values collection.
So when I search map.containsValue(value), will it return false if I deleted the key associated with the value with map.removeKey?
It depends ... see above.
This information can easily be found by reading the javadoc carefully.
(The problem with the "try it and see" approach is that it is easy to write a "black box" test that will cause you to drawing the wrong conclusions. I would only suggest "try it and see" if the javadoc did NOT contain the information. And I'd add "read the source" ... )
I know how easy it is to write a Drools rule to find the max value from a list of objects
e.g. MyBase(listOfObjects : myObjects)
accumulate (MyObject($value : value, $value != null) from listOfObjects; $maxValue : max($value))
My question is, how do you write a Drools rule to find the max value from a list of objects' list of objects?
e.g. MyBase(listOfObjects : myObjects)
accumulate (MyObject(anotherListOfObjects : mySmallerObjects) from listOfObjects
,MySmallerObject($value : value, $value != null) from anotherListOfObjects; $maxValue : max($value))
The above doesn't work.
So basically, I have an object MyBase, which has List<MyObjects> myObjects. Within myObjects, I want to find the max value from their List<MySmallerObject> mySmallerObjects (across all the myObjects, not just within mySmallerObjects)
I believe it is doable in Drools, I just need to get the syntax right.
I am using Drools version 5.5, thank you!
Hmm, I would collect all MySmallerObjects first, then accumulate over the collect operation's result. collect allows nested from elements. See chapter 4.8.3.7.3. Conditional Element collect in the Drools Expert User Guide http://docs.jboss.org/drools/release/5.5.0.Final/drools-expert-docs/html_single/index.html#d0e5351.
I have a question regarding the LinkedList class in Java.
I have a scenario wherein i need to add or set an index based on whether the index exists in the linkedlist or not. A pseudo-code of what i want to achieve is --
if index a exists within the linkedlist ll
ll.set(a,"arbit")
else
ll.add(a,"arbit")
I did go through the Javadocs for the LinkedList class but did not come across anything relevant.
Any ideas ?
Thanks
p1ng
What about using a Map for this:
Map<Integer, String> map = new HashMap<Integer, String>();
// ...
int a = 5;
map.put(a, "arbit");
Even if a already exists, put will just replace the old String.
Searching in linked list is not very efficient (O(n)). Have you considering using different data structure - e.g. HashMap which would give you O(1) access time?
If you need sequential access as well as keyed access you might want to try a LinkedHashMap, available as from 1.4.2
http://download.oracle.com/javase/1.4.2/docs/api/java/util/LinkedHashMap.html
Map<Integer, String> is definitely a good (the best?) way to go here.
Here's an option for keeping with LinkedList if that's for some bizarre reason a requirement. It has horrible runtime performance and disallows null, since null now becomes an indicator that an index isn't occupied.
String toInsert = "arbit";
int a = 5;
//grow the list to allow index a
while ( a >= ll.size() ) {
ll.add(null);
}
//set index a to the new value
ll.set(a, toInsert);
If you're going to take this gross road, you might be better off with an ArrayList.
Why is it so bad? Say you had only one element at index 100,000. This implementation would require 100,000 entries in the list pointing to null. This results in horrible runtime performance and memory usage.
LinkedList cannot have holes inside, so you can't have list [1,2,3,4] and then ll.add(10,10), so I think there's something wrong with your example. Use either Map or search for some other sparse array
It looks like you're trying to use a as a key, and don't state whether you have items at index i < a. If you run your code when ll.size() <= a then you'll end up with a NullPointerException.
And if you add an item at index a the previous item at a will now be at a+1.
In this case it would be best to remove item at a first (if it exists) then add item "arbit" into a. Of course, the condition above re: ll.size() <=a still applies here.
If the order of the results is important, a different approach could use a HashMap<Integer,String> to create your dataset, then extract the keys using HashMap<?,?>.getKeySet() then sort them in their natural order (they're numeric after all) then extract the values from the map while iterating over the keySet. Nasty, but does what you want... Or create your own OrderedMap class, that does the same...
Could you expand on why you need to use a LinkedList? Is ordering of the results important?