Jess-Rule : Str-Cat in Field comparison doen't compile - ontology

I wan't to match a value (String) of an jess-object and the comparative value is a combination of a string and another field.
Here a simple ("runnable") example:
(defclass Person (is-a :THING) (slot name (type string)) (slot email (type string)))
(mapclass Person)
(make-instance Andy of Person (name "Andy") (email "Andy#mail"))
(defrule search
(object (OBJECT ?tmpPerson)
(is-a Person)
(email (str-cat (slot-get ?tmpPerson name) "#mail"))
)
=>
(print t "found")
)
But the code doesn't compile in JessTab. It seems, that after the field-name "name" the "(" isn't allowed.
Error:
Jess reported an error in routine Jesp.parsePattern.
Message: Bad slot value at token '('.
Program text: ( defrule search ( object ( OBJECT ?tmpPerson ) ( is-a Person ) ( name ( at line 5.
How can I fix this?
Thanks in advance

To match a pattern to the value returned by a function, you have to precede the function call with an equals sign -- i.e., "(name =(str-cat ..."

Related

EPL Every Limit Subexpression Lifetime

I have a particular case for "every" pattern, this is the example code:
SELECT * FROM PATTERN [
every(
e1=Event(device_ip IN ( '10.10.10.1' ) AND category IS NOT NULL ))where timer:within(1800 Sec)
->
e2=Event(device_ip IN ( '10.10.10.1' ) AND event_cat_name.toLowerCase() IN ('User') AND log_session_id = e1.log_session_id)
->
e3=Event(device_ip IN ( '10.10.10.1' ) AND result.toLowerCase() IN ('Block') AND log_session_id = e1.log_session_id )
->
e4=Event(device_ip IN ( '10.10.10.1' ) AND category IS NOT NULL AND log_session_id != e1.log_session_id)
->
e5=Event(device_ip IN ( '10.10.10.1' ) AND event_cat_name.toLowerCase() IN ('User') AND log_session_id = e4.log_session_id)
->
e6=Event(device_ip IN ( '10.10.10.1' ) AND result.toLowerCase() IN ('Block') AND log_session_id = e4.log_session_id )
->
e7=Event(device_ip IN ( '10.10.10.1' ) AND category IS NOT NULL AND log_session_id != e4.log_session_id)
->
e8=Event(device_ip IN ( '10.10.10.1' ) AND event_cat_name.toLowerCase() IN ('User') AND log_session_id = e7.log_session_id)
->
e9=Event(device_ip IN ( '10.10.10.1' ) AND result.toLowerCase() IN ('Block') AND log_session_id = e7.log_session_id )
];
Let me explain it:
We know that "every" pattern will reset after content were found and create another "Window" looking for same event, we are applying every pattern just to "e1" event in this case.
The above code is for 9 events, they are "grouped" by 3 events, as you see from "e1" to "e3" correspond to 1 unique event, from "e4" to "e6" another unique event and so on, each 3 events we know are same unique event because just those 3 events have same ID in "log_session_id", but we know that events from "e1" to "e3" are differents from "e4" to "e6" and different from "e7" to "e9" because every unique event has different ID in "log_session_id".
So when we have the following sequence of events: e1, e2, e3, e4, e5, e6, e7, e8, e9
When "e1" to "e3" are detected, the pattern every reset and search for the same event of "e1"... all is ok until now, but when "e4" event arrives, because of "e1" and "e4" are almost same conditions, the first window match and also match for the new window created when every restarted. We have in "e4" distint conditions but they are not known in "e1" positions yet, so because e1 does not know that e4 exists at first, in the new window is match and 2 Windows are opened until now:
The first one have 2 unique events (e1 to e6)
The second one have 1 unique window (e4 to e6).
And when "e7" to "e9" arrives, are generated another window, in total until now we have 3 Windows:
The first one have 3 unique events (e1 to e9),
The second one have 2 unique events (e4 to e9)
The third one have 1 unique event (e7 to e9).
So, Do you know how to limit just to the first Window using every? we have tried with AND NOT but we cannot manage to do it.
You could make that pattern much smaller and readable by using insert-into for the same-expression filters:
// use this for all the same-expression filters
insert into FilteredStream select Event(device_ip IN ( '10.10.10.1' ));
select * from pattern [every(
e1=FilteredStream(category IS NOT NULL )) where timer:within(1800 Sec)
....)];
For removing overlapping matches, there are multiple choices, such as:
Let the overlapping match happen and use a subquery on the output event to see if it overlaps
Use match-recognize instead which automatically skips-past-last match

How do I “for … order by” in Saxon on Java

This is a follow on to this question.
I make the call:
XQueryCompiler compiler = processor.newXQueryCompiler();
// 21 of the following
xPath.declareNamespace(prefix, uri);
xPath.compile("for $n in '/def:System/def:Securities[def:AssetType != 50]' order by $n/'def:RiskLevel' return $n");
XQueryEvaluator selector = exe.load();
selector.setContextItem(xmlDocument);
// exception thrown on this:
selector.evaluate();
And I get:
net.sf.saxon.s9api.SaxonApiException: Required item type of first operand of '/' is node(); supplied value has item type xs:string
I'm guessing the '/def:System/def:Securities[def:AssetType != 50]' needs to be a node - how do I do that? And also, will making it a node then reduce it to one node rather than returning all nodes that match the query?
And this query can be complex as "node/node[#attr = '5]/node/not[node = 'dave']/node/#atr"
Update: With a query of "for $n in /def:System/def:Securities[def:AssetType != 50] order by $n/'def:RiskLevel, def:SecurityDesc' return $n" I get the same exception.
Those single quotes in the query are spurious. You're binding $n to the string '/def:System/def:Securities[def:AssetType != 50]', and the error is saying you can't use $n/xxx when $n is a string.

Retrieve an element of a list that satisfy a condition

This is my model class:
class Contact {
String name;
String email;
int phoneNo;
Contact(this.name, this.email, this.phoneNo);
}
Suppose I have a list of contacts like below:
List<Contact> contacts = [
new Contact('John', 'john#c.com', 002100),
new Contact('Lily', 'lily#c.com', 083924),
new Contact('Abby', 'abby#c.com', 103385),
];
I want to get John's phone number from contacts List, how can I do that?
singleWhere throws if there are duplicates or no element that matches.
An alternative is firstWhere with orElse https://api.dartlang.org/stable/1.24.3/dart-core/Iterable/firstWhere.html
var urgentCont = contacts.firstWhere((e) => e.name == 'John', orElse: () => null);
print(urgentCont?.phoneNo?.toString()?.padLeft(6, '0') ?? '(not found)');//Output: 002100
This is how I do it using singleWhere:
var urgentCont = contacts.singleWhere((e) => e.name == 'John');
print(urgentCont.phoneNo.toString().padLeft(6, '0'));//Output: 002100
singleWhere(bool test(E element)) → E Returns the single element that
satisfies test.
And there is some other methods in List class. As a example where():
where(bool test(E element)) → Iterable<E> Returns a new lazy Iterable
with all elements that satisfy the predicate test.
Update:
singleWhere() throws an error when there is no matching elements(Bad state: No element). And if there are duplicates, will throw Bad state: Too many elements
So, the best one is firstWhere according to #GunterZochbauer(refer his answer)

Lua Changing Table Keys

Anyone tell me why this doesn't work?
GET_TABLE {1=ID}
key = string.format("%q", GET_TABLE[1])
RETURN_TABLE[key] = "ss"
print(RETURN_TABLE[ID])
print(GET_TABLE[1])
First print result: nil. Second print result: ID
I want the first print result to be: ss
GET_TABLE {1=ID}
key = "ID"
RETURN_TABLE[key] = "ss"
print(RETURN_TABLE[ID])
print(GET_TABLE[1])
The above works fine so I assume its due to the string.format not working right?
The %q format token returns the input as an escaped and quoted Lua string. This means that given the input ID it will return "ID" (the double quotes being part of the string!) which is a different string. (Or, represented as Lua strings, the input is 'ID' and the return value is '"ID"'.)
You have therefore set the ID key while trying to retrieve the "ID" key (which presumably does not exist).
> x = 'ID'
> =x
ID
> =string.format('%q', x)
"ID"
> =#x
2
> =#string.format('%q', x)
4
Your code does not compile (you need [] around the index), and you should use the raw string of ID, not the "quoted" string:
GET_TABLE = {[1]=ID}
key = string.format("%s", GET_TABLE[1])
Note that I had to initialize ID and RETURN_TABLE objects to the following:
ID = 'ID'
RETURN_TABLE = {}
Stylistic note: you should only use all-caps names for constants, otherwise too many makes code hard to read

What would LINQ to Entities return when selecting an integer id for a given row name if the record does not exist?

Here's the code:
string name = "myName";
int id = (int)_myDB.ThingTable.Where(thing => thing.ThingName == name)
.Select(thing => thing.ThingId);
I have an error saying System.Linq.IQueryable cannot be converted to int (I'm assuming it's so that I don't end up with a case where no rows are found- no id is returned)
First, how can I cast it to an int?
Second, what gets returned if no record with a ThingName == name exists?
Thanks,
Matt
You need a query expression that returns a scalar. Something like:
myCollection.Where(c => c.X > 0).FirstOrDefault();
In your example it would be:
int id = (int)_myDB.ThingTable.Where(thing => thing.ThingName == name)
.Select(thing => thing.ThingId).FirstOrDefault();
If no row is returned, the default value of the scalar is returned (generally zero in the case of a non-nullable number).
Try using FirstOrDefault() on queries such as that. It will return the default value for the selection if nothing is returned. 0 for numbers, null for objects.

Resources