Introduction to py2neo

15,534 views

Published on

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

Published in: Technology, News & Politics
2 Comments
13 Likes
Statistics
Notes
No Downloads
Views
Total views
15,534
On SlideShare
0
From Embeds
0
Number of Embeds
2,720
Actions
Shares
0
Downloads
256
Comments
2
Likes
13
Embeds 0
No embeds

No notes for slide

Introduction to py2neo

  1. 1. Introducing py2neonigel@nigelsmall.name py2neo.org@technige @py2neo
  2. 2. Me...
  3. 3. Where does py2neo fit in? (your app) py2neo GET /db/data/ 200 OK REST Server Neo4j
  4. 4. Coming Up...● Connecting & Creating● Property Containers● Indexes & Uniqueness● Cypher & Geoff● Installation● Future Plans
  5. 5. Connecting & Creating
  6. 6. Default Connections>>> from py2neo import neo4j>>> graph_db = neo4j.GraphDatabaseService() default connection is made to <http://localhost:7474/db/data/>
  7. 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. 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. 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. 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. 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. 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. 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. 14. Property Containers
  15. 15. neo4j.PropertyContainer PropertyContainer Node Relationship
  16. 16. PropertyContainers implement many of the container methods defined by the Python standard<http://docs.python.org/reference/datamodel.html#emulating-container-types>
  17. 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. 18. neo4j.Node PropertyContainerNode Relationship
  19. 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. 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. 21. neo4j.Relationship PropertyContainerNode Relationship
  22. 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. 23. More sample data: a second tree m George (1895) Betty (1900) Liz (1926) Maggie (1930)
  24. 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. 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. 26. How can we avoidduplicate nodes?
  27. 27. Indexes
  28. 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. 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. 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. 31. Weve added thenodes... what about the relationships?
  32. 32. Cypher & Geoff
  33. 33. Cypher RELATESTART a=node(1), b=node(2)RELATE (a)-[ab:KNOWS]->(b)RETURN ab
  34. 34. Cypher RELATEa b RELATE a ba b RELATE a b !a b RELATE
  35. 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. 36. For relationships,relate can be seen as an idempotent alternative to create
  37. 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. 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. 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. 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. 41. Geoff is to graph data asCSV is to tabular data <http://geoff.nigelsmall.net/>
  42. 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. 43. Neo4j Console
  44. 44. Installation
  45. 45. Requirements● Python 2.6+ <http://python.org/>● Tornado 2.2.1 <http://www.tornadoweb.org/>● Neo4j 1.6+ <http://neo4j.org/>
  46. 46. Installation <http://pypi.python.org/pypi/py2neo>elgin@forge:~% sudo pip install py2neoelgin@forge:~% sudo pip install --upgrade py2neo
  47. 47. Source Code <https://github.com/nigelsmall/py2neo>elgin@forge:~% git clone git@github.com:nigelsmall/py2neo.git
  48. 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. 49. EOFnigel@nigelsmall.name py2neo.org@technige @py2neo

×