Neo4j cypher avoid negative values - neo4j

I have a node that has properties based on another node, For example:
MATCH (n:draft {sn:1}),(m:final {sn:1})
SET m.count = m.count - n.count
RETURN m
Seems to work. However what I want to do is set m.count to 0 if n.count > m.count. n.count > m.count results in a negative value and I want to avoid this.

You should be able to do this:
MATCH (n:draft {sn:1}),(m:final {sn:1})
SET m.count = CASE WHEN n.count > m.count THEN 0 ELSE m.count - n.count END
RETURN m

Related

Different result of Traversal

Traversal API is giving different result for seemingly same declaration. In method 1. I took method 1 sample from neo4j's site. And tried to restructure it in method 2. However, apparently there is not difference, both methods are producing different output. Method2 is completely skipping LIKE relationship. Even if I change the sequence in method1 like putting depthFirst() in last, the output changes.
It will be great if someone could please help me understand this different output?
Method 1:
void depthFirst() {
GraphDatabaseBuilder graphDbBuilder = new GraphDatabaseFactory()
.newEmbeddedDatabaseBuilder(storeDir);
GraphDatabaseService graphDb = graphDbBuilder.newGraphDatabase();
String output = "";
int i = 0;
try (Transaction tx = graphDb.beginTx()) {
Node node = graphDb.findNode(LabelTyeps.Person, "name", "Joe");
for (Path position : graphDb.traversalDescription().depthFirst()
.relationships(RelationshipTypes.KNOWS)
.relationships(RelationshipTypes.LIKES, Direction.INCOMING)
.evaluator(Evaluators.toDepth(5)).traverse(node)) {
output += position.toString() + ":"
+ (String) position.endNode().getProperty("name")
+ "\n";
}
System.out.println(output);
}
graphDb.shutdown();
}
Output of method 1:
(3):Joe
(3)<--[LIKES,1]--(8):Lisa
(3)<--[LIKES,1]--(8)--[KNOWS,2]-->(4):Lars
(3)<--[LIKES,1]--(8)--[KNOWS,2]-->(4)--[KNOWS,4]-->(7):Dirk
(3)<--[LIKES,1]--(8)--[KNOWS,2]-->(4)--[KNOWS,4]-->(7)--[KNOWS,5]-->(6):Peter
(3)<--[LIKES,1]--(8)--[KNOWS,2]-->(4)--[KNOWS,4]-->(7)--[KNOWS,5]-->(6)--[KNOWS,7]-->(5):Sara
(3)<--[LIKES,1]--(8)--[KNOWS,2]-->(4)<--[KNOWS,3]--(9):Ed
Method 2 (Just changed the way travDesc is structured)
try (Transaction tx = graphDb.beginTx()) {
Node node = graphDb.findNode(LabelTyeps.Person, "name", "Joe");
TraversalDescription travDesc = graphDb.traversalDescription();
travDesc.depthFirst();
travDesc.relationships(RelationshipTypes.KNOWS);
travDesc.relationships(RelationshipTypes.LIKES, Direction.INCOMING);
travDesc.evaluator(Evaluators.toDepth(5));
for (Path position : travDesc.traverse(node)) {
// System.out.println("Loop count: " + ++i);
output += position.toString() + ":"
+ (String) position.endNode().getProperty("name")
+ "\n";
// System.out.println(output);
}
System.out.println(output);
}
Output of method 2
(3):Joe
(3)--[KNOWS,6]-->(5):Sara
(3)--[KNOWS,6]-->(5)<--[KNOWS,7]--(6):Peter
(3)--[KNOWS,6]-->(5)<--[KNOWS,7]--(6)<--[KNOWS,5]--(7):Dirk
(3)--[KNOWS,6]-->(5)<--[KNOWS,7]--(6)<--[KNOWS,5]--(7)<--[KNOWS,4]--(4):Lars
(3)--[KNOWS,6]-->(5)<--[KNOWS,7]--(6)<--[KNOWS,5]--(7)<--[KNOWS,4]--(4)<--[KNOWS,3]--(9):Ed
(3)--[KNOWS,6]-->(5)<--[KNOWS,7]--(6)<--[KNOWS,5]--(7)<--[KNOWS,4]--(4)<--[KNOWS,2]--(8):Lisa
Sample data:
create (:Person {name:"Joe"})
,(:Person{name:"Lars"})
,(:Person{name:"Sara"})
,(:Person{name:"Peter"})
,(:Person{name:"Dirk"})
,(:Person{name:"Lisa"})
,(:Person{name:"Ed"})
match (a:Person{name:"Lisa"}), (b:Person{name:"Joe"}) create (a) - [:LIKES] -> (b)
match (a:Person{name:"Lisa"}), (b:Person{name:"Lars"}) create (a) - [:KNOWS] -> (b)
match (a:Person{name:"Ed"}), (b:Person{name:"Lars"}) create (a) - [:KNOWS] -> (b)
match (a:Person{name:"Lars"}), (b:Person{name:"Dirk"}) create (a) - [:KNOWS] -> (b)
match (a:Person{name:"Dirk"}), (b:Person{name:"Peter"}) create (a) - [:KNOWS] -> (b)
match (a:Person{name:"Joe"}), (b:Person{name:"Sara"}) create (a) - [:KNOWS] -> (b)
match (a:Person{name:"Peter"}), (b:Person{name:"Sara"}) create (a) - [:KNOWS] -> (b)
TraversalDescription is a immutable fluent API, quoting form http://neo4j.com/docs/java-reference/current/javadocs/org/neo4j/graphdb/traversal/TraversalDescription.html
A traversal description is immutable and each method which adds or modifies the behavior returns a new instances that includes the new modification, leaving the instance which returns the new instance intact.

