How to query Neo4j from Python: a quick introduction to Neo4j Driver and Cypher. | Towards Data Science

Neo4j is a graph database management system.
According to its website:
Neo4j is a native graph database, built from the ground up to leverage not only data but also data relationships. Neo4j connects data as it’s stored, enabling queries never before imagined, at speeds never thought possible.
In this article, we will provide a brief tutorial on using Neo4j from Python.
You can skip this section if an instance of the graph DBMS is already installed and configured. In order to install Neo4j Desktop, follow the step-by-step guide on the official website. :) Once correctly installed, you should have a browser window like in the picture below.
You could have some predefined sample projects already created. For this tutorial, we are going to create and use a brand new project. Just click on the New button and choose a name for our project!
Initially, the project is empty. We can start by adding a new database.
Once created the database, start it and open it. You should see a window like in the picture below where there is the information to use to connect to the database from a client. In our case, the URI is
bolt://localhost:7687
From the left vertical bar, you can enter the users administration menù to create a new user.
In this example, we are going to create an admin user.
Username: supermanPassword: pizzaRole: admin
We can check the creation of the new user by selecting the user list from the left vertical bar.
Now, we are ready from the server side! Let’s move to Python!
Install the package neo4j in our Python environment:
pip install neo4j
This is the officially supported driver so we stick to it in this tutorial. However, there are other well-designed community drivers you can consider for future projects. Once installed neo4j package, you can try to import it in Python.
from neo4j import __version__ as neo4j_versionprint(neo4j_version)
If everything is working, you should receive as output the version of neo4j package (4.0.1 in this case).
Now, we are ready to query the graph database!
Firstly, we need to define a connection class to connect to the graph database.
from neo4j import GraphDatabaseclass Neo4jConnection:        def __init__(self, uri, user, pwd):        self.__uri = uri        self.__user = user        self.__pwd = pwd        self.__driver = None        try:            self.__driver = GraphDatabase.driver(self.__uri, auth=(self.__user, self.__pwd))        except Exception as e:            print("Failed to create the driver:", e)            def close(self):        if self.__driver is not None:            self.__driver.close()            def query(self, query, db=None):        assert self.__driver is not None, "Driver not initialized!"        session = None        response = None        try:             session = self.__driver.session(database=db) if db is not None else self.__driver.session()             response = list(session.run(query))        except Exception as e:            print("Query failed:", e)        finally:             if session is not None:                session.close()        return response
The class above requires the url, the username and the password during the initialization. In the query method, the query string should be written in Neo4j’s graph query language: Cypher. For more details, check the Cypher Refcard.
Let’s create an instance of connection with the parameters defined before.
conn = Neo4jConnection(uri="bolt://localhost:7687", user="superman", pwd="pizza")
Then, we can make our first query! Let’s create a database called coradb.
conn.query("CREATE OR REPLACE DATABASE coradb")
We can feed our database with the data from the CORA dataset.
The Cora dataset consists of 2708 scientific publications classified into one of seven classes. The citation network consists of 5429 links. Each publication in the dataset is described by a 0/1-valued word vector indicating the absence/presence of the corresponding word from the dictionary. The dictionary consists of 1433 unique words.
Let’s create the citation graph from CSV files. We read the CSV file containing nodes information line by line and add each node to the graph with label Paper and properties id and class (of the paper).
query_string = '''USING PERIODIC COMMIT 500LOAD CSV WITH HEADERS FROM'https://raw.githubusercontent.com/ngshya/datasets/master/cora/cora_content.csv'AS line FIELDTERMINATOR ','CREATE (:Paper {id: line.paper_id, class: line.label})'''conn.query(query_string, db='coradb')
We do the same with edges information (notice the “arrow” syntax in defining the edge).
query_string = '''USING PERIODIC COMMIT 500LOAD CSV WITH HEADERS FROM'https://raw.githubusercontent.com/ngshya/datasets/master/cora/cora_cites.csv'AS line FIELDTERMINATOR ','MATCH (citing_paper:Paper {id: line.citing_paper_id}),(cited_paper:Paper {id: line.cited_paper_id})CREATE (citing_paper)-[:CITES]->(cited_paper)'''conn.query(query_string, db='coradb')
Finally, we are ready to make queries on our citation network! For example, we can ask which are the classes of papers in the network:
query_string = '''MATCH (p:Paper)RETURN DISTINCT p.classORDER BY p.class'''conn.query(query_string, db='coradb')
or the list of most cited papers:
query_string = '''MATCH ()-->(p:Paper) RETURN id(p), count(*) as indegree ORDER BY indegree DESC LIMIT 10'''conn.query(query_string, db='coradb')
You can use any syntax on Cypher Refcard, the only limit is your fantasy!
In addition to Cypher queries, you can also run graph algorithms in Neo4j, for example: path finding, centralities computation, community detection, etc. To this end, we need to activate Neo4j Graph Data Science Library. We need to come back to Neo4j Browser and enter the configuration menù (3 dots) of Graph Database.
Under the tab Plugins, install Graph Data Science Library and restart. Before computing any measure, we need to create a graph.
query_string = '''CALL gds.graph.create(  'coraGraph',  'Paper',  'CITES')'''conn.query(query_string, db='coradb')
Now, we can compute the PageRank and the Betweenness of each node of the graph and save them in properties.
query_string = '''CALL gds.pageRank.write('coraGraph', {  writeProperty: 'pagerank'})YIELD nodePropertiesWritten, ranIterations'''conn.query(query_string, db='coradb')query_string = '''CALL gds.betweenness.write('coraGraph', {   writeProperty: 'betweenness' })YIELD minimumScore, maximumScore, scoreSum, nodePropertiesWritten'''conn.query(query_string, db='coradb')
The complete list of implemented algorithms and their syntax can be found here.
If we query the graph right now, we can find out that each node has two more properties (pagerank and betweenness). We can transform the output in a dataframe and continue our analysis from there.
from pandas import DataFramequery_string = '''MATCH (p:Paper)RETURN DISTINCT p.id, p.class, p.pagerank, p.betweenness'''dtf_data = DataFrame([dict(_) for _ in conn.query(query_string, db='coradb')])dtf_data.sample(10)
The code above produces the following output:
If we have finished with the queries, we can close the connection.
conn.close()
Contacts: LinkedIn | Twitter