Ordering using a declared variable's property - jdo

I have a ScInfo class that exists in many different classes. This class also has a list of ScDetails which has a Date member variable called nextExecution.
I need to continuously look up eligible objects with their ScDetails object's nextExecution member variable is after or equal to the current server's time (i.e. persistenceManagerInstance.getServerDate()). Meaning that I need to look up objects, with ScInfo having a ScDetails object with nextExecution >= serverDate)
So I use the following method (A portion is shown):
public List<Object[]> getEligbleForExecution(long amount) {
PersistenceManager pm = null;
Transaction t = null;
try {
pm = getPM();
t = pm.currentTransaction();
t.begin();
Query q = pm
.newQuery(
entityClass, //This is generic
"!this.deleted && this.scheduleActive && det.active == true && (det.nextExecution == null || det.nextExecution <= :serverDate) && det.running == false && this.scInfo.scDetails.contains(det)");
q.declareVariables(ScDetail.class.getName() + " det;");
q.setRange(0, amount);
q.setResult("this, det");
q.setOrdering("det.nextExecution"); // This is the statement I need to apply but it's causing the error below
Date serverDate = pm.getServerDate();
List<Object[]> raw = new ArrayList<Object[]>((List<Object[]>) q.execute(serverDate));
Which throws the following error stack trace (DEBUG level, I mentioned what I thought to be essential for solving this problem):
14:54:32 DEBUG (Log4JLogger.java:58)-[main] >> QueryToSQL.processVariable (unbound) variable=det is not yet bound so returning UnboundExpression
14:54:32 DEBUG (Log4JLogger.java:58)-[main] Updating mapping of org.datanucleus.store.rdbms.sql.expression.NullLiteral#727f3b8a to be org.datanucleus.store.mapped.mapping.DateMapping#e72a8082
14:54:32 DEBUG (Log4JLogger.java:58)-[main] Transaction rolling back for ObjectManager org.datanucleus.MultithreadedObjectManager#fba0f36
14:54:32 DEBUG (Log4JLogger.java:58)-[main] Rolling back [DataNucleus Transaction, ID=Xid={A strange uncopyable character is in here !}, enlisted resources=[]]
14:54:32 DEBUG (Log4JLogger.java:58)-[main] Transaction rolled back in 1 ms
14:54:32 ERROR (ScTasksDAOImpl.java:67)-[main] Looking up eligible SC tasks
java.lang.NullPointerException
at org.datanucleus.store.rdbms.query.QueryToSQLMapper.processVariableExpression(QueryToSQLMapper.java:3245)
at org.datanucleus.store.rdbms.query.QueryToSQLMapper.processPrimaryExpression(QueryToSQLMapper.java:2075)
at org.datanucleus.query.evaluator.AbstractExpressionEvaluator.compilePrimaryExpression(AbstractExpressionEvaluator.java:180)
at org.datanucleus.query.evaluator.AbstractExpressionEvaluator.compileUnaryExpression(AbstractExpressionEvaluator.java:169)
at org.datanucleus.query.evaluator.AbstractExpressionEvaluator.compileAdditiveMultiplicativeExpression(AbstractExpressionEvaluator.java:148)
at org.datanucleus.query.evaluator.AbstractExpressionEvaluator.compileRelationalExpression(AbstractExpressionEvaluator.java:123)
at org.datanucleus.query.evaluator.AbstractExpressionEvaluator.compileOrAndExpression(AbstractExpressionEvaluator.java:65)
at org.datanucleus.query.evaluator.AbstractExpressionEvaluator.evaluate(AbstractExpressionEvaluator.java:46)
at org.datanucleus.query.expression.Expression.evaluate(Expression.java:337)
at org.datanucleus.store.rdbms.query.QueryToSQLMapper.compileOrdering(QueryToSQLMapper.java:845)
at org.datanucleus.store.rdbms.query.QueryToSQLMapper.compile(QueryToSQLMapper.java:403)
at org.datanucleus.store.rdbms.query.JDOQLQuery.compileQueryFull(JDOQLQuery.java:883)
at org.datanucleus.store.rdbms.query.JDOQLQuery.compileInternal(JDOQLQuery.java:343)
at org.datanucleus.store.query.Query.executeQuery(Query.java:1747)
at org.datanucleus.store.query.Query.executeWithArray(Query.java:1666)
at org.datanucleus.api.jdo.JDOQuery.execute(JDOQuery.java:243)
at com.sc.ipk.sc.services.ScTasksDAOImpl.getEligbleForExecution(ScTasksDAOImpl.java:41)
at com.sc.ipk.ixl.services.IxlTestDAOImpl.main(IxlTestDAOImpl.java:977)
14:54:32 DEBUG (Log4JLogger.java:58)-[main] Object Manager "org.datanucleus.MultithreadedObjectManager#fba0f36" closed
So is it not possible to use declared variables to query ordering ? I tried using sub-queries but I couldn't get that to work either, may be I can start a new question for that, if ordering using declared variables isn't possible.
EDIT:
Neil generously suggested that ordering based on an element that should exist in a collection doesn't look reasonable to him. I understand that but I cannot for example look-up ScDetails objects first after ordering them of course and then look-up my main objects afterwards because my target main object may differ from time to time and I may look-up ScDetails objects that doesn't belong to the main candidate class.
For example:
A has ScInfo which has a collection of ScDetails
B, C (Same as above)
So if I lookup ScDetails objects first (After ordering an all), I cannot filter my main candidate classes (A, B & C) because I may use a ScDetails that belongs to A while I'm trying to get B or C candidates.
Thank you.

I don't see how you can order by that variable. It represents an element of a collection of the candidate. Consequently if a candidate has say 5 elements then it is indeterminate how it can order by some property on the element (1-N mapping). Obviously if the candidate was the element then ordering by some property of the element makes perfect sense, whether variable or not.

Related

Kotlin - very frequent data removal and addition to a list causes npe

I've a buffer that is actually ArrayList<Object>.
Happens async:
This buffer list changes very frequently - I mean 15-50 times in single second and the idea is that whenever there's an update, I remove first element by position buffer.removeAt(0) and add new value in the end by buffer.add(new).
At some point I call a function that goes and do calculation with buffer list. What I do is I go through the list - element by element. At some point I run into NPE as the the element has been removed async.
How to solve this NPE? I was thinking of making deep copy, but making deep copy would mean to go through the buffer list and do some data allocation, which basically means that while I do deep copy I can still run into NPE.
How problems like these are solved?
How to solve NPE?
What would be more optimized way as this is gonna consume a lot of memory?
Code:
private fun observeFrequentData() {
frequentData.observe(owner, Observer { data ->
if (accelerationData == null) return#Observer
GlobalScope.launch {
val a = data[0].toDouble()
val b = data[1].toDouble()
val c = a + b
val timestamp = System.currentTimeMillis()
val customObj = CustomObj(c, timestamp)
if (buffer.size >= 5000) {
buffer.removeAt(0)
}
buffer.add(acceleration)
}
})
}
fun getBuffer() {
val mappedData = buffer.map { it.smth } // NPE, it == null
}
If you are doing lots of removing from 0, and insert at the end. Then ArrayList is probably not the container to use.
you can consider using a LinkedList .
buffer.removeFirst();
and
buffer.add(acceleration);
also note the following comments regarding synchronization.
Note that this implementation is not synchronized. If multiple threads
access a linked list concurrently, and at least one of the threads
modifies the list structurally, it must be synchronized externally. (A
structural modification is any operation that adds or deletes one or
more elements; merely setting the value of an element is not a
structural modification.) This is typically accomplished by
synchronizing on some object that naturally encapsulates the list. If
no such object exists, the list should be "wrapped" using the
Collections.synchronizedList method. This is best done at creation
time, to prevent accidental unsynchronized access to the list:
List list = Collections.synchronizedList(new LinkedList(...));
Using the synchronized keyword on your piece of code as #patrickf suggested.
To take care of performance, instead of making the method call itself synchronized, you can just write the 3 "buffer" related lines of code (size, removeAt and add) in a synchronized block.
Something like;
.
.
.
synchronized {
if (buffer.size >= 5000) {
buffer.removeAt(0)
}
buffer.add(acceleration)
}
}
})
Hope this helps!

