Skip to content

Instantly share code, notes, and snippets.

@andreasronge
Created May 8, 2010 21:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save andreasronge/394786 to your computer and use it in GitHub Desktop.
Save andreasronge/394786 to your computer and use it in GitHub Desktop.
require 'rubygems'
require 'neo4j'
include Neo4j
Transaction.new
# create some people
andreas = Node.new :name => 'andreas'
peter = Node.new :name => 'peter'
kalle = Node.new :name => 'kalle'
sune = Node.new :name => 'sune'
adam = Node.new :name => 'adam'
# create some composers/artists
madonna = Node.new :name => 'madonna'
beethoven = Node.new :name => 'beethoven'
schubert = Node.new :name => 'schubert'
brahms = Node.new :name => 'brahms'
pink_floyed = Node.new :name => 'pink floyed'
grieg = Node.new :name => 'grieg'
mozart = Node.new :name => 'mozart'
# make relationships, who like what music
adam.rels.outgoing(:likes) << beethoven << brahms << grieg << mozart << pink_floyed
andreas.rels.outgoing(:likes) << beethoven << brahms << mozart
peter.rels.outgoing(:likes) << beethoven << brahms << schubert
kalle.rels.outgoing(:likes) << brahms << pink_floyed
sune.rels.outgoing(:likes) << pink_floyed << madonna
# utility method, returns an array of composer nodes
def composers_for(person)
[*person.outgoing(:likes)]
end
# prints out recommendations for the given person
def recommend(person)
# which composers does this person like ?
my_composers = composers_for(person)
# find all other people liking those composers
other_people = person.outgoing(:likes).incoming(:likes).depth(2).filter{|f| f.depth == 2}
# for each of those people, sort by the number of matching composers
# so that the most relevant recommendations are printed first
other_people.sort_by{|p| (composers_for(p) & my_composers).size}.reverse.each do |other_person|
# then print out those composers that he don't have
puts "Recommendation from #{other_person[:name]}"
(composers_for(other_person) - my_composers).each do |s|
puts " composer #{s[:name]}"
end
end
end
recommend(andreas)
Transaction.finish
@phillipoertel
Copy link

Thank you for this example, but I don't see how Neo4j helps here. It seems to me this is just as easy to implement with SQL (see below). Does Neo4j handle larger data sets better than SQL, or why would I use it in this case?

Table LIKES
user_id composer_id
1 1
1 3
2 1
2 2
2 4
2 5

find user 1's preferences

user1_composers = select composer_id from likes where user_id=1

find users which like the same composer

users_with_same_like = select user_id from likes where composer_id IN(user1_composers)

find composers the other users like

recommendations = select count(composer_id) as _cnt, composer_id where user_id IN(users_with_same_like) and composer_id NOT IN(user1_composers) ORDER BY _cnt DESC

@andreasronge
Copy link
Author

Yes, Neo4j does not slow down for larger data set. The traversal speed will remain the same even if the data size increases.
Also, I think it is easier to program a graphy problem in a graph db.

@phillipoertel
Copy link

Hi Andreas,

thanks for your reply. I'm really curious how it feels like to work with Neo4j and am looking forward to trying it out!

Phillip

@andreasronge
Copy link
Author

Yes, it requires a new way of thinking. Like many NoSQL databases Neo4j is very simple, but it requires that you have to do some more thinking - which is great fun.
For example you can implement your own indexing in Neo4j with a tree of nodes connected to your data nodes (e.g. for a spatial index). It's important to make sure that the node space is spread out -
e.g that one node does not have several thousands of relationships to other nodes.
Would be create to get some feedback, missing features/documenation/performance ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment