Bidirectional Data modeling issue in neo4j - neo4j

I have two nodes, A and B,
A talks to B and B talks to A, (A)-[:talksTo]-(B)
A has a sentiment value towards B, and B has a sentiment value towards A.
So there is the problem, I need A to B relationship to store a value that the B to A relationship will also want to store (same key).
So I will try to do queries such as, MATCH (A:person)-[:talksTo]-(B:person) where A.sentiment < -2 return A;
So here A's sentiment toward B will be different the B's sentiment toward A, thus the needed separation.
I have tried to make unique key names to specify direction - but that makes queries difficult unless I can query with a wild card ex: ... where A.Asentiment < -2 would be queried as ... where A.*sentiment < -2
Another way I can think of to do this is make two different graphs, 1) A talks to B graph and B talks to A graph... but this would make queries tricky as I may get back more then one node for single node queries OR if I have to update a single node key:value to something else. I would prefer to have one node name per person.
Any ideas?

I don't know that this is a solution, but I don't think I understand enough so it might be a foil for better understanding:
MATCH (A:Person)-[dir1:talksTo]->(B:Person), (A)<-[dir2:talksTo]-(B)
WHERE dir1.sentiment < 2
RETURN A, B

Related

Define relationship dependent on another relationship in conceptual-model

I need to help to define a relationship in conceptual model for database. I'm doing it in PowerDesiner. I have 3 entities (let's call them A, B and C).
A doesn't have to have B, if A has B then only once.
B has to have at least one A.
B may have C, but doesn't have to.
C have precisely two B.
C has at least one A.
C can have A only if A is part of B, which is in relationship with C (one of the two B to C).
A may have C, but doesn't have to.
It's too complicated for me, I had an idea, but it turned out to be completely wrong. It's only a part of project, but the rest don't affect those 3. I need to do those limits on conceptual level, which is exactly my problem.
My first and propably the best idea was this http://i.snag.gy/Ofdze.jpg but it doesn't include the condition that C can have A only if A is part of B, which is in relationship with C (one of the two B to C)
Then I came up with this http://i.snag.gy/gKNQ9.jpg but as the solution before I think that it doesn't contains the same condition, even worse seems to be really messed up solution.
Ok,
for clarity I will refer to your relation conditions to the # of line you have described it, so Row_1-2 will refer to statements in 1st and 2nd row of your question.
Please, pay attention, there is a logical error in your 5th and 6th statements.
You say C has at least one A and C can have A only if.., the two are not possible toghether.
I will skip the 5th and keep the 6th in my answer.
Let's see, first of all add the relation between A and B
Then select the relation and right click it and select Change to Entity,
you will get:
Pay attention this new entity identifies the relation between A and B, you will need it to fulfill your 6th statement.
Now add relations between C and B and between C and A (through Rel_A-B)
Note, I have adjusted cardinalities in relation between B and C (2,2)

Ideas for an algorithm to randomly place interrelated nodes

I apologise for the title, I realise it isn't especially descriptive. I'll try to describe my problem in greater detail.
I have a set of "nodes", for sake of example we'll title them A, B, C, D, and E. These nodes are unique from one another in the sense that they have are "related" to each other, though only to specific nodes. In my real implantation, there could be thousands of nodes and I would like to develop an algorithm which could place them appropriately, regardless of their quantity.
We'll pretend the associations are as follows:
A: B, D
B: A, C, D
C: E
D: A, B
E: C
This format means that A is related to B and D, etc.
My goal is to display these relationships on a 2D plane by drawing each node as a circle, and drawing a line between them. I would like to display them in a "web" type fashion, meaning that the nodes do not overlap whatsoever, and the distance between related nodes is minimized. I would like for the diagram to suggest that by starting at A, for instance, one could travel next to B, then to C, and finally to E.
In a case such as B's, where it itself is related to C while C is not related to B, there does not have to be a distinction to suggest that. That is to say, showing that A:B and B:A can be the same as saying that B:C, despite C is not related to B.
I hope I have made myself clear in what I would like to accomplish. I don't think I'll have very much trouble coding the actual algorithm, I just for the life of me can't think of a way logical way to approach the problem.
Any suggestions at all are greatly appreciated, I don't need pseudocode or step by step instructions, just some advice from some more seasoned programmers who may be able to look at the problem from a different perspective.
Thanks!
Try searching for "force directed graph drawing".
The basic idea is as follows:
Initialize node positions randomly (putting them with equal distances on a circle turned out to be good)
Apply Forces between the nodes:
Nodes push off each other
if they are related, they are additionally pulled towards each other
Repeat step 2 until you have a nice layout.
There is a live example at http://getspringy.com/

How to query recommendation using Cypher

