introduction to py2neo
DESCRIPTION
An introduction to the python library py2neo, used for building applications which use the Neo4j graph database.TRANSCRIPT
![Page 2: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/2.jpg)
Me...
![Page 3: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/3.jpg)
Where does py2neo fit in?
Neo4j
REST Server
(your app)
py2neo
GET /db/data/200 OK
![Page 4: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/4.jpg)
Coming Up...
● Connecting & Creating● Property Containers● Indexes & Uniqueness● Cypher & Geoff● Installation● Future Plans
![Page 5: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/5.jpg)
Connecting & Creating
![Page 6: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/6.jpg)
Default Connections
>>> from py2neo import neo4j
>>> graph_db = neo4j.GraphDatabaseService()
default connection is made to <http://localhost:7474/db/data/>
![Page 7: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/7.jpg)
Custom Connections
>>> from py2neo import neo4j
>>> uri = "http://otherserv:9999/db/data/"
>>> graph_db = neo4j.GraphDatabaseService(uri)
>>> graph_db.neo4j_version
(1, 8, u'M04', 1, u'g892e348')
![Page 8: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/8.jpg)
A few simple methods...
>>> graph_db.get_node(0)
Node('http://localhost:7474/db/data/node/0')
>>> graph_db.get_reference_node()
Node('http://localhost:7474/db/data/node/0')
>>> graph_db.get_node_count()
1
>>> graph_db.get_relationship_count()
0
![Page 9: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/9.jpg)
Sample data: a family tree
All characters appearing in this work are fictitious. Any resemblance to real persons, living or dead, is purely coincidental.
Phil (1921) Liz (1926)
Anne (1950)Chaz (1948) Andy (1960) Ed (1964)
m(1947)
![Page 10: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/10.jpg)
create
nodes = graph_db.create(
{"name": "Phil", "born": 1921},
{"name": "Liz", "born": 1926},
{"name": "Chaz", "born": 1948},
{"name": "Anne", "born": 1950},
{"name": "Andy", "born": 1960},
{"name": "Ed", "born": 1964},
)
Phil Liz
Chaz Anne
Andy Ed
list of nodes
![Page 11: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/11.jpg)
create
rels = graph_db.create(
(phil, "MARRIED", liz),
(chaz, "FATHER", phil),
(chaz, "MOTHER", liz),
)
Phil Liz
Chaz
MARRIED
MOTHER FATHER
node must already exist
list of relationships
![Page 12: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/12.jpg)
create
family = graph_db.create(
{"name": "Phil", "born": 1921}, {"name": "Liz", "born": 1926},
{"name": "Chaz", "born": 1948}, {"name": "Anne", "born": 1950},
{"name": "Andy", "born": 1960}, {"name": "Ed", "born": 1964},
(0, "MARRIED", 1, {"year": 1947, "place": "London"}),
(2, "FATHER", 0), (3, "FATHER", 0),
(4, "FATHER", 0), (5, "FATHER", 0),
(2, "MOTHER", 1), (3, "MOTHER", 1),
(4, "MOTHER", 1), (5, "MOTHER", 1),
)
![Page 13: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/13.jpg)
create
family = graph_db.create(
{"name": "Phil", "born": 1921}, {"name": "Liz", "born": 1926},
{"name": "Chaz", "born": 1948}, {"name": "Anne", "born": 1950},
{"name": "Andy", "born": 1960}, {"name": "Ed", "born": 1964},
(0, "MARRIED", 1, {"year": 1947, "place": "London"}),
(2, "FATHER", 0), (3, "FATHER", 0),
(4, "FATHER", 0), (5, "FATHER", 0),
(2, "MOTHER", 1), (3, "MOTHER", 1),
(4, "MOTHER", 1), (5, "MOTHER", 1),
)
nodes, rels = family[0:6], family[6:]
phil, liz, chaz, anne, andy, ed = nodes
list of nodes and relationships
node defined in same batch
relationship properties
![Page 14: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/14.jpg)
Property Containers
![Page 15: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/15.jpg)
neo4j.PropertyContainer
Node Relationship
PropertyContainer
![Page 16: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/16.jpg)
PropertyContainers implement many of the
container methods defined by the Python standard
<http://docs.python.org/reference/datamodel.html#emulating-container-types>
![Page 17: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/17.jpg)
neo4j.PropertyContainer
# update properties
liz["star_sign"] = "Taurus"
# query properties
for node in nodes:
name = node["name"]
if "star_sign" in node:
print name + " is a node["star_sign"]
else:
print name + " doesn't believe in horoscopes"
set property
get property
test property containment
![Page 18: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/18.jpg)
neo4j.Node
Node Relationship
PropertyContainer
![Page 19: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/19.jpg)
Relationships and Related Nodes
parental_rels = liz.get_relationships(
neo4j.Direction.INCOMING, "MOTHER"
)
parental_rels = liz.get_relationships_with(
chaz, neo4j.Direction.INCOMING, "MOTHER"
)
children = liz.get_related_nodes(
neo4j.Direction.INCOMING, "MOTHER"
)
Liz
Chaz
Anne
Liz
Chaz
Anne
Liz
Chaz
Anne
![Page 20: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/20.jpg)
Relationships and Related Nodes
>>> liz.has_relationship(neo4j.Direction.BOTH, "MARRIED")
True
>>> anne.is_related_to(phil, neo4j.Direction.OUTGOING, "FATHER")
True
>>> ed.is_related_to(andy, neo4j.Direction.BOTH, "BROTHER")
False
could also specify multiple types
![Page 21: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/21.jpg)
neo4j.Relationship
Node Relationship
PropertyContainer
![Page 22: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/22.jpg)
neo4j.Relationship
>>> rels[0].start_node
Node('http://localhost:7474/db/data/node/1')
>>> rels[0].end_node
Node('http://localhost:7474/db/data/node/2')
>>> rels[0].type
'MARRIED'
![Page 23: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/23.jpg)
More sample data: a second tree
George (1895) Betty (1900)
Liz (1926) Maggie (1930)
m
![Page 24: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/24.jpg)
Phil (1921) Liz (1926)
Anne (1950)Chaz (1948) Andy (1960) Ed (1964)
m(1947)
George (1895) Betty (1900)
Liz (1926) Maggie (1930)
m
![Page 25: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/25.jpg)
Phil (1921) Liz (1926)
Anne (1950)Chaz (1948) Andy (1960) Ed (1964)
m(1947)
George (1895) Betty (1900)
Liz (1926) Maggie (1930)
m
same person
![Page 26: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/26.jpg)
How can we avoid duplicate nodes?
![Page 27: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/27.jpg)
Indexes
![Page 28: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/28.jpg)
Indexing the first family...
>>> people = graph_db.get_or_create_index(neo4j.Node, "People")
>>> for node in nodes:
... people.add("name", node["name"], node)
>>> people.get("name", "Liz")
[Node('http://localhost:7474/db/data/node/2')]
list of matching entities
![Page 29: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/29.jpg)
...and the second
>>> new_props = [
... {"name": "George", "born": 1895},
... {"name": "Betty", "born": 1900},
... {"name": "Liz", "born": 1926},
... {"name": "Maggie", "born": 1930},
... ]
>>> george, betty, liz, maggie = [
... people.get_or_create("name", prop["name"], prop)
... for prop in new_props
... ]
>>> people.get("name", "Liz")
[Node('http://localhost:7474/db/data/node/2')]
same node as before
![Page 30: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/30.jpg)
People
name Andy
name Anne
name Betty
name Chaz
name Ed
name George
name Liz
name Maggie
name Phil
A Quick Query
>>> people.query("name:*e*")
[Node('http://localhost:7474/db/data/node/4'),
Node('http://localhost:7474/db/data/node/7'),
Node('http://localhost:7474/db/data/node/8'),
Node('http://localhost:7474/db/data/node/9')]
Maggie
Anne
Betty
George
![Page 31: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/31.jpg)
We've added the nodes... what about the relationships?
![Page 32: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/32.jpg)
Cypher & Geoff
![Page 33: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/33.jpg)
Cypher RELATE
START a=node(1), b=node(2)
RELATE (a)-[ab:KNOWS]->(b)
RETURN ab
![Page 34: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/34.jpg)
Cypher RELATE
a b RELATE a b
a b RELATE a b
a b RELATE !
![Page 35: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/35.jpg)
relate
new_rels = graph_db.relate(
(george, "MARRIED", betty),
(liz, "FATHER", george),
(maggie, "FATHER", george),
(liz, "MOTHER", betty),
(maggie, "MOTHER", betty),
)George Betty
Maggie
MARRIED
MOTHERFATHER
Liz
FATHER MOTHER
![Page 36: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/36.jpg)
For relationships,
relate can be seen as an idempotent
alternative to create
![Page 37: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/37.jpg)
cypher.execute
>>> from py2neo import cypher
>>> query = "START q=node(1) RETURN q"
>>> data, metadata = cypher.execute(graph_db, query)
>>> for row in data:
... q = row[0]
... print q
first column
![Page 38: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/38.jpg)
cypher.execute
>>> from py2neo import cypher
>>> query = "START q=node(1) RETURN q"
>>> data, metadata = cypher.execute(graph_db, query)
>>> for row in data:
... q = row[0]
... print q
available only after all rows received
first column
![Page 39: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/39.jpg)
cypher.execute
query = "START q=node(1) RETURN q"
def print_row(row):
q = row[0]
print row
cypher.execute(graph_db, query, row_handler=print_row)
executed once per row as each row is received
![Page 40: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/40.jpg)
Command Line Cypherelgin@forge:~% cypher "start a=node(1) match (a)-[:MARRIED]->(b) return a, b"
+------------------------------------------------------------------+
| a | b |
+------------------------------------------------------------------+
| (1) {"name":"Phil","born":1921} | (2) {"name":"Liz","born":1926} |
+------------------------------------------------------------------+
elgin@forge:~% cypher -f csv "start a=node(1) match (a)-[ab:MARRIED]->(b) return a, ab, b"
"a","ab","b"
"(1)","(1)-[0:MARRIED]->(2)","(2)"
elgin@forge:~% cypher -f json "start a=node(1) match (a)-[ab:MARRIED]->(b) return a, ab, b"
[
{"a": "(1)", "ab": "(1)-[0:MARRIED]->(2)", "b": "(2)"}
]
elgin@forge:~% cypher -f geoff "start a=node(1) match (a)-[ab:MARRIED]->(b) return a, ab, b"
(1) {"name": "Phil", "born": 1921}
(2) {"name": "Liz", "born": 1926}
(1)-[0:MARRIED]->(2) {"year": 1947, "place": "London"}
![Page 41: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/41.jpg)
Geoff is to graph dataas
CSV is to tabular data
<http://geoff.nigelsmall.net/>
![Page 42: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/42.jpg)
elgin@forge:~% cypher -f geoff "start n=node(*), r=rel(*) return n, r"
(0) {}
(1) {"born": 1921, "name": "Phil", "family": "Windsor"}
(2) {"born": 1926, "star_sign": "Taurus", "family": "Windsor", "name": "Liz"}
(3) {"born": 1948, "name": "Chaz", "family": "Windsor"}
(4) {"born": 1950, "name": "Anne", "family": "Windsor"}
(5) {"born": 1960, "name": "Andy", "family": "Windsor"}
(6) {"born": 1964, "name": "Ed", "family": "Windsor"}
(7) {"born": 1895, "name": "George"}
(8) {"born": 1900, "name": "Betty"}
(9) {"born": 1930, "name": "Maggie"}
(1)-[0:MARRIED]->(2) {"place": "London", "year": 1947}
(3)-[1:FATHER]->(1) {}
(4)-[2:FATHER]->(1) {}
(5)-[3:FATHER]->(1) {}
(6)-[4:FATHER]->(1) {}
(3)-[5:MOTHER]->(2) {}
(4)-[6:MOTHER]->(2) {}
(5)-[7:MOTHER]->(2) {}
(6)-[8:MOTHER]->(2) {}
(7)-[9:MARRIED]->(8) {}
(2)-[10:FATHER]->(7) {}
(9)-[11:FATHER]->(7) {}
(2)-[12:MOTHER]->(8) {}
(9)-[13:MOTHER]->(8) {}
![Page 43: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/43.jpg)
Neo4j Console
![Page 44: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/44.jpg)
Installation
![Page 45: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/45.jpg)
Requirements
● Python 2.6+ <http://python.org/>● Tornado 2.2.1 <http://www.tornadoweb.org/>● Neo4j 1.6+ <http://neo4j.org/>
![Page 46: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/46.jpg)
Installation
<http://pypi.python.org/pypi/py2neo>
elgin@forge:~% sudo pip install py2neo
elgin@forge:~% sudo pip install --upgrade py2neo
![Page 47: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/47.jpg)
Source Code
<https://github.com/nigelsmall/py2neo>
elgin@forge:~% git clone [email protected]:nigelsmall/py2neo.git
![Page 48: Introduction to py2neo](https://reader033.vdocuments.site/reader033/viewer/2022052410/554f3872b4c905471e8b4848/html5/thumbnails/48.jpg)
Future Plans
● Fast HTTP● Multi-threading support● Python 3● Command line tools● Property caching● Test harness for multiple Neo4j versions● New methods, e.g. get_paths_to