Top Banner
Neo4jrb 3 is awesome Prepared for the NYC Neo4j Meetup, November 19, 2014 by Chris Grigg totally biased co-maintainer Prepared for the NYC Neo4j Meetup, November 19, 2014
22

Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

Jul 13, 2015

Download

Software

Chris Grigg
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

Neo4jrb 3 is awesome

Prepared for the NYC Neo4j Meetup, November 19, 2014

by Chris Griggtotally biased co-maintainer

Prepared for the NYC Neo4j Meetup, November 19, 2014

Page 2: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

In this presentation...

We're going to talk Neo4j and Ruby.

In case you're new to either, here's the quickest summary you'll ever get of both.

Page 3: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

Basic data modeling in Neo4jNeo4j is a pure graph database.

SQL tables and relationships.

Image from http://i.stack.imgur.com/LmARq.png

A table becomes a label (Task and Tag), a row becomes a node, a column becomes a property, a join table becomes a relationship. The relationship is part of the data, so once we have a single Task, finding its tags is fast and easy. Relationships can have their own properties, too.

Image generated using http://www.apcjones.com/arrows/

Page 4: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

Cypher is Neo4j's Query Language"Return the tags of a specific task…"

SQL:SELECT * FROM 'Tag' JOIN 'TaskTag' ON ('Tag'.TagID = 'TaskTag'.TagID) where 'TaskTag'.TaskID = 1;

Cypher:MATCH (task:Task)-[r:TAGGED_WITH]->(tag:Tag) WHERE ID(task) = 1 RETURN tag

Page 5: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

Ruby...● ...is a dynamically typed programming language with a

syntax aimed at making developers happy.

● ...is known for (among other things) low learning curve, huge and colorful community, and tools that enable rapid development.

● ...calls its packages "gems."

Page 6: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

What is Neo4jrb?A project that makes Ruby devs happy and Neo4j easier.

● neo4j-core gem handles low-level DB communication, provides basic Neo4j API and Cypher DSL.

● neo4j gem adds object-graph-mapper (OGM) features. It's like Mongoid or ActiveRecord but for Neo4j.

But usually "Neo4jrb" means "the neo4j gem."

Page 7: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

Oh yeah, and......we won an award from Neo Technology at the 2014 Graph Connect conference for Best Community Contribution.

We think that's pretty cool and we'll bring it up until it gets weird.

Page 8: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

OK, so what do these gems do?They provide abstractions. If you start with this:MATCH (s:`Student`)-[r1:`ENROLLED_IN`]->(l:`Lesson`) WHERE s.name = 'Chris' RETURN s

neo4j-core lets you write it like this:Neo4j::Session.query.match('(s:`Student`)-[r1:`ENROLLED_IN`]->(l:`Lesson`)').where(s: { name: 'Chris' }).pluck(:s)

neo4j (neo4jrb) lets you simplify it to this:Student.as(:s).lessons.where(s: { name: 'Chris' }).pluck(:s)

Page 9: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

But wait, there's more!

Neo4jrb was modeled after ActiveRecord. That means...● Node models. Declared properties, validations,

callbacks, methods, finders.● Relationship models. Like node models, but they hold

your relationship logic.● Expressive Cypher DSL. You can build entire apps

without ever writing a line of Cypher directly.● Low, low cost of entry. Know Rails and ActiveRecord?

You can use Neo4j!

Page 10: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

No, you don't have to use JRuby.

Neo4jrb 2 required JRuby and Neo4j Embedded. This made things complicated.Neo4jrb 3 supports Ruby MRI with Neo4j Server AND JRuby with Neo4j embedded with the same API. That means:● Want to use the Neo4j Java API and Torquebox? No

problem.● Want the ease of Ruby MRI, flexibility of Neo4j Server?

Maybe Heroku or a different PaaS? You're covered.

Page 11: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

Why use an O*M?● Protect your code from query language changes.● Usually more comfortable for devs: write your Ruby app

in Ruby instead of Ruby + Cypher.● Encourages best practices.● Shortcuts for boilerplate code.● ...and many more, but we're on a time limit here.

Page 12: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

OGM VS pure Cypher. Why? Part 1.Any O*M makes the most repetitive parts of an app less of a chore. Cypher:CREATE (s:Student { name: 'Chris', age: 30 }) RETURN s

CREATE (l:Lesson { subject: 'Math', level: 99 }) RETURN l

MATCH (s:Student { name: 'Chris', age: 30 }), (l:Lesson { subject: 'Math', level: 99 })WITH s, lCREATE (s)-[r:`ENROLLED_IN`]->(l) RETURN r

What does that look like in Neo4jrb?student = Student.create(name: 'Chris', age: 30)

lesson = Lesson.create(subject: 'Math', level: 99)

student.lessons << lesson

Page 13: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

OGM VS pure Cypher. Why? Part 2.There's also this…student.age = 31