Java 8 Map merge VS compute, essential difference?

It seems Both merge and compute Map methods are created to reduce if("~key exists here~") when put.
My problem is: add to map a [key, value] pair when I know nothing: neither key existing in map nor it exist but has value nor value == null nor key == null.
words.forEach(word ->
map.compute(word, (w, prev) -> prev != null ? prev + 1 : 1)
);
words.forEach(word ->
map.merge(word, 1, (prev, one) -> prev + one)
);
Is the only difference 1 is moved from Bifunction to parameter?
What is better to use? Does any of merge, compute suggests key/val are existing?
And what is essential difference in use case of them?
The documentation of Map#compute(K, BiFunction) says:
Attempts to compute a mapping for the specified key and its current mapped value (or null if there is no current mapping). For example, to either create or append a String msg to a value mapping:
map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))
(Method merge() is often simpler to use for such purposes.)
If the remapping function returns null, the mapping is removed (or remains absent if initially absent). If the remapping function itself throws an (unchecked) exception, the exception is rethrown, and the current mapping is left unchanged.
The remapping function should not modify this map during computation.
And the documentation of Map#merge(K, V, BiFunction) says:
If the specified key is not already associated with a value or is associated with null, associates it with the given non-null value. Otherwise, replaces the associated value with the results of the given remapping function, or removes if the result is null. This method may be of use when combining multiple mapped values for a key. For example, to either create or append a String msg to a value mapping:
map.merge(key, msg, String::concat)
If the remapping function returns null, the mapping is removed. If the remapping function itself throws an (unchecked) exception, the exception is rethrown, and the current mapping is left unchanged.
The remapping function should not modify this map during computation.
The important differences are:
For compute(K, BiFunction<? super K, ? super V, ? extends V>):
The BiFunction is always invoked.
The BiFunction accepts the given key and the current value, if any, as arguments and returns a new value.
Meant for taking the key and current value (if any), performing an arbitrary computation, and returning the result. The computation may be a reduction operation (i.e. merge) but it doesn't have to be.
For merge(K, V, BiFunction<? super V, ? super V, ? extends V>):
The BiFunction is invoked only if the given key is already associated with a non-null value.
The BiFunction accepts the current value and the given value as arguments and returns a new value. Unlike with compute, the BiFunction is not given the key.
Meant for taking two values and reducing them into a single value.
If the mapping function, as in your case, only depends on the current mapped value, then you can use both. But I would prefer:
compute if you can guarantee that a value for the given key exists. In this case the extra value parameter taken by the merge method is not needed.
merge if it is possible that no value for the given key exists. In this case merge has the advantage that null does NOT have to be handled by the mapping function.

