how to create multiple relationships in a single cypher statement - neo4j

I must create a set of relationships, all having the same source and type, like in the following sample:
create (_1)-[:`typ`]->(:`x` {`name`:"Mark"})
create (_1)-[:`typ`]->(:`y` {`name`:"Jane"})
create (_1)-[:`typ`]->(:`z` {`name`:"John"})
...
I'd like to have a shorten way to write those statements, like following attempt?
create (_1)-[:`typ`]->[(:`x` {`name`:"Mark"}),
(:`y` {`name`:"Jane"}),
(:`z` {`name`:"John"})]
Any idea?
Thank you in advance.
Paolo

You could do it in a performant and easy way by this pattern:
{batch: [
{from:"alice#example.com",to:"bob#example.com",properties:{since:2012}},
{from:"alice#example.com",to:"charlie#example.com",properties:{since:2016}}]}
UNWIND {batch} as row
MATCH (from:Label {row.from})
MATCH (to:Label {row.to})
CREATE/MERGE (from)-[rel:KNOWS]->(to)
(ON CREATE) SET rel += row.properties
Taken with thanks from 5 Tips & Tricks for Fast Batched Updates of Graph Structures with Neo4j and Cypher by #MichaelHunger.

Related

Create doesn't make all nodes and relationships appear

I just downloaded and installed Neo4J. Now I'm working with a simple csv that is looking like that:
So first I'm using this to merge the nodes for that file:
LOAD CSV WITH HEADERS FROM 'file:///Athletes.csv' AS line
MERGE(Rank:rank{rang: line.Rank})
MERGE(Name:name{nom: line.Name})
MERGE(Sport:sport{sport: line.Sport})
MERGE(Nation:nation{pays: line.Nation})
MERGE(Gender: gender{genre: line.Gender})
MERGE(BirthDate:birthDate{dateDeNaissance: line.BirthDate})
MERGE(BirthPlace: birthplace{lieuDeNaissance: line.BirthPlace})
MERGE(Height: height{taille: line.Height})
MERGE(Pay: pay{salaire: line.Pay})
and this to create some constraint for that file:
CREATE CONSTRAINT ON(name:Name) ASSERT name.nom IS UNIQUE
CREATE CONSTRAINT ON(rank:Rank) ASSERT rank.rang IS UNIQUE
Then I want to display to which country the athletes live to. For that I use:
Create(name)-[:WORK_AT]->(nation)
But I have have that appear:
I would like to know why I have that please.
I thank in advance anyone that takes time to help me.
Several issues come to mind:
If your CREATE clause is part of your first query: since the CREATE clause uses the variable names name and nation, and your MERGE clauses use Name and Nation (which have different casing) -- the CREATE clause would just create new nodes instead of using the Name and Nation nodes.
If your CREATE clause is NOT part of your first query: your CREATE clause would just create new nodes (since variable names, even assuming they had the same casing, are local to a query and are not stored in the DB).
Solution: You can add this clause to the end of the first query:
CREATE (Name)-[:WORK_AT]->(Nation)
Yes, Agree with #cybersam, it's the case sensitive issue of 'name' and 'nation' variables.
My suggesttion:
MERGE (Name)-[:WORK_AT]->(Nation)
I see that you're using MERGE for nodes, so just in case any values of Name or Nation duplicated, you should use MERGE instead of CREATE.

Neo4j relationship writing process

I am using Neo4j graph to create graph database. using load csv command to create relationship. It takes 2hours to load 1 million data rows relationship into any relationship. Is there any other way to create relationship faster?
CREATE is faster than MERGE.And using MERGE or MATCH can result 'Eager Operation'. Please go through this blog for more reference.
As a work around you can try the below query.
You can use WITH in the query for avoinding cartisian product and whole 'row' to pass down. Try adding index to "indexed_date" and try the below query.
USING PERIODIC COMMIT LOAD CSV WITH HEADERS FROM "file:///raw.csv" AS row
MATCH (tweet_id:tweet_id {name: row.tweet_id}) with tweet_id
MATCH (indexed_date:indexed_date {name: row.indexed_date}) with indexed_date,tweet_id
CREATE (indexed_date)-[date_i_tweet:date_i_tweet]->(tweet_id);
Hope this helps
For your query, you should have :
a unique constraint on tweet_id : CREATE CONSTRAINT ON (n:tweet_id) ASSETS n.tweet_id IS UNIQUE
a unique constraint or an indexed_date : CREATE CONSTRAINT ON (n:indexed_date) ASSETS n.indexed_date IS UNIQUE
Cheers

