Jack Daniel
Jack Daniel

Reputation: 2611

Neo4j - Iterate for common nodes for a given list of nodes

I have no idea of iterating on list in neo4j. Please some one suggest the idea for the below problem.

Example: I have some nodes in the graph. Then, I will give few(always varying, this is the user input) keywords to search for nodes which are common to this words. In my graph each word is a node.

Ex: Input: [Best sports car]
output: connected nodes for Best are [samsung,porshe,ambassdor,protein,puma]
        connected nodes for sports are [cricket,racing,rugby,puma,porshe]
        connected nodes for car are [porshe,ambassdor,benz,audi]
Common nodes to all words are : [porshe]
Result is : porshe

I don't have any idea of iterating each word and storing the match results. Please some one suggest any idea.

Upvotes: 1

Views: 692

Answers (2)

Christophe Willemsen
Christophe Willemsen

Reputation: 20185

In order to test the following working query, I'll make some assumptions :

  • The words nodes have the label :Word and the name property.
  • The porsche, puma, etc.. nodes have the label :Item and a name property.
  • Item nodes have an outgoing CONNECT relationships to Word nodes

Which will give the following graph :

enter image description here

The query is the following (in order to simulate the given words as parameters, I added a WITH containing the words list in the beginning of the query)

WITH ["car","best","sports"] as words
MATCH (n:Word)<-[:CONNECT]-(i:Item) 
WHERE n.name IN words
WITH i, count(*) as c, words
WHERE c = size(words)
RETURN i

And will return only the porsche Item node.

Logic explanation

The logic of the query, is that if a node matches all given words, there will be 3 patterns to it found in the first MATCH, so the count(*) will have a value of 3 here for the porsche node. This value is compared to the size of the words list.

More explanations

In the WITH statement, there is two expressions : i and count(*).

i is not an aggregate function, so it will act as a grouping key. count(*) is an aggregate function and will run on the i bucket, calculating the aggregate values.

For example, if you want to know how many words each Item is matching you can simply do :

WITH ["car","best","sports"] as words
MATCH (n:Word)<-[:CONNECT]-(i:Item) WHERE n.name IN words
RETURN i.name, count(*)

Which will return this :

enter image description here

You can see that porsche is matching 3 words, which is the size of the given words list, then you can simply compare the 3 from the count aggregation to this size.

In order to fully understand how aggregation works, you can refer to the manual : http://neo4j.com/docs/stable/query-aggregation.html

You can test the query here :

http://console.neo4j.org/r/e6bee0

If you pass the words as parameters, this will then be the corresponding query :

MATCH (n:Word)<-[:CONNECT]-(i:Item) 
WHERE n.name IN {words}
WITH i, count(*) as c
WHERE c = size({words})
RETURN i

assuming {words} is the name of the given query parameter

Upvotes: 3

Dave Bennett
Dave Bennett

Reputation: 11216

Is something like this what you are after?

Start with a collection of words form the requested search.

Match each word against the graph.

Collect the connected words in a list.

with ['Best', 'sports', 'car'] as word_coll
unwind word_coll as word
match (:Word {name: word})--(conn_word:Word)
return word,collect(conn_word)

Upvotes: 1

Related Questions