Reputation: 55
I need help with creating relations between countries in neo4j using python. I have a code, but in neo4j browser it doesn't create relations.
from neo4j import GraphDatabase
driver = GraphDatabase.driver("neo4j://localhost:7687",
auth=("neo4j", "test"))
def create_country(tx, name,continent,population_mln,govrm_system,bcountry):
tx.run("CREATE (a:Country {name: $name,continent: $continent,population_mln: $population_mln,govrm_system:$govrm_system,bcountry: $bcountry})",
name=name,continent=continent,population_mln=population_mln,govrm_system=govrm_system,bcountry=bcountry)
with driver.session() as session:
session.execute_write(create_country, "russia","Asia",143,"terrorist state",["Kazakhstan","Lithuania","Finland","China","Japan"])
session.execute_write(create_country, "India","Asia",1393,"Parliamentary Republic","China")
session.execute_write(create_country, "China","Asia",1412,"One-party state",["India","russia","Philipines","Japan"])
session.execute_write(create_country, "Poland","Europe",37,"Parliamentary Republic",["Lithuania","Germany","Czechia"])
session.execute_write(create_country, "Kazakhstan","Asia",19,"Presidential system Republic","russia")
session.execute_write(create_country, "Lithuania","Europe",2.7,"Parliamentary Republic",["russia","Poland"])
session.execute_write(create_country, "Finland","Europe",5.5,"Parliamentary Republic","russia")
session.execute_write(create_country, "Philipines","Asia",111,"Parliamentary Republic",["Japan","China"])
session.execute_write(create_country, "Japan","Asia",125,"Constitutional Monarchy",["Philipines","China","russia"])
session.execute_write(create_country, "Germany","Europoe",83,"Parliamentary Republic",["Czechia","Austria","Poland"])
session.execute_write(create_country, "Czechia","Europoe",10,"Parliamentary Republic",["Austria","Poland","Germany"])
session.execute_write(create_country, "Austria","Europoe",9,"Parliamentary Republic",["Czechia","Germany"])
def create_bordering_country(tx, name, bcountry):
tx.run("FOREACH (n IN a.bcountry | MERGE (bcountry:Country {name: n}) MERGE (a)-[:HAS_BORDER_WITH]-(bcountry))")
It should look like this:
What I get in neo4j:
I also tried to do like this, but then I get duplicates of countries:
def create_bordering_country(tx, name, bcountry):
tx.run("MATCH (a:Country) WHERE a.name = $name "
"MERGE (a)-[:HAS_BORDER_WITH]-(:Country {name: $bcountry}) RETURN DISTINCT a.name",
name=name, bcountry=bcountry)
session.execute_write(create_bordering_country, "russia", "China")
session.execute_write(create_bordering_country, "India", "China")
session.execute_write(create_bordering_country, "russia", "Kazakhstan")
session.execute_write(create_bordering_country, "russia", "Lithuania")
session.execute_write(create_bordering_country, "russia", "Finland")
session.execute_write(create_bordering_country, "Poland", "Lithuania")
session.execute_write(create_bordering_country, "China", "Japan")
session.execute_write(create_bordering_country, "Russia", "Japan")
session.execute_write(create_bordering_country, "Philipines", "Japan")
session.execute_write(create_bordering_country, "Philipines", "China")
session.execute_write(create_bordering_country, "Germany", "Poland")
session.execute_write(create_bordering_country, "Austria", "Poland")
session.execute_write(create_bordering_country, "Czechia", "Poland")
session.execute_write(create_bordering_country, "Czechia", "Austria")
session.execute_write(create_bordering_country, "Czechia", "Germany")
session.execute_write(create_bordering_country, "Germany", "Austria")
Upvotes: 1
Views: 57
Reputation: 881
In your first attempt, it doesn't look like you ever called the create_bordering_country function. I would recommend this approach:
import pandas as pd
from neo4j import GraphDatabase
driver = GraphDatabase.driver("neo4j://localhost:7687",
auth=("neo4j", "test"))
country_df = pd.DataFrame([
["russia","Asia",143,"terrorist state",["Kazakhstan","Lithuania","Finland","China","Japan"]],
["India","Asia",1393,"Parliamentary Republic",["China"]],
["China","Asia",1412,"One-party state", ["India","russia","Philipines","Japan"]],
["Poland","Europe",37,"Parliamentary Republic",["Lithuania","Germany","Czechia"]],
["Kazakhstan","Asia",19,"Presidential system Republic", ["russia"]],
["Lithuania","Europe",2.7,"Parliamentary Republic",["russia","Poland"]],
["Finland","Europe",5.5,"Parliamentary Republic",["russia"]],
["Philipines","Asia",111,"Parliamentary Republic",["Japan","China"]],
["Japan","Asia",125,"Constitutional Monarchy",["Philipines","China","russia"]],
["Germany","Europoe",83,"Parliamentary Republic",["Czechia","Austria","Poland"]],
["Czechia","Europoe",10,"Parliamentary Republic",["Austria","Poland","Germany"]],
["Austria","Europoe",9,"Parliamentary Republic",["Czechia","Germany"]]],
columns=['name', 'continent', 'populationMillion', 'governmentSystem', 'neighboringCountries'])
node_dicts = country_df[['name', 'continent', 'populationMillion', 'governmentSystem']].to_dict("records")
rel_dicts = country_df[['name', 'neighboringCountries']].to_dict("records")
def create_countries(tx, node_dicts):
result = tx.run("""UNWIND $nodeDicts as nodeDict
MERGE (c:Country {name: nodeDict['name']})
SET c.continent = nodeDict['continent'] ,
c.populationMillion = nodeDict['populationMillion'],
c.governmentSystem = nodeDict['governmentSystem']""",
{"nodeDicts": node_dicts})
summary = result.consume()
return summary.counters
def create_neighbor_relationships(tx, rel_dicts):
result = tx.run("""UNWIND $relDicts as relDict
MATCH (c:Country {name: relDict['name']})
UNWIND relDict['neighboringCountries'] as neighbor
MATCH (n:Country {name: neighbor})
MERGE (c)-[:HAS_BORDER_WITH]->(n)""",
{"relDicts": rel_dicts})
summary = result.consume()
return summary.counters
with driver.session() as session:
node_results = session.write_transaction(create_countries, node_dicts)
print(node_results)
rel_results = session.write_transaction(create_neighbor_relationships, rel_dicts)
print(rel_results)
I would also recommend creating an index on the name property for the Country nodes.
Upvotes: 0
Reputation: 12704
You are getting duplicates because merge will create more bcountry even if it exists already. Please use below new query.
Function: create_bordering_country
Old code:
MATCH (a:Country) WHERE a.name = $name
MERGE (a)-[:HAS_BORDER_WITH]-(:Country {name: $bcountry})
RETURN DISTINCT a.name
New code:
MERGE (a:Country) WHERE a.name = $name
MERGE (b:Country) WHERE b.name = $bcountry
MERGE (a)-[:HAS_BORDER_WITH]-(b)
RETURN a.name
Upvotes: 1