What am I missing ! Timetree query not working

MATCH startPath = (event:RESERVATION)-[]->(sd:DAY)<-[:`5`]-(sm:MONTH)<-[:`1`]-(sy:YEAR)<-[:`2016`]-(room:ROOM)
WHERE event.reservationId = 44
RETURN startPath
and
MATCH endPath = (event:RESERVATION)-[]->(ed:DAY)<-[:`6`]-(em:MONTH)<-[:`1`]-(ey:YEAR)<-[:`2016`]-(room:ROOM)
WHERE event.reservationId = 44
RETURN endPath
both return valid paths, but when combined as
MATCH startPath = (event:RESERVATION)-[]->(sd:DAY)<-[:`5`]-(sm:MONTH)<-[:`1`]-(sy:YEAR)<-[:`2016`]-(room:ROOM),
endPath = (event:RESERVATION)-[]->(ed:DAY)<-[:`6`]-(em:MONTH)<-[:`1`]-(ey:YEAR)<-[:`2016`]-(room:ROOM)
WHERE event.reservationId = 44
RETURN startPath, endPath
returns no row !
What am I missing ?
The last query requires both startPath and endPath to end with the same exact ROOM node (since they both use the same room identifier). Your data probably has no such node.

Why do I receive a syntax error when trying to set a property in a CASE statement?

