I have a XML file containing metadata like a field's maximum length. I have to use drools to build rules to validate this metadata against a list of facts. I don't want to hardcode the name of each field that may or may not be specified in the XML.
I tried to do this :
when
$metadata: Metadata(maxLength != null);
$obj: Object(eval($metadata.getFieldName()).length > $metadata.maxLength);
then
// TODO
end
It does not work and I get the following error :
java.lang.IllegalStateException: Errors while building rules : Unable
to Analyse Expression $metadata.getFieldName() > $metadata.maxLength:
[Error: Comparison operation requires compatible types. Found class
java.lang.String and class java.lang.Integer] [Near : {...
$metadata.getFieldName() > $metadata.maxLength ....}]
Is it possible to dynamically get a field name and compare its maximum length? Will I have to create a java object to accomplish this?
Thank you
You talk of XML and metadata. Can you distinguish all entities? For example, if it is about orders, can you extract each order, and attributes of each order?
I solved a similar problem with using maps to store each attribute.
public class Order{
private int id;
private Map<String, Integer> num_attribute_map = new HashMap<String, Integer>();
public Map getNumAttributeMap(){
return this.num_attribute_map;
}
If an order has customer_satisfaction = 5,
order_obj.getNumAttributeMap().put("customer_satisfaction" , 5);
And thus you have created Orders with their attributes stored in the numAttributeMap.
For implementing a rule on an Order
$ord : Order(
getNumAttributeMap[$attribute] >= $value
)
where $attribute would be "customer_satisfaction", of course. The [] notation is used to access elements of a list, given index or values of a map, given the key.
Hope you "get" the concepts of maps. Also, do look up Drools language support for list and map access.
I have also implemented maps of lists of strings to perform an "is in" operation, in addition to maps of integers that do comparison operations. Please refer https://stackoverflow.com/a/9241089/604511 too
Finally, I have decided to generate my drools file dynamically from my XML using rule templates.
Related
I am working on a Scala codebase and I have to implement a scenario which uses some data structure to populate information for further processing.
The gist of the problem is,
I have a dataframe studentDf which has the student marksheet information eg.
Name, ID, Subject, Details, Marks, isFail
Now there can be multiple records for the same Name-ID mapping. I have to reflect the scenario where if the student has failed in any subject, the details (and the corresponding record) will pop up in a resultDf. And if he has not failed in any subject (congratulations!!!) then we can populate any record corresponding to the Name-ID mapping.
Basically what I would do in Java 8 for this is,
Assuming I have List<StudentMarks> studentMarksList => list of all the marks of all the students.
Map<String, List<StudentMarks>> studentToMarkMapping = new HashMap<>();
studentMarksList.stream().foreach(studentMark->{
studentToMarkMapping.computeIfAbsent(studentMark.getName()+"_"+studentMark.getID, k => new ArrayList<>()).add(studentMark);
}
Set<Student> resultSet = new HashSet<>();
for(Map.Entry<String,List<StudentMarks>> studentToMark : studentToMarkMapping){
List<StudentMarks> studentMarks = studentToMark.getValue();
for(StudentMarks studentMark : studentMarks){
if(studentMark.getFailed() == true){//Return corresponding failed subject record
resultSet.add(studentMark);
break;
}
}
resultSet.add(studentMark.get(0)); // just add any subjectMark for student who has passed all subjects
}
In Scala to do the same, I was trying to load the data into a Mutable Map, but to populate multiple records for the same student into a list and then find out whether he has failed in any or not, I am getting stuck. I see the concept of using ListBuffer which is a mutable variant of a list, but I am confused how to use it. It is possible that we can do without Map as well, but I tried some other ways which didn't end up working.
If somebody can provide any help on this, would be great. Thanks a lot!!!
I have a List of Objects
List<Person> personLst = [{"person:" {personName:AASH_01 , country :AUS, state :ADL, zip :null },
{personName:AASH_01 , country :AUS, state :MLB, zip :null}}]
and Map holds a key value and based on this need to apply the filter for the list.
Map<String, String> lstMap = new HashMap<>();
lstMap.put("ADL","12345")
Apply Filter Condition:
If the personLst.contains(ADL) this is a map key filter it and replace the zip with map value(12345).
Tried different stackoverflow question , did not help much on .
Just to be sure,
List<Person> personLst = [{"person:" {personName:AASH_01 , country :AUS, state :ADL, zip :null },{personName:AASH_01 , country :AUS, state :MLB, zip :null}}]
really refers to a list of valid java objects, right? Because in the current state those would be valid JavaScript Objects, but not valid Java objects.
Also, should a List<Person> really be called with personLst.contains(String)?
So, assuming these are valid Java objects with the correct getters and setters, and the correct method is intended, you should be able to use
personLst.forEach(p -> {
if(lstMap.containsKey(p.getState()))
p.setZip(lstMap.get(p.getState()));
});
I've seen a lot of examples of using UpdateExpression to update attributes using the updateItem method. However, I still don't understand how to update multiple attributes in DynamoDB at the same time dynamically.
I am trying to update AND rename multiple attributes in the same updateItem call.
I understand that this requires a REMOVE of the old name and a SET of the new name. I have these names in hashedId's of objects, but won't have them until runtime. So my question is how do I use UpdateExpression with variables and not a hard-coded String?
All the examples I have seen use hard-coded UpdateExpressions.
can't update item in DynamoDB
Dynamo DB : UpdateItemSpec : Multiple Update Expression - Not Working
DynamoDB update Item multi action
How to rename DynamoDB column/key
I am working in Java.
It seems very odd to me that I haven't been able to find an example of this... which leads me to believe I am doing something wrong.
Thanks for the help!
You have to build the update expression string dynamically based on the attribute names and values that you receive at runtime. I do exactly this. I'm not working in Java, but here is some pseudo code (with a Ruby bias) example for you that dynamically builds the update expression string, the expression attribute names hash, and the expression attribute values hash. You can then plug in these 3 things into the update_item method:
update_exp_set = [] //array of remove expression snippets
update_exp_remove = [] //array of update expression snippets
exp_attribute_names = {} //hash of attribute names
exp_attribute_values = {} //hash of attribute values
// Iterate through all your fields and add things as needed to your arrays and hashes.
// Two examples are below for a field with the name <fieldName> and value <fieldValue>.
// You'll need to convert this to Java and update it to make sense with the AWS Java SDK.
// For a given field that needs to be updated:
update_exp_set << "#<fieldName> = :fieldValue" //add to array of set expression snippets
exp_attribute_names["#<fieldName>"] = "<fieldName>" //add to hash of attribute names
exp_attribute_values[":<fieldValue>"] = "<fieldValue>" //add to hash of attribute values
// For a given field that needs to be removed:
update_exp_remove << "#<fieldName>"
exp_attribute_names["#<fieldName>"] = "<fieldName>" //add to hash of attribute names
// Use your snippets to create your full update expression:
update_exp_set_clause = ""
update_exp_remove_clause = ""
if update_exp_set.length != 0 //check if you have something to set
update_exp_set_clause = "SET " + update_exp_set.join(',')
end
if update_exp_remove.length != 0 //check if you have something to remove
update_exp_remove_clause = "REMOVE" + update_exp_remove.join(',')
end
final_update_exp = update_exp_set_clause + " " + update_exp_remove_clause
Does this help?
I am using the AWS Java SDK for communicating with DynamoDB. I am trying to do a table update of some properties stored in a map.
Before the update, I have an object that looks like this:
{
"myMap": {
"innerMap": {}
},
"hashKeyName": "hashKeyValue"
}
My code looks like this:
Table myTable = ...;
myTable.updateItem("hashKeyName", "hashKeyValue",
new AttributeUpdate("myMap.innerMap.myKey").addNumeric(100));
After this update, my Dynamo object looks like this (notice that the map is still empty):
{
"myMap": {
"innerMap": {}
},
"myMap.innerMap.myKey": 100,
"hashKeyName": "hashKeyValue"
}
Why was myMap.innerMap.myKey added as a separate field instead of being correctly set in the map?
The reason for this is because using AttributeUpdate is considered a legacy operation and the usage of map keys as attribute names is not supported. The correct usage to use an update expression:
myTable.updateItem("hashKeyName", "hashKeyValue",
"ADD myMap.innerMap.myKey :val", null /* NameMap, see comment */,
new ValueMap().withNumeric(":val", 100));
Notice that there is no name map in the above expression. One might be tempted to do use ADD #name :val as an update expression and then provide a name map for #name => myMap.innerMap.myKey. In this case, these expressions are not equivalent. When a . appears in the raw expression, it is treated as a path separator. When . appears in a NameMap value, it is not considered a path separator.
I'm using JBoss Drools 5.5.0 rules.
I have an ArrayList<ElementDetail>, and Map<String, ElementDetail>, and I need to do print out all the ElementDetail in ArrayList but not in Map.
class ElementDetail {
private String name;
...
}
ElementDetail class has a name variable which is identified as the Map key.
So far this is what I tried, but it gives no matches:
...
when
eleList : List()
$eleDetail : ElementDetail() from eleList
$map: Map(myMap.keySet contains $eleDetail.getName())
...
I was able to find similar posts for matching elements in a collection, but it does not get the unmatched elements for a map:
Drools and Maps
drools rule get value from a map
to check if an Object is present in List in Drools
Well, you'll have to use the negated form of contains, and myMap is not bound.
$eleList : List()
$eleDetail : ElementDetail( $name: name ) from $eleList
$map: Map( keySet not contains $name )