Runtime error:dictionary changed size during iteration

I iterate thru items of a dictionary "var_dict".
Then as I iterate in a for loop, I need to update the dictionary.
I understand that is not possible and that triggers the runtime error I experienced.
My question is, do I need to create a different dictionary to store data? As is now, I am trying to use same dictionary with different keys.
I know the problem is related to iteration thru the key and values of a dictionary and attempt to change it. I want to know if the best option in this case if to create a separate dictionary.
for k, v in var_dict.items():
match = str(match)
match = match.strip("[]")
match = match.strip("&apos;&apos;")
result = [index for index, value in enumerate(v) if match in value]
result = str(result)
result = result.strip("[]")
result = result.strip("&apos;")
#====> IF I print(var_dict), at this point I have no error *********
if result == "0":
#It means a match between interface on RP PSE2 model was found; Interface position is on PSE2 architecture
print (f&apos;PSE-2 Line cards:{v} Interfaces on PSE2:{entry} Interface PortID:{port_id}&apos;)
port_id = int(port_id)
print(port_id)
if port_id >= 19:
#print(f&apos;interface:{entry} portID={port_id} CPU_POS={port_cpu_pos} REPLICATION=YES&apos;)
if_info = [entry,&apos;PSE2=YES&apos;,port_id,port_cpu_pos,&apos;REPLICATION=YES&apos;]
var_dict[&apos;IF_PSE2&apos;].append(if_info)
#===> *** This is the point that if i attempt to print var_dict, I get the Error during olist(): dictionary changed size during iteration
else:
#print(f&apos;interface:{entry},portID={port_id} CPU_POS={port_cpu_pos} REPLICATION=NO&apos;)
if_info = [entry,&apos;PSE2=YES&apos;,port_id,port_cpu_pos,&apos;REPLICATION=NO&apos;]
var_dict[&apos;IF_PSE2&apos;].append(if_info)
else:
#it means the interface is on single PSE. No replication is applicable. Just check threshold between incoming and outgoing rate.
if_info = [entry,&apos;PSE2=NO&apos;,int(port_id),port_cpu_pos,&apos;REPLICATION=NO&apos;]
var_dict[&apos;IF_PSE1&apos;].append(if_info)
I did a shallow copy and that allowed me to iterate a dictionary copy and make modifications to the original dictionary. Problem solved. Thanks.
(...)
temp_var_dict = var_dict.copy()
for k, v in temp_var_dict.items():
(...)