Hello I am using Node4j and I am trying to change de properties of a relationship depending of it´s type , the code that I have is :
Start f=rel(1) MATCH ()-[f]->()
SET f.distancia=256
return CASE f
WHEN rel(f)='FERROCARRIL'
THEN SET f.tiempo=f.distancia/150*60, f.precio=f.distancia*0.23
WHEN rel(f)='AVION'
THEN SET f.tiempo=f.distancia/250*60, f.precio=f.distancia*0.6
WHEN rel(f)='BUS'
THEN SET f.tiempo=f.distancia/110*60, f.precio=f.distancia*0.25
ELSE
SET f.tiempo=f.distancia/100*60, f.precio=f.distancia*0.28
END
I also try putting in the case rel(f) instead of f but i obtained the same result.
It returns an invalid syntax error, how I can do this ?
PS: I need to obtain f by the id of the relationship
It doesn't work because you can't set values in a CASE statement. To make it work you have to set the values in a FOREACH statement. So, in your CASE statement you can set an empty array for types that do not match and set a single item array for the one type that does match.
MATCH ()-[f]->()
WHERE id(f) = 1
SET f.distancia=256
WITH f
, CASE type(f)
WHEN 'FERROCARRIL'
THEN [[1],[],[],[]]
WHEN 'AVION'
THEN [[],[1],[],[]]
WHEN 'BUS'
THEN [[],[],[1],[]]
ELSE
[[],[],[],[1]]
END as type_rel
FOREACH( x in type_rel[0] | SET f.tiempo=f.distancia/150*60, f.precio=f.distancia*0.23 )
FOREACH( x in type_rel[1] | SET f.tiempo=f.distancia/250*60, f.precio=f.distancia*0.6 )
FOREACH( x in type_rel[2] | SET f.tiempo=f.distancia/110*60, f.precio=f.distancia*0.25 )
FOREACH( x in type_rel[3] | SET f.tiempo=f.distancia/100*60, f.precio=f.distancia*0.28 )
RETURN type_rel, f
An alternate cleaner approach would be something like this...
MATCH ()-[f]->()
WHERE id(f) = 1
SET f.distancia=256
WITH f
, CASE type(f)
WHEN 'FERROCARRIL'
THEN [150, 0.23]
WHEN 'AVION'
THEN [250, 0.6]
WHEN 'BUS'
THEN [110, 0.25]
ELSE
[100, 0.28]
END as factors
SET f.tiempo=f.distancia/ factors[0] * 60, f.precio= f.distancia * factors[1]
RETURN f

Total sum from a set (logic)

