Introduction to py2neo

  • 10,404 views
Uploaded on

An introduction to the python library py2neo, used for building applications which use the Neo4j graph database.

An introduction to the python library py2neo, used for building applications which use the Neo4j graph database.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
10,404
On Slideshare
0
From Embeds
0
Number of Embeds
8

Actions

Shares
Downloads
155
Comments
1
Likes
7

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Introducing py2neonigel@nigelsmall.name py2neo.org@technige @py2neo
  • 2. Me...
  • 3. Where does py2neo fit in? (your app) py2neo GET /db/data/ 200 OK REST Server Neo4j
  • 4. Coming Up...● Connecting & Creating● Property Containers● Indexes & Uniqueness● Cypher & Geoff● Installation● Future Plans
  • 5. Connecting & Creating
  • 6. Default Connections>>> from py2neo import neo4j>>> graph_db = neo4j.GraphDatabaseService() default connection is made to <http://localhost:7474/db/data/>
  • 7. Custom Connections>>> from py2neo import neo4j>>> uri = "http://otherserv:9999/db/data/">>> graph_db = neo4j.GraphDatabaseService(uri)>>> graph_db.neo4j_version(1, 8, uM04, 1, ug892e348)
  • 8. 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
  • 9. Sample data: a family tree m (1947) Phil (1921) Liz (1926) Chaz (1948) Anne (1950) Andy (1960) Ed (1964)All characters appearing in this work are fictitious. Any resemblance to real persons, living or dead, is purely coincidental.
  • 10. list of nodes createnodes = graph_db.create( Phil Liz {"name": "Phil", "born": 1921}, {"name": "Liz", "born": 1926}, {"name": "Chaz", "born": 1948}, {"name": "Anne", "born": 1950}, Chaz Anne {"name": "Andy", "born": 1960}, {"name": "Ed", "born": 1964},) Andy Ed
  • 11. list of relationships create MARRIEDrels = graph_db.create( Phil Liz (phil, "MARRIED", liz), (chaz, "FATHER", phil), FATHER MOTHER (chaz, "MOTHER", liz), Chaz) node must already exist
  • 12. createfamily = 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),)
  • 13. list of nodes and relationships createfamily = 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), relationship (4, "FATHER", 0), (5, "FATHER", 0), properties (2, "MOTHER", 1), (3, "MOTHER", 1), (4, "MOTHER", 1), (5, "MOTHER", 1),) node defined in same batchnodes, rels = family[0:6], family[6:]phil, liz, chaz, anne, andy, ed = nodes
  • 14. Property Containers
  • 15. neo4j.PropertyContainer PropertyContainer Node Relationship
  • 16. PropertyContainers implement many of the container methods defined by the Python standard<http://docs.python.org/reference/datamodel.html#emulating-container-types>
  • 17. neo4j.PropertyContainer set property# update propertiesliz["star_sign"] = "Taurus"# query properties get property test propertyfor node in nodes: containment name = node["name"] if "star_sign" in node: print name + " is a node["star_sign"] else: print name + " doesnt believe in horoscopes"
  • 18. neo4j.Node PropertyContainerNode Relationship
  • 19. Relationships and Related Nodes Chazparental_rels = liz.get_relationships( Liz neo4j.Direction.INCOMING, "MOTHER" Anne) Chazparental_rels = liz.get_relationships_with( Liz chaz, neo4j.Direction.INCOMING, "MOTHER" Anne) Chazchildren = liz.get_related_nodes( Liz neo4j.Direction.INCOMING, "MOTHER" Anne)
  • 20. 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
  • 21. neo4j.Relationship PropertyContainerNode Relationship
  • 22. neo4j.Relationship>>> rels[0].start_nodeNode(http://localhost:7474/db/data/node/1)>>> rels[0].end_nodeNode(http://localhost:7474/db/data/node/2)>>> rels[0].typeMARRIED
  • 23. More sample data: a second tree m George (1895) Betty (1900) Liz (1926) Maggie (1930)
  • 24. m George (1895) Betty (1900) Liz (1926) Maggie (1930) m (1947) Phil (1921) Liz (1926)Chaz (1948) Anne (1950) Andy (1960) Ed (1964)
  • 25. m George (1895) Betty (1900) same person Liz (1926) Maggie (1930) m (1947) Phil (1921) Liz (1926)Chaz (1948) Anne (1950) Andy (1960) Ed (1964)
  • 26. How can we avoidduplicate nodes?
  • 27. Indexes
  • 28. 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
  • 29. ...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 same node... ] as before>>> people.get("name", "Liz")[Node(http://localhost:7474/db/data/node/2)]
  • 30. 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)] People George name Andy name Anne Maggie name Betty name Chaz name Ed name George Anne name Liz name Maggie Betty name Phil
  • 31. Weve added thenodes... what about the relationships?
  • 32. Cypher & Geoff
  • 33. Cypher RELATESTART a=node(1), b=node(2)RELATE (a)-[ab:KNOWS]->(b)RETURN ab
  • 34. Cypher RELATEa b RELATE a ba b RELATE a b !a b RELATE
  • 35. relatenew_rels = graph_db.relate( (george, "MARRIED", betty), (liz, "FATHER", george), (maggie, "FATHER", george), (liz, "MOTHER", betty), (maggie, "MOTHER", betty), George MARRIED Betty) FATHER FATHER MOTHER MOTHER Liz Maggie
  • 36. For relationships,relate can be seen as an idempotent alternative to create
  • 37. 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
  • 38. cypher.execute>>> from py2neo import cypher>>> query = "START q=node(1) RETURN q">>> data, metadata = cypher.execute(graph_db, query) available only after all rows received>>> for row in data:... q = row[0]... print q first column
  • 39. cypher.executequery = "START q=node(1) RETURN q" executed once per row as eachdef print_row(row): row is received q = row[0] print rowcypher.execute(graph_db, query, row_handler=print_row)
  • 40. 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"}
  • 41. Geoff is to graph data asCSV is to tabular data <http://geoff.nigelsmall.net/>
  • 42. 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) {}
  • 43. Neo4j Console
  • 44. Installation
  • 45. Requirements● Python 2.6+ <http://python.org/>● Tornado 2.2.1 <http://www.tornadoweb.org/>● Neo4j 1.6+ <http://neo4j.org/>
  • 46. Installation <http://pypi.python.org/pypi/py2neo>elgin@forge:~% sudo pip install py2neoelgin@forge:~% sudo pip install --upgrade py2neo
  • 47. Source Code <https://github.com/nigelsmall/py2neo>elgin@forge:~% git clone git@github.com:nigelsmall/py2neo.git
  • 48. 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
  • 49. EOFnigel@nigelsmall.name py2neo.org@technige @py2neo