Duplicate items in Set

In Kotlin, I have a MutableSet of a data class. The data class does not override equals() or hashCode(). I've been encountering bugs involving duplicate objects in the set, and I noticed that calling foo.containsAll(foo) returns false for the set.
I went through each item in the set and only a handful return false for foo.contains(foo.toList()[i]). For those that do, calling foo.toList()[i] == foo.toList()[i] returns true. So, equality checking works.
What is going on here?
I believe the only way this is possible (short of reflection, etc.) is if your data class contains something mutable and an instance changing state after being added to the set, etc. e.g.
data class Foo(var int: Int = 0)
data class Bar(val string: String, val foo: Foo = Foo())
val bars = mutableSetOf<Bar>()
bars += Bar("")
bars += Bar("")
println(bars.containsAll(bars)) // true
bars.first().foo.int = 12
println(bars.containsAll(bars)) // false
This is because the result of hashCode() is being used in the set to identify it but if the state changes in an instance of your data class then it will likely have a different hash value causing issues like this.
In general elements in sets and keys in maps should be immutable to avoid this issue.

Can I insert into a map by key in F#?

I'm messing around a bit with F# and I'm not quite sure if I'm doing this correctly. In C# this could be done with an IDictionary or something similar.
type School() =
member val Roster = Map.empty with get, set
member this.add(grade: int, studentName: string) =
match this.Roster.ContainsKey(grade) with
| true -> // Can I do something like this.Roster.[grade].Insert([studentName])?
| false -> this.Roster <- this.Roster.Add(grade, [studentName])
Is there a way to insert into the map if it contains a specified key or am I just using the wrong collection in this case?
The F# Map type is a mapping from keys to values just like ordinary .NET Dictionary, except that it is immutable.
If I understand your aim correctly, you're trying to keep a list of students for each grade. The type in that case is a map from integers to lists of names, i.e. Map<int, string list>.
The Add operation on the map actually either adds or replaces an element, so I think that's the operation you want in the false case. In the true case, you need to get the current list, append the new student and then replace the existing record. One way to do this is to write something like:
type School() =
member val Roster = Map.empty with get, set
member this.Add(grade: int, studentName: string) =
// Try to get the current list of students for a given 'grade'
let studentsOpt = this.Roster.TryFind(grade)
// If the result was 'None', then use empty list as the default
let students = defaultArg studentsOpt []
// Create a new list with the new student at the front
let newStudents = studentName::students
// Create & save map with new/replaced mapping for 'grade'
this.Roster <- this.Roster.Add(grade, newStudents)
This is not thread-safe (because calling Add concurrently might not update the map properly). However, you can access school.Roster at any time, iterate over it (or share references to it) safely, because it is an immutable structure. However, if you do not care about that, then using standard Dictionary would be perfectly fine too - depends on your actual use case.

Resources