student.save

Instead of…MATCH (s:Student) WHERE ID(s) = {your_id} SET s.age = 31 RETURN s

Or what about deleting?student.destroy

I'll take that over this:MATCH (s:Student)-[r]-() WHERE ID(s) = {your_id} DELETE s, r

Page 14: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

What else? Easier Cypher Matches.

Neo4jrb provides what we think is the best Cypher DSL out there.

Return a student's lessons of level 99 taught by teachers aged 30.student.lessons(:l).where(level: 99).teachers.where(age: 30).pluck(:l)

Generates Cypher:"MATCH (student2305:`Student`), (l:`Lesson`), student2305-[rel0:`ENROLLED_IN`]->(l:`Lesson`), (result:`Teacher`), l<-[rel1:`lessons_taught`]-(result:`Teacher`) WHERE ID(student2305) = {ID_student2305} AND l.level = {l_level} AND result.age = {result_age} RETURN l | params: {:ID_student2305=>2305, :l_level=>99, :result_age=>30}"

That's cool, right?

Page 15: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

And little shortcuts...Say your endpoint is /students/:student_id/lessons/:idand you want all of a given student's lessons in one query. The Cypher:"MATCH (s:Student)-[r:`ENROLLED_IN`]->(l:Lessons) WHERE s.uuid = {student_id} AND l.uuid = {lesson_id} RETURN l"

...you could write this, which requires some knowledge of the database:Student.where(uuid: params[:student_id).lessons.where(uuid: params[:id])

...but the OGM gives you this. You only need to know about your models:Student.all.match_to(params[:student_id]).lessons.match_to(params[:id])

Page 16: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

Another thing: unique IDs by default.Problem: Neo Technology says not to count on its unique IDs for permalinks.

Solution: Neo4jrb generates a unique ID for each node out of the box.

This can be swapped out for the unique ID generation scheme of your choice.

Page 17: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

We find a basic REST wrapper requires you to think about the database a lot.The goal here is to let you think more about your app, less about the database.

Page 18: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

Getting started in RailsAdd to Gemfilegem 'neo4j'

Add to config/application.rbrequire 'neo4j/railtie'

Install Neo4jrake neo4j:install[community-2.1.5]

Omit from git if neededecho '/db/neo4j' >> .gitignore

Start Neo4jrake neo4j:start

See https://github.com/neo4jrb/neo4j/wiki/Neo4j-v3-Setup for more.

Page 19: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

Anatomy of a node modelclass Student

include Neo4j::ActiveNode # adds all node methods

property :name

index :name

property :email, constraint: :unique

property :gpa, type: Integer

has_many :out, :lessons, rel_class: 'EnrolledIn'

end

● A label is created that matches the class name. Also creates finder methods, Student.find , Student.where, Student.find_by , etc,...

● A schema index is added to the :name property and a unique constraint is added to :email.● Declaring properties creates setters/getters, student.email /student.email=● has_many creates an association, allowing for Student.all.lessons.where , student.

lessons.each , etc,... rel_class tells it to look at the 'EnrolledIn' model for more info.

Page 20: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

Anatomy of a rel modelclass EnrolledIn

include Neo4j::ActiveRel # adds all relationship methods

from_class Student

to_class Lesson

type 'ENROLLED_IN'

property :grade

property :created_at, type: DateTime

property :updated_at, type: DateTime

end

● Separates out relationship logic. Instead of student.lessons << lesson , do EnrolledIn.new(from_node: student, to_node: lesson).save

● You can add callbacks like after_create , all the standard Rails validations like validates_presence_of , custom properties with type conversion, custom methods, etc,...

● created_at/updated_at properties are set and updated automatically when declared.

Page 21: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

Some tips...● Name ActiveRel models after relationship types. It follows Rails naming

conventions: EnrolledIn is the model, "ENROLLED_IN" is the type.● Not using ActivelRel? Use the 'type' option in ActiveNode associations.

The gem creates types for you but they're never ideal.● Neo4j makes it easy to perform dynamic calculations of things like "number

of comments on a post" and "number of students in a class" but this doesn't mean you always should. Counts like those don't change constantly, so consider storing them in properties on the node.

● Familiarize yourself with Cypher, play with Neo4j's web browser! You don't need to know Cypher to get started but to squeeze performance out of your app, you will eventually need to know it.

Page 22: Intro to Neo4jrb 3.0 (NYC Neo4j Meetup 11/19/2014)

What's next?● Check out the sample app at https://github.com/subvertallchris/neodemo● Check out the gem at https://github.com/neo4jrb/neo4j● Get in touch with me: [email protected], @subvertallmedia on

twitter● Follow @neo4j and @neo4jrb on Twitter!● Tell your friends about Neo4j, the Ruby gem, and the NYC Neo4j Meetup!

www.meetup.com/nycneo4j/

Huge thanks to Nick Manning for organizing this event!