How to force Neo4j to use 2 indexes?

I mean, if I have two indexes:
CREATE INDEX ON :labelA(idA)
CREATE INDEX ON :labelB(idB)
And I do the following query:
MATCH (n:labelA {idA: valA})
MATCH (n:labelB {idB: valB})
CREATE (n)-[:Rel]->(B)
Does neo4j just use one of the indexes? If does, How do I force neo4j to use the 2 indexes?.
Thanks in advance.
Currently Neo will only use a maximum of one index to determine where to start walking the graph as part of query resolution. This is likely to change in the future. You can give Neo hints on which of the 2 or more indexes to use via USE INDEX but you can't get it to use more than one at this point.
You could check if indexes are being used to find the nodes by prepending your query with PROFILE.
You could throw the query optimizer a hint something like this...
MATCH (a:labelA {idA: valA}), (b:labelB {idB: valB})
USING INDEX a:LabelA(idA)
USING INDEX b:LabelB(idB)
CREATE (a)-[:Rel]->(b)

Parse a big file and populate a Neo4j database

I am working on a Ruby on Rails project that will read and parse somewhat big text file (around 100k lines) and build Neo4j nodes (I am using Neography) with that data.
This is the Neo4j related fraction of the code I wrote:
d= Neography::Rest.new.execute_query("MATCH (n:`Label`) WHERE (n.`name`='#{id}') RETURN n")
d= Neography::Node.load(d, #neo)
p= Neography::Rest.new.create_node("name" => "#{id}")
Neography::Rest.new.add_label(p, "LabelSample")
d=Neography::Rest.new.get_node(d)
Neography::Rest.new.create_relationship("belongs_to", p, d)
so, what I want to do is: a search in the already populated db for the node with the same "name" field as the parsed data, create a new node for this data and finally create a relationship between the two of them.
Obiously this code simply takes way too much time to be executed.
So I tried with Neography's batch, but I ran into some issues.
p = Neography::Rest.new.batch [:create_node, {"name" => "#{id}"}]
gave me a "undefined method `split' for nil:NilClass" in
id["self"].split('/').last
d=Neography::Rest.new.batch [:get_node, d]
gives me a Neography::UnknownBatchOptionException for get_node
I am not even sure this will save me enough time either.
I also tried different ways to do this, using Batch Import for example, but I couldn't find a way to get the already created node I need from the db.
As you can see I'm kinda new to this so any help will be appreciated.
Thanks in advance.
You might be able to do this with pure cypher (or neography generated cypher). Something like this perhaps:
MATCH (n:Label) WHERE n.name={id}
WITH n
CREATE (p:LabelSample {name: n.name})-[:belongs_to]->n
Not that I'm using CREATE, but if you don't want to create duplicate LabelSample nodes you could do:
MATCH (n:Label) WHERE n.name={id}
WITH n
MERGE (p:LabelSample {name: n.name})
CREATE p-[:belongs_to]->n
Note that I'm using params, which are generally recommended for performance (though this is just one query, so it's not as big of a deal)

How do I use an index that has dots in the name?

I'm just starting to learn the Cypher query language and GraphDb in general. I've created some indexes using the class name of my nodes like:
"com.acme.node.SomeNodeType"
I can't for the life of me figure out how to reference this index in Cypher. I found this thread but using ` didn't work for me.
So I guess I have 2 questions:
Is it possible to use an index with dots in the name?
If so, how do I specify the name in the query?
can you try to query them with '' like
start n = node:`my.index`('name:test') return n
?

Resources