I'm trying to query Book nodes for recommendation by Cypher.
I want to recommend A:Book and C:Book for A:User.
i'm sorry I need some graph to explain this question, but I could't up graph image because my lepletion lacks for upload function.
I wrote query below.
match (u1:User{uid:'1003'})-->(o1:Order)-->(b1:Book)<--(o2:Order)
<--(u2:User)-->(o3:Order)-->(b2:Book)
return b2
This query return all Books(A,B,C,D) dispite cypher's Uniqueness.
I expect to only return A:Book and C:Book.
Is this behavior Neo4j' specification?
How do I get expected return? Thanks, everyone.
environment:
Neo4j ver.v2.0.0-RC1
Using Neo4j Server with REST API
Without the sample graph its hard to say why you get something back when you expected something else. You can share a sample graph by including a create statement that would generate said graph, or by creating it in Neo4j console and putting the link in your question. Here is an example of the latter: console.neo4j.org/r/fnnz6b
In the meantime, you probably want to declare the type of the relationships in your pattern. If a :User has more than one type of outgoing relationships you will be excluding those other paths based on the labels of the nodes on the other end, which is much less efficient than to only traverse the right relationships to begin with.
To my mind its not clear whether (u:User)-->(o:Order)-->(b:Book) means that a user has one or more orders, and each order consists of one or more books; or if it means only that a user ordered a book. If you can share a sample, hopefully that will be clear too.
Edit:
Great, so looking at the graph: You get B and D back because others who bought B also bought D, and others who bought D also bought B, which is your criterion for recommendation. You can add a filter in the WHERE clause to exclude those books that the user has already bought, something like
WHERE NOT (u1)-[:BUY]->()-[:CONTAINS]->(b2)
This will give you A, C, C back, since there are two matching paths to C. It's probably not important to get two result items for C, so you can either limit the return to give only distinct values
RETURN DISTINCT(b2)
or group the return values by counting the matching paths for each result as a 'recommendation score'
RETURN b2, COUNT(b2) as score
Also, if each order only [CONTAINS] one book, you could try modelling without order, just (:User)-[:BOUGHT]->(:Book).

neo4j complex pattern searching

I'm new to NEO4J and I need help on a specific problem. Or an answer if it's even possible.
SETUP:
We have 2 distinct type of nodes: users (A,B,C,D) and Products (1,2,3,4,5,6,7,8)
Next we have 2 distinct type of relationships between users and products where a users WANTS a Product and where a product is OWNED BY a user.
1,2 is owned by A
3,4 is owned by B
5,6 is owned by C
7,8 is owned by D
Now
B wants 1
C wants 3
D wants 5
So for now, I have no problems and I created the graph data with no difficulty. My questions starts here. We have a circle, when A wants product 8.
A-[:WANTS]->8-[:OWNEDBY]->D-[:WANTS]->5-[:OWNEDBY]->C-[:WANTS]->3-[:OWNEDBY]->B-[:WANTS]->1-[:OWNEDBY]->A
So we have a distinct pattern, U-[:WANTS]->P-[:OWNEDBY]->U
Now what I want to do is to find the paths toward the start node (initiating user that wants a product) following that pattern.
How do I define this using Cypher? Or do I need another way?
Thanks upfront.
i got a feeling this can be hacked with reduce and counting every even (every second) relationship:
MATCH p=A-[:OWNEDBY|WANTS*..20]->X
WITH r in relationships(p)
RETURN type(r),count(r) as cnt,
WHERE cnt=10;
or maybe counting all paths where the number of rels is even:
MATCH p=A-[:OWNEDBY|WANTS*..]->X
RETURN p,reduce(total, r in relationships(p): total + 1) as tt
WHERE tt%2=0;
but you graph must have the strict pattern, where all incoming relationship from the set of ownedby and wants must be different from all outgoin relationships from the same set. in other words, this pattern can not exist: A-[:WANTS]->B-[:WANTS]->C or A-[:OWNEDBY]->B-[:OWNEDBY]->C
the query is probably wrong in syntax, but the logic can be implemented in cypher whn you will play more with it.
or use gremlin, I think I saw somewhere a gremlin query, where you could define a pattern and than loop n-times via that pattern further till the end node.
I've played around with this and created http://console.neo4j.org/?id=qq9v1 showing the sample graph. I've found the following cypher statement solving the issue:
start a=node(1)
match p=( a-[:WANTS]->()-[:WANTS|OWNEDBY*]-()-[:OWNEDBY]->a )
return p
order by length(p) desc
limit 1
There is just one glitch: the intermediate part [:WANTS|OWNEDBY*] does not mandate alternating WANT and OWNEDBY chains. As #ulkas stated, this should not be an issue if you take care during data modelling.
You might also look into http://api.neo4j.org/current/org/neo4j/graphalgo/GraphAlgoFactory.html to apply graph algorithms from Java code. You might use unmangaged extensions to provide REST access to that.

Neo4j - data modeling

I am building some test application with Neo4j. I want to model small social network and try to find:
All friends of user X
Friends of user's X friends, who likes beer
I stuck with modeling "know" relation. Let's take 3 users A, B and C. Is it enough to define only one relation between, them ex.
A knows B
B knows C
or I have to make 'bidirectional' relations and explicitly provide that
A knows B so B knows A
B knows C so C knows B
it will increase the number of relations, but maybe it is needed.
The same question is related to favorite drink.
A likes beer
should I also define?
beer is liked by A
If you want to be able to differentiate between a knowing b and b knowing a, then you need to have two relationships. Otherwise, at query time, you can easily get both by omitting the direction.
Similarly, with beer being liked, you really only need to define one direction.
For a real example: The facebook/linkedin model where connections are mutual only needs one direction/relationship, but the twitter model where one person can follow another (but the other person doesn't have to follow them back), you'd need two relationships--one for each direction.
Update with some query examples:
CREATE
(joe {name:"Joe"}),
(jim {name:"Jim"}),
(bob {name:"Bob"}),
(beer {name:"Beer"}),
joe-[:friends_with]-jim,
joe-[:friends_with]-bob,
bob-[:likes]->beer;
For the friends:
START person=node:node_auto_index(name="Joe")
MATCH (person)-[:friends_with]-(friend)
RETURN person, friend;
And the friends who like beer:
START person=node:node_auto_index(name="Joe"), beer=node:node_auto_index(name="Beer")
MATCH (person)-[:friends_with]-(friend)-[:likes]->(beer)
RETURN person, friend, beer;

Resources