I have a logic problem for an iOS app but I don't want to solve it using brute-force.
I have a set of integers, the values are not unique:
[3,4,1,7,1,2,5,6,3,4........]
How can I get a subset from it with these 3 conditions:
I can only pick a defined amount of values.
The sum of the picked elements are equal to a value.
The selection must be random, so if there's more than one solution to the value, it will not always return the same.
Thanks in advance!
This is the subset sum problem, it is a known NP-Complete problem, and thus there is no known efficient (polynomial) solution to it.
However, if you are dealing with only relatively low integers - there is a pseudo polynomial time solution using Dynamic Programming.
The idea is to build a matrix bottom-up that follows the next recursive formulas:
D(x,i) = false x<0
D(0,i) = true
D(x,0) = false x != 0
D(x,i) = D(x,i-1) OR D(x-arr[i],i-1)
The idea is to mimic an exhaustive search - at each point you "guess" if the element is chosen or not.
To get the actual subset, you need to trace back your matrix. You iterate from D(SUM,n), (assuming the value is true) - you do the following (after the matrix is already filled up):
if D(x-arr[i-1],i-1) == true:
add arr[i] to the set
modify x <- x - arr[i-1]
modify i <- i-1
else // that means D(x,i-1) must be true
just modify i <- i-1
To get a random subset at each time, if both D(x-arr[i-1],i-1) == true AND D(x,i-1) == true choose randomly which course of action to take.
Python Code (If you don't know python read it as pseudo-code, it is very easy to follow).
arr = [1,2,4,5]
n = len(arr)
SUM = 6
#pre processing:
D = [[True] * (n+1)]
for x in range(1,SUM+1):
D.append([False]*(n+1))
#DP solution to populate D:
for x in range(1,SUM+1):
for i in range(1,n+1):
D[x][i] = D[x][i-1]
if x >= arr[i-1]:
D[x][i] = D[x][i] or D[x-arr[i-1]][i-1]
print D
#get a random solution:
if D[SUM][n] == False:
print 'no solution'
else:
sol = []
x = SUM
i = n
while x != 0:
possibleVals = []
if D[x][i-1] == True:
possibleVals.append(x)
if x >= arr[i-1] and D[x-arr[i-1]][i-1] == True:
possibleVals.append(x-arr[i-1])
#by here possibleVals contains 1/2 solutions, depending on how many choices we have.
#chose randomly one of them
from random import randint
r = possibleVals[randint(0,len(possibleVals)-1)]
#if decided to add element:
if r != x:
sol.append(x-r)
#modify i and x accordingly
x = r
i = i-1
print sol
P.S.
The above give you random choice, but NOT with uniform distribution of the permutations.
To achieve uniform distribution, you need to count the number of possible choices to build each number.
The formulas will be:
D(x,i) = 0 x<0
D(0,i) = 1
D(x,0) = 0 x != 0
D(x,i) = D(x,i-1) + D(x-arr[i],i-1)
And when generating the permutation, you do the same logic, but you decide to add the element i in probability D(x-arr[i],i-1) / D(x,i)

Detailed distance between words

How would I go about displaying detailed distance between words.
For example, the output of the program could be:
Words are "car" and "cure":
Replace "a" with "u".
Add "e".
The Levenshtein distance does not fulfill my needs (I think).
Try the following. The algorithm is roughly following Wikipedia (Levenshtein distance). The language used below is ruby
Use as an example, the case of changing s into t as follows:
s = 'Sunday'
t = 'Saturday'
First, s and t are turned into arrays, and an empty string is inserted at the beginning. m will eventually be the matrix used in the argorithm.
s = ['', *s.split('')]
t = ['', *t.split('')]
m = Array.new(s.length){[]}
m here, however, is different from the matrix given if the algorithm in wikipedia for the fact that each cell includes not only the Levenshtein distance, but also the (non-)operation (starting, doing nothing, deletion, insertion, or substitution) that was used to get to that cell from an adjacent (left, up, or upper-left) cell. It may also include a string describing the parameters of the operation. That is, the format of each cell is:
[Levenshtein distance, operation(, string)]
Here is the main routine. It fills in the cells of m following the algorithm:
s.each_with_index{|a, i| t.each_with_index{|b, j|
m[i][j] =
if i.zero?
[j, "started"]
elsif j.zero?
[i, "started"]
elsif a == b
[m[i-1][j-1][0], "did nothing"]
else
del, ins, subs = m[i-1][j][0], m[i][j-1][0], m[i-1][j-1][0]
case [del, ins, subs].min
when del
[del+1, "deleted", "'#{a}' at position #{i-1}"]
when ins
[ins+1, "inserted", "'#{b}' at position #{j-1}"]
when subs
[subs+1, "substituted", "'#{a}' at position #{i-1} with '#{b}'"]
end
end
}}
Now, we set i, j to the bottom-right corner of m and follow the steps backwards as we unshift the contents of the cell into an array called steps, until we reach the start.
i, j = s.length-1, t.length-1
steps = []
loop do
case m[i][j][1]
when "started"
break
when "did nothing", "substituted"
steps.unshift(m[i-=1][j-=1])
when "deleted"
steps.unshift(m[i-=1][j])
when "inserted"
steps.unshift(m[i][j-=1])
end
end
Then we print the operation and the string of each step unless that is a non-operation.
steps.each do |d, op, str=''|
puts "#{op} #{str}" unless op == "did nothing" or op == "started"
end
With this particular example, it will output:
inserted 'a' at position 1
inserted 't' at position 2
substituted 'n' at position 2 with 'r'
class Solution:
def solve(self, text, word0, word1):
word_list = text.split()
ans = len(word_list)
L = None
for R in range(len(word_list)):
if word_list[R] == word0 or word_list[R] == word1:
if L is not None and word_list[R] != word_list[L]:
ans = min(ans, R - L - 1)
L = R
return -1 if ans == len(word_list) else ans
ob = Solution()
text = "cat dog abcd dog cat cat abcd dog wxyz"
word0 = "abcd"
word1 = "wxyz"
print(ob.solve(text, word0, word1))

Resources