<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;A0UNR3c-fSp7ImA9WxBUFkU.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576</id><updated>2010-03-04T08:54:56.955+01:00</updated><title>Neo4j Blog</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://blog.neo4j.org/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://blog.neo4j.org/" /><author><name>Tobias Ivarsson</name><uri>http://www.blogger.com/profile/04765223705065183885</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>20</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/Neo4jBlog" /><feedburner:info uri="neo4jblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CUQHRHY9eSp7ImA9WxBUEUw.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-5370391669256271544</id><published>2010-02-25T16:45:00.008+01:00</published><updated>2010-02-25T16:55:35.861+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-25T16:55:35.861+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="example" /><category scheme="http://www.blogger.com/atom/ns#" term="jruby" /><category scheme="http://www.blogger.com/atom/ns#" term="graphdb" /><category scheme="http://www.blogger.com/atom/ns#" term="acl" /><title>Access control lists the graph database way</title><content type="html">&lt;p&gt;In many contexts you need to handle user permissions to access, create or change some kind of resources. A common example is a file system, and that's what we are going to dive into in this blog post. We're going to use &lt;a href="http://github.com/andreasronge/neo4j"&gt;Ruby bindings&lt;/a&gt; for the &lt;a href="http://neo4j.org/"&gt;Neo4j graph database&lt;/a&gt; to create a small - but working - example application.&lt;/p&gt;&lt;h2&gt;Preparation&lt;/h2&gt;&lt;p&gt;To set up the environment for this example on Ubuntu, I used the following commands:&lt;/p&gt;&lt;pre class="brush: plain"&gt;sudo apt-get install jruby&lt;br /&gt;sudo jruby -S gem install neo4j&lt;/pre&gt;&lt;p&gt;To import the libraries, the following code was used:&lt;/p&gt;&lt;pre class="brush: ruby"&gt;require 'rubygems'&lt;br /&gt;require 'neo4j'&lt;br /&gt;require 'neo4j/extensions/find_path'&lt;/pre&gt;&lt;h2&gt;Heading for the node space&lt;/h2&gt;&lt;p&gt;So user permissions, what are they all about? Obviously it's about users, and usually user groups as well. We'll abstract this away a bit and use the term &lt;em&gt;principals&lt;/em&gt;, which can be single users or groups.&lt;/p&gt;&lt;p&gt;The other side of user permissions are the resources which are to be protected. In our case we'll have a file system, so there will be folders and files. Here we'll use the term &lt;em&gt;content&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Let's start out building a graph to support the application from what we have gathered so far! When working with a graph it's beneficial to think in a graphy manner, so that's where we'll begin. Graphs are presumably about connecting things, so our first step is to create some relationships. Neo4j comes with a built-in &lt;em&gt;reference node&lt;/em&gt;, which is easily accessible at all times. We use this to create our own "subreference nodes", one for principals and one for content. This is how our graph looks so far:&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_sm_3KdSgQMg/S4abeWUza6I/AAAAAAAAAQ0/Ile0VJ3z6pc/s1600-h/acl-subref.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 128px;" src="http://1.bp.blogspot.com/_sm_3KdSgQMg/S4abeWUza6I/AAAAAAAAAQ0/Ile0VJ3z6pc/s400/acl-subref.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5442208145415039906" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;To create (and get) the subreference nodes, we use this function:&lt;/p&gt;&lt;pre class="brush: ruby"&gt;def get_or_create_sub_ref( name )&lt;br /&gt;  result = Neo4j.ref_node.rels.outgoing( name ).nodes.first&lt;br /&gt;  if ( result.nil? )&lt;br /&gt;    result = Neo4j::Node.new :name =&gt; name.to_s.capitalize.gsub("_", " ")&lt;br /&gt;    Neo4j.ref_node.rels.outgoing( name ) &lt;&lt; result&lt;br /&gt;  end&lt;br /&gt;  return result&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;This function is then called whenever we need to use a subreference node. The important parts here are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;ref_node&lt;/code&gt;: the built-in reference node&lt;/li&gt;&lt;li&gt;&lt;code&gt;rels&lt;/code&gt;: relationships connected to a node&lt;/li&gt;&lt;li&gt;&lt;code&gt;outgoing&lt;/code&gt;: the direction of the relationship (the relationships are always directed, but you can choose to ignore the direction in traversals)&lt;/li&gt;&lt;li&gt;&lt;code&gt;( name )&lt;/code&gt;: the type of relationships to follow (the type can be ignored in traversals as well, but in our case we want to use it)&lt;/li&gt;&lt;li&gt;&lt;code&gt;nodes&lt;/code&gt;: the nodes in the other end of the relationships&lt;/li&gt;&lt;li&gt;&lt;code&gt;first&lt;/code&gt;: the first node found - there sould only be one subreference node of each type&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If the subreference node isn't found, it will be created and connected to the reference node. As you can see, we're adding a property with the key &lt;code&gt;name&lt;/code&gt; to the nodes as well, which is there solely for the purpose of visualization (the images in this post are created using &lt;a href="http://neoclipse.org/"&gt;Neoclipse&lt;/a&gt;).&lt;/p&gt;&lt;h2&gt;Basic structure&lt;/h2&gt;&lt;p&gt;For the principals part, we are going to connect the top-level ones to the corresponding subreference node using a &lt;code&gt;PRINCIPAL&lt;/code&gt; type of relationship. Other than that, there's just users and groups, so let's use a &lt;code&gt;IS_MEMBER_OF_GROUP&lt;/code&gt; relationship type to encode that. This is how that looks in the graph:&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_sm_3KdSgQMg/S4abvEigk2I/AAAAAAAAAQ8/aNBTST487wc/s1600-h/acl-principals.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 372px;" src="http://1.bp.blogspot.com/_sm_3KdSgQMg/S4abvEigk2I/AAAAAAAAAQ8/aNBTST487wc/s400/acl-principals.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5442208432698463074" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;And here's the code to create it:&lt;/p&gt;&lt;pre class="brush: ruby"&gt;def new_principal( name, member_of_groups = [] )&lt;br /&gt;  principal = Neo4j::Node.new&lt;br /&gt;  principal[ :name ] = name&lt;br /&gt;  if member_of_groups.empty?&lt;br /&gt;    get_or_create_sub_ref( :PRINCIPALS ).rels.outgoing( :PRINCIPAL ) &lt;&lt; principal&lt;br /&gt;  else&lt;br /&gt;    for group in member_of_groups&lt;br /&gt;      principal.rels.outgoing( :IS_MEMBER_OF_GROUP ) &lt;&lt; group&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;  return principal&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;If a new principal isn't member of any groups, it's added as a top-level principal, connected to the principals subrefererence node. In other case, it's simply added to the groups.&lt;/p&gt;&lt;p&gt;With Neo4j all operations on the graph have to be encapsulated in a transaction, so this is how we'll call the above function:&lt;/p&gt;&lt;pre class="brush: ruby"&gt;Neo4j::Transaction.run do&lt;br /&gt;  all_principals = new_principal( "All principals" )&lt;br /&gt;  root = new_principal( "root", [ all_principals ] )&lt;br /&gt;  regular_users = new_principal( "Regular users", [ all_principals ] )&lt;br /&gt;  user1 = new_principal( "user1", [ regular_users ] )&lt;br /&gt;  user2 = new_principal( "user2", [ regular_users ] )&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;For the content part, things are very similar to the principals part. The main difference is that in this case, an item can have only a single parent item. Here's the graphical view on that:&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_sm_3KdSgQMg/S4acDVmMXdI/AAAAAAAAARE/mzRdjSOtY1A/s1600-h/acl-content.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 398px; height: 400px;" src="http://2.bp.blogspot.com/_sm_3KdSgQMg/S4acDVmMXdI/AAAAAAAAARE/mzRdjSOtY1A/s400/acl-content.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5442208780874702290" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;And this is the code to create the structure:&lt;/p&gt;&lt;pre class="brush: ruby"&gt;def new_content( name, parent = nil )&lt;br /&gt;  content = Neo4j::Node.new&lt;br /&gt;  content[ :name ] = name&lt;br /&gt;  if ( parent.nil? )&lt;br /&gt;    get_or_create_sub_ref( :CONTENT_ROOTS ).rels.outgoing( :CONTENT_ROOT ) &lt;&lt; content&lt;br /&gt;  else&lt;br /&gt;    parent.rels.outgoing( :HAS_CHILD_CONTENT ) &lt;&lt; content&lt;br /&gt;  end&lt;br /&gt;  return content&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;Similar to how the principals were created, this is the code to create the content data:&lt;/p&gt;&lt;pre class="brush: ruby"&gt;Neo4j::Transaction.run do&lt;br /&gt;  root_folder = new_content( "Root folder" )&lt;br /&gt;  temp_folder = new_content( "Temp", root_folder )&lt;br /&gt;  home_folder = new_content( "Home", root_folder )&lt;br /&gt;  user1_home_folder = new_content( "user1 home", home_folder )&lt;br /&gt;  user2_home_folder = new_content( "user2 home", home_folder )&lt;br /&gt;  a_file = new_content( "MyFile.pdf", user1_home_folder )&lt;br /&gt;end&lt;/pre&gt;&lt;h2&gt;At the core&lt;/h2&gt;&lt;p&gt;Now that we have the basic structure in place, what's left regarding our data is a small but crucial part: the permissions information! We're using a simple scheme: adding security relationships with optional boolean flags for read and write permission. Not much to say here, this is what we want the full graph to look like (click for a bigger version):&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_sm_3KdSgQMg/S4acShBjKJI/AAAAAAAAARM/R8jK72uiEhc/s1600-h/acl-all.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 230px;" src="http://2.bp.blogspot.com/_sm_3KdSgQMg/S4acShBjKJI/AAAAAAAAARM/R8jK72uiEhc/s400/acl-all.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5442209041640269970" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;A small function will help us add the security information:&lt;/p&gt;&lt;pre class="brush: ruby"&gt;def apply_security( content, principal, map_with_flags )&lt;br /&gt;  security_relationship = Neo4j::Relationship.new( :SECURITY, principal, content )&lt;br /&gt;  map_with_flags.each_pair {|key, value| security_relationship[ key ] = value}&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;It's time to add the security data:&lt;/p&gt;&lt;pre class="brush: ruby"&gt;Neo4j::Transaction.run do&lt;br /&gt;  apply_security( root_folder, root, { "w" =&gt; true } )&lt;br /&gt;  apply_security( root_folder, all_principals, { "r" =&gt; true } )&lt;br /&gt;  apply_security( temp_folder, all_principals, { "w" =&gt; true } )&lt;br /&gt;  apply_security( user1_home_folder, regular_users, { "r" =&gt; false, "w" =&gt; false } )&lt;br /&gt;  apply_security( user1_home_folder, user1, { "r" =&gt; true, "w" =&gt; true } )&lt;br /&gt;  apply_security( user2_home_folder, user2, { "r" =&gt; true, "w" =&gt; true } )&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;To check the permission for some action by an actual principal for some content, there's some work to do. This is the algorithm we use to retrieve a permission flag:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Move from the content node and upwards through the file system structure and investigate each level for permission information.&lt;/li&gt;&lt;li&gt;On each level, see if there are any principals related to or identical with the principal concerned.&lt;/li&gt;&lt;li&gt;Make sure to use the permission information from the principal closest to the principal concerned.&lt;/li&gt;&lt;li&gt;If permission information was found, return it; otherwise, continue traversing to the next level in the file system.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;In the code for this, we'll use a function named &lt;code&gt;depth_of_principal()&lt;/code&gt; to calculate the distance between the principal we have traversed to and the principal concerned. More on that later, here's the code to check the permissions:&lt;/p&gt;&lt;pre class="brush: ruby"&gt;def has_access( content, principal, flag )&lt;br /&gt;  for current_content in content.incoming( :HAS_CHILD_CONTENT ).depth( :all )&lt;br /&gt;    lowest_score = nil&lt;br /&gt;    lowest_modifier = nil&lt;br /&gt;    for rel in current_content.rels.incoming( :SECURITY )&lt;br /&gt;      rel_principal = rel.start_node&lt;br /&gt;      if !rel[ flag ].nil?&lt;br /&gt;        score = depth_of_principal( rel_principal, principal )&lt;br /&gt;        if !score.nil?&lt;br /&gt;          modifier = rel[ flag ]&lt;br /&gt;          if lowest_score.nil? || score &lt; lowest_score ||&lt;br /&gt;            ( score == lowest_score &amp;&amp; modifier )&lt;br /&gt;            lowest_score = score&lt;br /&gt;            lowest_modifier = modifier&lt;br /&gt;          end&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;    if !lowest_modifier.nil?&lt;br /&gt;      return lowest_modifier&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;  return false&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;Here's our function to check the distance between principals (and to see if they're on the same path at all).&lt;/p&gt;&lt;pre class="brush: ruby"&gt;def depth_of_principal( principal, reference_principal )&lt;br /&gt;  result = reference_principal.outgoing( :IS_MEMBER_OF_GROUP ).depth( :all ).path_to( principal )&lt;br /&gt;  return result.nil? ? nil : result.size&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;Finally, we want to see that everything works, so here's a utility function to print permission information:&lt;/p&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;def print_has_access( content, principal, flag )&lt;br /&gt;  print principal[ :name ] + " +" + flag.upcase + " access to " + content[ :name ] + "? " +&lt;br /&gt;    has_access( content, principal, flag ).to_s + "\n"&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;And here's how to use the function:&lt;/p&gt;&lt;pre class="brush: ruby"&gt;Neo4j::Transaction.run do&lt;br /&gt;  print_has_access( home_folder, root, "w" )&lt;br /&gt;  print_has_access( home_folder, user1, "w" )&lt;br /&gt;  print_has_access( a_file, root, "r" )&lt;br /&gt;  print_has_access( a_file, user2, "r" )&lt;br /&gt;  print_has_access( a_file, user1, "w" )&lt;br /&gt;end&lt;/pre&gt;&lt;h2&gt;Next steps&lt;/h2&gt;&lt;p&gt;The full source code is found &lt;a href="https://svn.neo4j.org/examples/acl/"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Here's a few useful resources to help you on your way:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://wiki.neo4j.org/"&gt;Neo4j Wiki&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://github.com/andreasronge/neo4j"&gt;Neo4j.rb&lt;/a&gt; at github&lt;/li&gt;&lt;li&gt;&lt;a href="http://neo4j.org/community/list/"&gt;mailing lists&lt;/a&gt; - good places to get help&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.neo4j.org/2010/02/top-10-ways-to-get-to-know-neo4j.html"&gt;The top 10 ways to get to know Neo4j&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Thanks for reading - any feedback is welcome!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-5370391669256271544?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/5370391669256271544/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=5370391669256271544" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/5370391669256271544?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/5370391669256271544?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/ScqFxPgTb9A/access-control-lists-graph-database-way.html" title="Access control lists the graph database way" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_sm_3KdSgQMg/S4abeWUza6I/AAAAAAAAAQ0/Ile0VJ3z6pc/s72-c/acl-subref.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.neo4j.org/2010/02/access-control-lists-graph-database-way.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUUHRn8zfSp7ImA9WxBVE0Q.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-8914872132592643770</id><published>2010-02-16T16:14:00.001+01:00</published><updated>2010-02-17T08:53:57.185+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-17T08:53:57.185+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="social network" /><category scheme="http://www.blogger.com/atom/ns#" term="neo4j" /><category scheme="http://www.blogger.com/atom/ns#" term="graphdb" /><category scheme="http://www.blogger.com/atom/ns#" term="talks" /><category scheme="http://www.blogger.com/atom/ns#" term="release" /><category scheme="http://www.blogger.com/atom/ns#" term="nosql" /><category scheme="http://www.blogger.com/atom/ns#" term="neo4j.rb" /><category scheme="http://www.blogger.com/atom/ns#" term="graph database" /><title>The top 10 ways to get to know Neo4j</title><content type="html">Today is a big day in &lt;a href="http://neo4j.org/"&gt;Neo4j&lt;/a&gt; land because after ten long years of development and seven years of commercial 24/7 production we just announced &lt;a href="http://neo4j.org/download"&gt;Neo4j 1.0&lt;/a&gt;!&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We're very excited about this and this post will outline the ten most interesting and fun ways of getting started with Neo4j. Without further ado, let's go!&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;h3&gt;Wait, what is Neo4j?&lt;/h3&gt;&lt;p&gt;&lt;a href="http://neo4j.org/"&gt;Neo4j&lt;/a&gt; is a graph database, that is, it stores data as nodes and relationships. Both nodes and relationships can hold properties in a key/value fashion. Here's a small example:&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://wiki.neo4j.org/images/8/84/Matrix.png"&gt;&lt;img style="cursor: pointer; width: 573px; height: 297px;" src="http://wiki.neo4j.org/images/8/84/Matrix.png" alt="" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;You can navigate the structure either by following the relationships or use declarative traverser features to get to the data you want.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;h3&gt;Introduction&lt;/h3&gt;&lt;p&gt;For a high-level, 9 minutes cocktail-party introduction of Neo4j, check out this interview with &lt;a href="http://twitter.com/emileifrem"&gt;Emil Eifrem&lt;/a&gt;:&lt;/p&gt;&lt;p&gt;&lt;embed src="http://blip.tv/play/geoUgbH6LQI" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="345" width="480"&gt;&lt;/embed&gt;&lt;/p&gt;&lt;p&gt;(&lt;a href="http://blip.tv/file/2895759"&gt;blip.tv&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;To watch a longer introduction, see the &lt;a href="https://nosqleast.com/2009/#speaker/eifrem"&gt;no:sql(east) 2009&lt;/a&gt; presentation by &lt;a href="http://twitter.com/emileifrem"&gt;Emil Eifrém&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;h3&gt;Handling complexity&lt;/h3&gt;&lt;p&gt;Most applications will not only have to scale to a huge volumes, but also &lt;a href="http://blogs.neotechnology.com/emil/2009/11/nosql-scaling-to-size-and-scaling-to-complexity.html"&gt;scale to the complexity&lt;/a&gt; of the domain at hand. Typically, there may be many interconnected entities and optional properties. Even simple domains can be complex to handle because of the queries you want to run on them, for example to find paths. Two coding examples are the &lt;a href="http://blog.neo4j.org/2009/09/social-networks-in-database-using-graph.html"&gt; social network example&lt;/a&gt; (&lt;a href="http://github.com/andreasronge/neo4j/tree/master/examples/you_might_know/"&gt;partial Ruby implementation&lt;/a&gt;) and the &lt;a href="http://wiki.neo4j.org/content/IMDB_Example"&gt;Neo4j IMDB example&lt;/a&gt; (&lt;a href="http://github.com/andreasronge/neo4j/tree/master/examples/imdb/"&gt;Ruby variation of the code&lt;/a&gt;). For more examples of different domains modeled in a graph database, visit the &lt;a href="http://wiki.neo4j.org/content/Domain_Modeling_Gallery"&gt;Domain Modeling Gallery&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;h3&gt;Storing objects&lt;/h3&gt;&lt;p&gt;The common domain implementation pattern when using Neo4j is to let the domain objects &lt;a href="http://wiki.neo4j.org/content/Design_Guide#How_to_wrap_nodes_in_POJOs"&gt;wrap a node&lt;/a&gt;, and store the state of the entity in the node properties. To relieve you from the boilerplate code needed for this, you can use a framework like &lt;a href="http://www.blogger.com/post-create.g?blogID=5194400562660165576"&gt;jo4neo&lt;/a&gt; (&lt;a href="http://architects.dzone.com/articles/java-object-mapping-neo4j"&gt;intro&lt;/a&gt;, &lt;a href="http://www.thewebsemantic.com/tag/neo4j/"&gt;blog posts&lt;/a&gt;), where you use annotations to declare properties and relationships, but still have the full power of the graph database available for deep traversals and other graphy stuff. Here's a code sample showing jo4neo in action:&lt;/p&gt;&lt;pre class="brush: java"&gt;public class Person {&lt;br /&gt;  //used by jo4neo&lt;br /&gt;  transient Nodeid node;&lt;br /&gt;  //simple property&lt;br /&gt;  @neo String firstName;&lt;br /&gt;  //helps you store a java.util.Date to neo4j&lt;br /&gt;  @neo Date date;&lt;br /&gt;  // jo4neo will index for you&lt;br /&gt;  @neo(index=true) String email;&lt;br /&gt;  // many to many relation&lt;br /&gt;  @neo Collection&lt;role&gt; roles; &lt;br /&gt;&lt;br /&gt;  /* normal class oriented&lt;br /&gt;  * programming stuff goes here&lt;br /&gt;  */&lt;br /&gt;}&lt;/role&gt;&lt;/pre&gt;&lt;p&gt;Another way to persist objects is by using the &lt;a href="http://github.com/andreasronge/neo4j"&gt;neo4j.rb&lt;/a&gt; Neo4j wrapper for Ruby. Time for a few lines of sample code again:&lt;/p&gt;&lt;pre class="brush: ruby"&gt;require "rubygems"&lt;br /&gt;require "neo4j"&lt;br /&gt;&lt;br /&gt;class Person&lt;br /&gt;  include Neo4j::NodeMixin&lt;br /&gt;  # define Neo4j properties&lt;br /&gt;  property :name, :salary, :age, :country&lt;br /&gt;&lt;br /&gt;  # define an one way relationship to any other node&lt;br /&gt;  has_n :friends&lt;br /&gt;&lt;br /&gt;  # adds a Lucene index on the following properties&lt;br /&gt;  index :name, :salary, :age, :country&lt;br /&gt;end&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;h3&gt;REST API&lt;/h3&gt;&lt;p&gt;Of course you want a RESTful API in front of the graph database as well. There's been plenty of work going on in that area and here are some options:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The &lt;a href="http://github.com/andreasronge/neo4j"&gt;neo4j.rb&lt;/a&gt; Ruby bindings comes with a REST extension.&lt;/li&gt;&lt;li&gt;The &lt;a href="http://github.com/mdeiters/neo4jr-simple"&gt;neo4jr-simple&lt;/a&gt; Ruby wrapper has the &lt;a href="http://github.com/mdeiters/neo4jr-social"&gt;neo4jr-social&lt;/a&gt; example project, which exposes social network data over a REST API.&lt;/li&gt;&lt;li&gt;Similarly, the &lt;a href="http://github.com/ept/neo4j-resources"&gt;Scala bindings&lt;/a&gt; has a companion &lt;a href="http://github.com/ept/neo4j-scala-template"&gt;example project&lt;/a&gt; which will show you how to set up a project exposing your data over REST.&lt;/li&gt;&lt;li&gt;Last but not least, &lt;a href="http://twitter.com/jimwebber"&gt;Jim Webber&lt;/a&gt; has joined up with the core Neo4j team to create a kick-ass REST API. The current code base is only &lt;a href="https://svn.neo4j.org/laboratory/components/rest/"&gt;in the laboratory&lt;/a&gt; but a lot of people are already kicking its tires.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;h3&gt;Language bindings&lt;/h3&gt;&lt;p&gt;The Neo4j graph engine is written in Java, so you can easily add &lt;a href="http://neo4j.org/download/"&gt;the jar file&lt;/a&gt; and start using the &lt;a href="http://api.neo4j.org/current/"&gt;simple and minimalistic API&lt;/a&gt; right away. Your first stop should be the &lt;a href="http://wiki.neo4j.org/content/Getting_Started_Guide"&gt;Getting started guide&lt;/a&gt;, or if you want to add a package of useful add-on components to the mix, go for &lt;a href="http://wiki.neo4j.org/content/Getting_Started_With_Apoc"&gt;Getting started with Apoc&lt;/a&gt;. Other language bindings:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://wiki.neo4j.org/content/Python"&gt;Python&lt;/a&gt; - see &lt;a href="http://us.pycon.org/2010/conference/schedule/event/115/"&gt;PyCon 2010&lt;/a&gt; too!&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.neo4j.org/content/Ruby"&gt;Ruby&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.neo4j.org/content/Clojure"&gt;Clojure&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.neo4j.org/content/Scala"&gt;Scala&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.neo4j.org/content/Java"&gt;Java object mapping&lt;/a&gt;&lt;/li&gt;&lt;li&gt;For Groovy, see the next section on frameworks.&lt;/li&gt;&lt;li&gt;Integration with &lt;a href="http://wiki.neo4j.org/content/PHP"&gt;PHP&lt;/a&gt; is worked on as well.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;h3&gt;Frameworks&lt;/h3&gt;&lt;p&gt;Work is being done on using Neo4j as backend of different frameworks. Follow the links to get more information!&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://github.com/andreasronge/neo4j"&gt;Ruby on Rails&lt;/a&gt; (&lt;a href="http://github.com/andreasronge/neo4j-rails-example"&gt;example app&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.neo4j.org/content/Grails"&gt;Grails&lt;/a&gt; (&lt;a href="http://blog.armbruster-it.de/2009/10/example-neo4j-with-grails/"&gt;example code&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.neo4j.org/content/Spring_And_Neo4j"&gt;Spring framework&lt;/a&gt; (&lt;a href="http://wiki.neo4j.org/content/IMDB_Example"&gt;full example&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href="http://journal.thobe.org/2009/12/seamless-neo4j-integration-in-django.html"&gt;Django&lt;/a&gt; - see &lt;a href="http://us.pycon.org/2010/conference/schedule/event/115/"&gt;PyCon 2010&lt;/a&gt; too!&lt;/li&gt;&lt;li&gt;&lt;a href="http://docs.codehaus.org/display/GRIFFON/Neo4j+Plugin"&gt;Griffon&lt;/a&gt; (&lt;a href="http://github.com/aalmiray/griffon_sample_apps/tree/master/neo4j-test"&gt;sample app&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;h3&gt;Tools&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://wiki.neo4j.org/content/Shell"&gt;Shell&lt;/a&gt;: a command-line shell for browsing the graph and manipulate it.&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.neo4j.org/content/Neoclipse"&gt;Neoclipse&lt;/a&gt;: Eclipse plugin (and standalone application) for Neo4j. Visual interface to browse and edit the graph.&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.neo4j.org/content/Batch_Insert"&gt;Batch inserter&lt;/a&gt;: tool to bulk upload big datasets quickly.&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.neo4j.org/content/Online_Backup"&gt;Online backup&lt;/a&gt;: performs backup of a running Neo4j instance.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;h3&gt;Query languages&lt;/h3&gt;&lt;p&gt;Beyond using Neo4j programmatically, you can also issue queries using a query language. These are the supported options at the moment:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;SPARQL: Neo4j can be used as a triple- or quadstore, and has SAIL and SPARQL implementations. Go to the &lt;a href="http://components.neo4j.org/"&gt;components site&lt;/a&gt; to find out more about the related components.&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.neo4j.org/2010/02/yay-graph-processing-infrastructure-is.html"&gt;Gremlin&lt;/a&gt;: a graph-based programming-language with different backend implementations in the works as well as a supporting toolset.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;h3&gt;Inspiration&lt;/h3&gt;&lt;p&gt;Have a look at the &lt;a href="http://wiki.neo4j.org/content/Neo4j_In_The_Wild"&gt;Neo4j in the wild&lt;/a&gt; page to see what others are doing with Neo4j. Here's a selection:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.monkeyatlarge.com/projects/redline-travel-time/"&gt;Red line travel times visualization&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://snosled.svn.sourceforge.net/svnroot/snosled/TRUNK/snosled/src/main/resources/developmentPlan.html"&gt;snosled&lt;/a&gt; medical terminology tool&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amanzitel.com/page/AWE"&gt;Amanzi Wireless Explorer&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://github.com/mdeiters/neo4jr-social"&gt;neo4jr-social&lt;/a&gt; REST API to social network data&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;Hopefully this post was a good starting guide to the Neo4j ecosystem. As always, please ask any questions on the &lt;a href="https://lists.neo4j.org/"&gt;mailing list&lt;/a&gt; or come hang out with us in the &lt;a href="http://wiki.neo4j.org/content/Neo4j_Wiki:Community_Portal"&gt;#neo4j channel&lt;/a&gt; on IRC.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-8914872132592643770?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/8914872132592643770/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=8914872132592643770" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/8914872132592643770?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/8914872132592643770?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/oSfbm69dHqY/top-10-ways-to-get-to-know-neo4j.html" title="The top 10 ways to get to know Neo4j" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://blog.neo4j.org/2010/02/top-10-ways-to-get-to-know-neo4j.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUMGRXg8fyp7ImA9WxBWFkk.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-3416549946001723409</id><published>2010-02-07T18:12:00.023+01:00</published><updated>2010-02-08T17:43:44.677+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-08T17:43:44.677+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="neo4j.rb" /><category scheme="http://www.blogger.com/atom/ns#" term="graph" /><category scheme="http://www.blogger.com/atom/ns#" term="gremlin" /><title>Yay! The Graph Processing Infrastructure is starting to emerge!</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://gremlin-users.googlegroups.com/web/gremlin-standing.png?gda=XDTDTkcAAABhE4ES9mFsdwzht2XmOfEXBxQYzVIPS_l1JjKqQ9E0SkZH6pevkOz8QKF1YsWVvG8VeY4b49xGcMK802iZZ8SFeV4duv6pDMGhhhZdjQlNAw"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 204px; height: 220px;" src="http://gremlin-users.googlegroups.com/web/gremlin-standing.png?gda=XDTDTkcAAABhE4ES9mFsdwzht2XmOfEXBxQYzVIPS_l1JjKqQ9E0SkZH6pevkOz8QKF1YsWVvG8VeY4b49xGcMK802iZZ8SFeV4duv6pDMGhhhZdjQlNAw" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Hi all,&lt;br /&gt;in the last months, the &lt;a href="http://www.tinkerpop.com/"&gt;Tinkerpop&lt;/a&gt; team has been starting to venture into the big task of starting a unified ecosystem for the world of graphs and related projects and products. Now, I am proud to say that it seems things are starting to get some traction and see increasing contributions from outside the core team, mainly the awesome &lt;a href="http://markorodriguez.com/"&gt;Marko Rodriguez&lt;/a&gt;:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;Logo contributed by &lt;a href="http://csillustrated.berkeley.edu/"&gt;Ketrina Yim&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The JUNG graph library got adapted to &lt;a href="http://gremlin.tinkerpop.com/"&gt;Gremlin&lt;/a&gt;&lt;/li&gt;&lt;li&gt;HyperGraphDB is being adapted to work with Gremlin&lt;/li&gt;&lt;li&gt;a REST API based on the awesome work of &lt;a href="http://jim.webber.name/"&gt;Jim Webber&lt;/a&gt; and the &lt;a href="http://www.neo4j.org/"&gt;Neo4j&lt;/a&gt; team is in the making by &lt;a href="http://www.jexp.de/"&gt;Michael Hunger&lt;/a&gt; and Pavel Yaskevich&lt;/li&gt;&lt;/ul&gt;So, here is the current project ecosystem - great work of everyone involved! &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://gremlin.tinkerpop.com/"&gt;Gremlin&lt;/a&gt;:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;mainly driven by Marko Rodriguez&lt;/li&gt;&lt;li&gt;a library and standalone, single-user Java project, defining a&lt;/li&gt;&lt;li&gt;number of data models - to start with the Property Graph Model (PGM) and the&lt;/li&gt;&lt;li&gt;General Document Model (GDM) , soon to be broken out of the core Gremlin code.&lt;/li&gt;&lt;li&gt;Adapters to different underlying graph implementations, from Neo4j to SAIL, integrating anything from Sesame to a live LinkedData SAIL&lt;/li&gt;&lt;li&gt;Adapters to other interesting graph frameworks like JUNG, suggested by &lt;a href="http://automenta.com/"&gt;Seth@Automenta&lt;/a&gt;&lt;/li&gt;&lt;li&gt;A Turing complete scripting language for querying, modification and transformation of PGM and GDM compliant data structures&lt;/li&gt;&lt;li&gt;All selectors are XPath-based in syntax&lt;/li&gt;&lt;li&gt;Pluggable external path elements and function implementation.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://github.com/jexp/RESTling"&gt;RESTling&lt;/a&gt;&lt;/span&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Driven mainly by &lt;a href="http://www.jexp.de/"&gt;Michael Hunger&lt;/a&gt; and Pavel Yaskevich&lt;/li&gt;&lt;li&gt;A REST interface using e.g. Jetty and Jersey as the frameworks&lt;/li&gt;&lt;li&gt;Exposes Gremlin as a set of RESTful HTTP URI templates (e.g.&lt;a href="http://localhost/restling/%7Balgo%7D/%7Bparam1%7D/%7Bparam2%7D" target="_blank"&gt; http://localhost/restling/{&lt;wbr&gt;algo}/{param1}/{param2}&lt;/a&gt;) and operations (PUT, GET, DELETE, POST)&lt;/li&gt;&lt;li&gt;handles multi-session access to the Gremlin backend&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://github.com/tinkerpop/webling"&gt;Webling&lt;/a&gt;:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Driven mainly by &lt;a href="http://github.com/xedin"&gt;Pavel Yaskevich&lt;/a&gt; via financing from &lt;a href="http://www.neotechnology.com/"&gt;Neo Technology&lt;/a&gt;&lt;/li&gt;&lt;li&gt;A web based visual end-user interface to Restling&lt;/li&gt;&lt;li&gt;A web based terminal supporting execution of Gremlin operations and logic&lt;/li&gt;&lt;li&gt;Visualization support with graph libraries&lt;/li&gt;&lt;li&gt;Multi-user support&lt;/li&gt;&lt;li&gt;Via REST support to connect to remote Restling instances&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://gargamel.tinkerpop.com"&gt;Gargame&lt;/a&gt;&lt;a href="http://github.com/tinkerpop/gargamel"&gt;l&lt;/a&gt;:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Driven mainly by Marko Rodriguez&lt;br /&gt;&lt;/li&gt;&lt;li&gt;a execution framework primarily targeted at &lt;a href="http://en.wikipedia.org/wiki/Bulk_synchronous_parallel"&gt;Bulk Synchronous Parallel&lt;/a&gt; graph algos&lt;/li&gt;&lt;li&gt;A number of highly parallel base graph algos integrated into Gremlin to use this framework&lt;/li&gt;&lt;li&gt;A communication framework for execution of gremlin tasks on different (partitioned or replicated) graph instances, firstly using &lt;a href="http://linkedprocess.org/"&gt;LinkedProcess&lt;/a&gt; (financed by the &lt;a href="http://www.lanl.gov/"&gt;LANL&lt;/a&gt;) and XMPP, but replaceable with e.g. an Erlang-implementation (kudos to &lt;a href="http://www.ingo-schramm.de/"&gt;Ingo Schramm&lt;/a&gt; for suggesting it) or RESTling- based communication for optimization of different aspects like inter-process communication during execution&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;All in all, I just wanted to express my excitement over the whole emerging community around Gremlin, Neo4j and graphs in general! It is thrilling to see that the easy use of graphs and the internet-scale processing of complex data structures is starting to take shape in an open world, getting the different views on graphy data onto one page and providing a broader audience the possibility to use graph structures in the real world.&lt;br /&gt;&lt;br /&gt;/peter neubauer&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-3416549946001723409?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/3416549946001723409/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=3416549946001723409" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/3416549946001723409?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/3416549946001723409?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/s2w8E7SnmgA/yay-graph-processing-infrastructure-is.html" title="Yay! The Graph Processing Infrastructure is starting to emerge!" /><author><name>Peter Neubauer</name><uri>http://www.blogger.com/profile/08648014346248909032</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="03899237397995011553" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.neo4j.org/2010/02/yay-graph-processing-infrastructure-is.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUEMRn06fip7ImA9WxBSF0g.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-1426211784649338244</id><published>2009-12-25T15:07:00.013+01:00</published><updated>2009-12-25T17:14:47.316+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-25T17:14:47.316+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="social network" /><category scheme="http://www.blogger.com/atom/ns#" term="jruby" /><category scheme="http://www.blogger.com/atom/ns#" term="jython" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="nosql" /><category scheme="http://www.blogger.com/atom/ns#" term="neo4j.rb" /><title>Holiday fun with Neo4j</title><content type="html">&lt;p&gt;Looking for something fun to do during the holidays? Here are a few suggestions for some new cool &lt;a href="http://neo4j.org/"&gt;Neo4j&lt;/a&gt; things that you can play around with.&lt;/p&gt;&lt;p&gt;A very recent addition to the Neo4j space is the JRuby library &lt;a href="http://github.com/mdeiters/neo4jr-social"&gt;Neo4jr-social&lt;/a&gt; by &lt;a href="http://twitter.com/mdeiters"&gt;Matthew Deiters&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Neo4jr-Social is a self contained HTTP REST + JSON interface to the graph database Neo4j. Neo4jr-Social supports simple dynamic node creation, building relationships between nodes and also includes a few common social networking queries out of the box (i.e. linkedin degrees of seperation and facebook friend suggestion) with more to come. Think of Neo4jr-Social is to Neo4j like Solr is to Lucene.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Neo4jr-social is built on top of &lt;a href="http://github.com/mdeiters/neo4jr-simple"&gt;Neo4jr-simple&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;A simple, ready to go JRuby wrapper for the Neo4j graph database engine.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;There's also the &lt;a href="http://github.com/andreasronge/neo4j"&gt;Neo4j.rb&lt;/a&gt; JRuby bindings by &lt;a href="http://twitter.com/ronge"&gt;Andreas Ronge&lt;/a&gt; which have been developed for quite a while by multiple contributors.&lt;/p&gt;&lt;p&gt;Staying in Ruby land, there's also some &lt;a href="http://github.com/obruening/neoviz"&gt;visualization&lt;/a&gt; and other &lt;a href="http://github.com/sashaagafonoff/peoplemap"&gt;social network analysis&lt;/a&gt; stuff going on.&lt;/p&gt;&lt;p&gt;Looking for something in Java? Then you definitely want to take a look at &lt;a href="http://code.google.com/p/jo4neo/"&gt;jo4neo&lt;/a&gt; by &lt;a href="http://twitter.com/tcowan"&gt;Taylor Cowan&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;    Simple object mapping for neo. No byte code interweaving, just plain old reflection and plain old objects.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;There's also a blog post where Taylor shows how to model a &lt;a href="http://www.thewebsemantic.com/2009/12/18/userroles-pattern-in-jo4neo/"&gt;User/Roles pattern using jo4neo&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;There's apparently a lot of work &lt;a href="http://nosql.mypopescu.com/post/299775877/nosql-to-people"&gt;going on&lt;/a&gt; right now in the Django camp to enable support for SQL and NOSQL databases alike. &lt;a href="http://twitter.com/thobe"&gt;Tobias Ivarsson&lt;/a&gt; (who's the author and maintainer of the Neo4j &lt;a href="http://wiki.neo4j.org/content/Python"&gt;Python bindings&lt;/a&gt;) recently implemented initial support for Neo4j in Django. Read his post &lt;a href="http://journal.thobe.org/2009/12/seamless-neo4j-integration-in-django.html"&gt;Seamless Neo4j integration in Django&lt;/a&gt; for a look at what's new.&lt;/p&gt;&lt;p&gt;One more recent project is the &lt;a href="http://wiki.neo4j.org/content/Grails"&gt;Neo4j plugin for Grails&lt;/a&gt;. There are already some projects out there using it. We want to make sure Neo4j is a first-class Grails backend so expect more noise in this area in the future.&lt;/p&gt;&lt;p&gt;You can find (some of the) projects using Neo4j on the &lt;a href="http://wiki.neo4j.org/content/Neo4j_In_The_Wild"&gt;Neo4j In The Wild&lt;/a&gt; page. From the front page of the &lt;a href="http://wiki.neo4j.org/"&gt;Neo4j wiki&lt;/a&gt; you'll find even more language bindings, tutorials and other things that will support you when playing around with Neo4j!&lt;/p&gt;&lt;p&gt;Happy Holidays and Happy Hacking wishes from the Neo4j team!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-1426211784649338244?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/1426211784649338244/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=1426211784649338244" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/1426211784649338244?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/1426211784649338244?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/LL1f0juLpYY/holiday-fun-with-neo4j.html" title="Holiday fun with Neo4j" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.neo4j.org/2009/12/holiday-fun-with-neo4j.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8HRno7fyp7ImA9WxNQFUk.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-2897939188649956439</id><published>2009-09-15T13:43:00.023+02:00</published><updated>2009-09-21T17:27:17.407+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-21T17:27:17.407+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="comparison" /><category scheme="http://www.blogger.com/atom/ns#" term="relational model" /><category scheme="http://www.blogger.com/atom/ns#" term="graphdb" /><category scheme="http://www.blogger.com/atom/ns#" term="graph database" /><category scheme="http://www.blogger.com/atom/ns#" term="graph" /><category scheme="http://www.blogger.com/atom/ns#" term="relational database" /><category scheme="http://www.blogger.com/atom/ns#" term="rdbms" /><title>Social networks in the database: using a graph database</title><content type="html">&lt;p&gt;Recently &lt;a href="http://www.alberton.info/"&gt;Lorenzo Alberton&lt;/a&gt; gave a talk on &lt;a href="http://www.slideshare.net/quipo/trees-in-the-database-advanced-data-structures"&gt;Trees In The Database&lt;/a&gt; where he showed the most used approaches to storing trees in a relational database. Now he has moved on to an even more interesting topic with his article &lt;a href="http://techportal.ibuildings.com/2009/09/07/graphs-in-the-database-sql-meets-social-networks/"&gt;Graphs in the database: SQL meets social networks&lt;/a&gt;. Right from the beginning of his excellent article Alberton puts this technical challenge in a proper context:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Graphs are ubiquitous. Social or P2P networks, thesauri, route planning systems, recommendation systems, collaborative filtering, even the World Wide Web itself is ultimately a graph! Given their importance, it’s surely worth spending some time in studying some algorithms and models to represent and work with them effectively.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;After a brief explanation of what a graph data structure is, the article goes on to show how graphs can be represented in a table-based database. The rest of the article shows in detail how an &lt;a href="http://en.wikipedia.org/wiki/Adjacency_list"&gt;adjacency list model&lt;/a&gt; can be used to represent a graph in a relational database. Different examples are used to illustrate what can be done in this way.&lt;/p&gt;&lt;p&gt;This post is going to show how the same things can be done when using a native graph database, namely &lt;a href="http://neo4j.org/"&gt;Neo4j&lt;/a&gt;. To begin with it's good to have a grip on how your data actually looks, and when it comes to &lt;em&gt;graphs&lt;/em&gt; I prefer a &lt;em&gt;graphical&lt;/em&gt; representation, so here goes:&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_sm_3KdSgQMg/Sq-IYSqcw8I/AAAAAAAAAEs/-B-87_4OmXQ/s1600-h/socnet-start.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://3.bp.blogspot.com/_sm_3KdSgQMg/Sq-IYSqcw8I/AAAAAAAAAEs/-B-87_4OmXQ/s400/socnet-start.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5381670030639154114" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;As you can see it's a fairly small social network, so it should be easy to comprehend what's going on in the examples. Anyhow, please read &lt;a href="http://techportal.ibuildings.com/2009/09/07/graphs-in-the-database-sql-meets-social-networks/"&gt;the original article&lt;/a&gt; for the full context of the examples; this article will mainly deal with how to solve the same problems in a true graph database. For the sample code, Java will be used. If you're no fan of Java, go check out the &lt;a href="http://neo4j.org/community/languages/"&gt;current language bindings of Neo4j&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;Representing a graph&lt;/h2&gt;&lt;p&gt;This part is very different when dealing with a graph database: there's no need to think much about the representation at all when using a graph database. Nodes and relationships (also called edges) are native to a graph database and this includes making sure that the graph is consistent (for example ensuring that every relationship has a start node and an end node). As a developer you can focus more on what to model and less on how to represent it.&lt;/p&gt;&lt;h2&gt;Traversing the graph&lt;/h2&gt;&lt;p&gt;Our first task is to find the nodes that are directly connected to a node in the case of directed relationships. We assume the &lt;code&gt;node&lt;/code&gt; variable as input and then the code is as easy as follows:&lt;/p&gt;&lt;pre class="brush: java"&gt;for ( Relationship rel : node.getRelationships( RelationshipTypes.KNOWS, Direction.OUTGOING ) )&lt;br /&gt;{&lt;br /&gt;    Node otherNode = rel.getEndNode();&lt;br /&gt;    // Here goes your code to make use of otherNode.&lt;br /&gt;    // You can aggregate it or whatever you want to do.&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;What we are doing here is to fetch all the outgoing relationships and then get the node at the other end of the relationship. In Neo4j all relationships between nodes are typed, and as seen from both the image above and the code, a &lt;code&gt;KNOWS&lt;/code&gt; relationship type was used in this case. The relationship types are explained on the &lt;a href="http://api.neo4j.org/current/org/neo4j/api/core/RelationshipType.html"&gt;&lt;code&gt;RelationshipType&lt;/code&gt;&lt;/a&gt; page of the &lt;a href="http://api.neo4j.org/current/"&gt;Neo4j API reference&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;To following image shows &lt;code&gt;node1&lt;/code&gt; and all the nodes that are directly connected to it. When following all outgoing relationships, the result will be a single node, namley &lt;code&gt;node3&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_sm_3KdSgQMg/Sq-Ir-VSX1I/AAAAAAAAAE0/PrQDycnMSXg/s1600-h/socnet-connected-directed.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 276px;" src="http://3.bp.blogspot.com/_sm_3KdSgQMg/Sq-Ir-VSX1I/AAAAAAAAAE0/PrQDycnMSXg/s400/socnet-connected-directed.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5381670368779067218" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Next it's time to do the same thing again but using undirected relationships. Both Neo4j and the model in Alberton's article store the relationships as directed but then you can retrieve them in a different way to ignore their direction. Here's how to do this using Neo4j:&lt;/p&gt;&lt;pre class="brush: java"&gt;for ( Relationship rel : node.getRelationships( RelationshipTypes.KNOWS, Direction.BOTH ) )&lt;br /&gt;{&lt;br /&gt;    Node otherNode = rel.getOtherNode( node );&lt;br /&gt;    // Make use of otherNode here ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Did you spot the difference? Where the previous code had &lt;code&gt;Direction.OUTGOING&lt;/code&gt; we know have &lt;code&gt;Direction.BOTH&lt;/code&gt;. For those of you who are curious now: yes, there's &lt;code&gt;Direction.INCOMING&lt;/code&gt; as well.&lt;/p&gt;&lt;p&gt;When viewed with a perspective that ignores directions, the whole graph looks like this::&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_sm_3KdSgQMg/Sq-JD9TjSPI/AAAAAAAAAE8/MzKRYOmyWbQ/s1600-h/socnet-undirected.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 224px;" src="http://4.bp.blogspot.com/_sm_3KdSgQMg/Sq-JD9TjSPI/AAAAAAAAAE8/MzKRYOmyWbQ/s400/socnet-undirected.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5381670780820211954" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;When running the new code with &lt;code&gt;Direction.BOTH&lt;/code&gt;, all the directly connected nodes will be retrieved irregardless of direction:&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_sm_3KdSgQMg/Sq-JXbcrwLI/AAAAAAAAAFE/fg24zhanM-Q/s1600-h/socnet-conected-undirected.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 272px;" src="http://2.bp.blogspot.com/_sm_3KdSgQMg/Sq-JXbcrwLI/AAAAAAAAAFE/fg24zhanM-Q/s400/socnet-conected-undirected.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5381671115329093810" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Difference graph-based/table-based:&lt;/strong&gt; First, obviously the SQL solution is declarative, while the Neo4j solution is procedural. As we'll see later on there is a declarative API to traverse the node space (graph) in Neo4j as well. Second, changing from directed to undirected relationships almost didn't change the code neccesary at all with the graph database approach, while the relational one requires some changes.&lt;/p&gt;&lt;h2&gt;Transitive closure&lt;/h2&gt;&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Transitive_closure#Graph_theory"&gt;Transitive closures&lt;/a&gt; in the sense Alberton uses it is irrelevant in a graph database context as you have access to the full graph from the beginning. The need for defining a transitive closure over the graph in relational databases is caused by its lack of native support for graph data structures.&lt;/p&gt;&lt;p&gt;What is still of course relevant in the graph database setting is how to find all nodes that are reachable from one node, using directed relationships. So let's see how to do that. As previously we assume the &lt;code&gt;node&lt;/code&gt; variable as input to this piece of code:&lt;/p&gt;&lt;pre class="brush: java"&gt;Traverser traverser = node.traverse(&lt;br /&gt;    Order.BREADTH_FIRST,&lt;br /&gt;    StopEvaluator.END_OF_GRAPH,&lt;br /&gt;    ReturnableEvaluator.ALL_BUT_START_NODE,&lt;br /&gt;    RelationshipTypes.KNOWS,&lt;br /&gt;    Direction.OUTGOING );&lt;br /&gt;for ( Node foundNode : traverser )&lt;br /&gt;{&lt;br /&gt;    final int depth = traverser.currentPosition().depth();&lt;br /&gt;    // Use foundNode and depth to whatever you want.&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;So what's happening in this code? We start out by setting up a traverser. The traverser will use a &lt;a href="http://en.wikipedia.org/wiki/Breadth-first_search"&gt;breadth first algorithm&lt;/a&gt;, so that we can intercept the depth/distance to each of the returned node correctly. The traverser will not stop until the end of the graph and will return all nodes but the start node. It will follow relationships of the &lt;code&gt;KNOWS&lt;/code&gt; type in the outgoing direction. Finally the loop fetches the result from the traverser.&lt;/p&gt;&lt;p&gt;If we for some reason want to do this for all nodes in the graph, we simply feed the code above with all existing nodes. This time we assume having all nodes in our network in the &lt;code&gt;allNodes&lt;/code&gt; variable. It's easy to get them as the &lt;a href="http://api.neo4j.org/current/org/neo4j/api/core/NeoService.html"&gt;&lt;code&gt;Neo Service&lt;/code&gt; API&lt;/a&gt; provides a &lt;a href="http://api.neo4j.org/current/org/neo4j/api/core/NeoService.html#getAllNodes%28%29"&gt;&lt;code&gt;getAllNodes()&lt;/code&gt;&lt;/a&gt; method. What we need to do is just a regular loop:&lt;/p&gt;&lt;pre class="brush: java"&gt;for ( Node node : allNodes )&lt;br /&gt;{&lt;br /&gt;    // perform the traversal for each node here&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;How then to do the same thing but using undirected relationships? I rest assured that readers will have no problems solving this so I leave it as a homework excercise!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Difference graph-based/table-based:&lt;/strong&gt; This time it's less obvious what the SQL actually does; you need a bit of SQL fu to parse that code! The corresponding Neo4j code this time uses a declarative approach, which depicts the wanted result.&lt;/p&gt;&lt;h2&gt;LinkedIn: degrees of separation&lt;/h2&gt;&lt;p&gt;Now it's definitely time to get closer to what a graph database could do for you in an application. In this case we want to know the possible paths from one person in a social network to an other. With those paths at hand we can do things similar to the &lt;em&gt;"How you're connected to N.N."&lt;/em&gt; feature of &lt;a href="http://www.linkedin.com/"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;For a deeper analysis it could be of interest to know all possible paths between two nodes within a limited distance (and not only go for the shortest path), so we will see how that would work. This task could be performed with the low level API of Neo4j, but in this case we will use the &lt;a href="http://components.neo4j.org/graph-algo/"&gt;graph-algo package&lt;/a&gt; instead. Of course a graph database should come with basic graph algorithms included as well! This time we will assume that we (quite obviously) know the &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; nodes and how long paths we are looking for (&lt;code&gt;maxPathLenght&lt;/code&gt;). Let's get to the code:&lt;/p&gt;&lt;pre class="brush: java"&gt;AllSimplePaths simplePaths = new AllSimplePaths( &lt;br /&gt;    startNode,&lt;br /&gt;    endNode,&lt;br /&gt;    maxPathLenght,&lt;br /&gt;    Direction.BOTH,&lt;br /&gt;    RelationshipTypes.KNOWS );&lt;br /&gt;    List&amp;lt;List&amp;lt;Node&amp;gt;&amp;gt; pathsAsNodes = simplePaths.getPathsAsNodes();&lt;br /&gt;    // Use pathsAsNodes in your application.&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Do you want to sort the paths by distance (a.k.a. lenght of the paths)? Then add this code:&lt;pre class="brush: java"&gt;Collections.sort( pathsAsNodes, new Comparator&amp;lt;List&amp;lt;Node&amp;gt;&amp;gt;()&lt;br /&gt;{&lt;br /&gt;    public int compare( final List&amp;lt;Node&amp;gt; left, final List&amp;lt;Node&amp;gt; right )&lt;br /&gt;    {&lt;br /&gt;        return left.size() - right.size();&lt;br /&gt;    }&lt;br /&gt;} );&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;When looking for paths from &lt;code&gt;node1&lt;/code&gt; to &lt;code&gt;node6&lt;/code&gt; using undirected relationships all nodes but &lt;code&gt;node7&lt;/code&gt; will be part of at least one path:&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_sm_3KdSgQMg/Sq-JlNWb-cI/AAAAAAAAAFM/nKltC9sSoJE/s1600-h/socnet-degrees-undirected.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 192px;" src="http://1.bp.blogspot.com/_sm_3KdSgQMg/Sq-JlNWb-cI/AAAAAAAAAFM/nKltC9sSoJE/s400/socnet-degrees-undirected.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5381671352062966210" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;If we for some reason use directed relationships, the result will be found among the nodes that are colored yellow in this graph:&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_sm_3KdSgQMg/Sq-KA9fbKfI/AAAAAAAAAFc/MwIMdEgrgPA/s1600-h/socnet-degrees-directed.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 195px;" src="http://4.bp.blogspot.com/_sm_3KdSgQMg/Sq-KA9fbKfI/AAAAAAAAAFc/MwIMdEgrgPA/s400/socnet-degrees-directed.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5381671828842031602" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Difference graph-based/table-based:&lt;/strong&gt; In this case you could argue that it's not a fair comparison, since a relational database can't ship with built-in functions for such specific things as finding paths in a graph. There's some validity to that. But that's also my point: graphs are, as Alberton and &lt;a href="http://stackoverflow.com/questions/703999/what-are-some-examples-of-problems-that-are-best-solved-with-graphs"&gt;Google&lt;/a&gt; &lt;a href="http://googleresearch.blogspot.com/2009/06/large-scale-graph-computing-at-google.html"&gt;say&lt;/a&gt;, ubiquitous these days and no longer a narrow special case. In an increasingly connected world, a graph database many times brings a lot more functionality and performance to the table -- pun intended! -- than a relational system designed for the payroll systems of the 70s.&lt;/p&gt;&lt;h2&gt;Facebook: you might also know&lt;/h2&gt;&lt;p&gt;Our last example will require some more complexity to solve. But on the other hand I regard it as the most fun and rewarding piece. The challenge this time is to traverse into friends of friends (or even deeper) and find people with something in common. Based on this we can distill someone the user might know, or could be interested in knowing. The persons in our social network all have different values for two features, &lt;code&gt;feat1&lt;/code&gt; and &lt;code&gt;feat2&lt;/code&gt;. The idea of the solution presented here is to keep track of the features that are common in each branch of the traversal and to stop when there is nothing in common any more or the maximum distance has been reached. To do this we use recursion (which was never a problem in graph databases, unlike in relational database systems). Before we start to recurse, we have to set some things up:&lt;/p&gt;&lt;pre class="brush: java"&gt;class YouMightKnow&lt;br /&gt;{&lt;br /&gt;    List&amp;lt;List&amp;lt;Node&amp;gt;&amp;gt; result = new ArrayList&amp;lt;List&amp;lt;Node&amp;gt;&amp;gt;();&lt;br /&gt;    int maxDistance;&lt;br /&gt;    Set&amp;lt;Node&amp;gt; buddies = new HashSet&amp;lt;Node&amp;gt;();&lt;br /&gt;&lt;br /&gt;    public YouMightKnow( Node node, String[] features, int maxDistance )&lt;br /&gt;    {&lt;br /&gt;        this.maxDistance = maxDistance;&lt;br /&gt;        for ( Relationship rel : node.getRelationships( RelationshipTypes.KNOWS ) )&lt;br /&gt;        {&lt;br /&gt;            buddies.add( rel.getOtherNode( node ) );&lt;br /&gt;        }&lt;br /&gt;        findFriends( node, Arrays.asList( new Node[] { node } ), Arrays.asList( features ), 1 );&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;features&lt;/code&gt; parameter contains the names of the features we want to check. As all features of course matches at the starting point, we can send them in as the &lt;code&gt;matches&lt;/code&gt; list. To make sure we don't suggest people who are already &lt;code&gt;buddies&lt;/code&gt; we keep track of those in a &lt;code&gt;set&lt;/code&gt;. That's all we need to prepare, so off we go to the recursion! It's initially fed with the root node and path to start from, together with the list of the matching features and finally the current distance. Here's how things continue from there:&lt;/p&gt;&lt;pre class="brush: java"&gt;    void findFriends( Node rootNode, List&amp;lt;Node&amp;gt; path, List&amp;lt;String&amp;gt; matches, int depth )&lt;br /&gt;    {&lt;br /&gt;        for ( Relationship rel : rootNode.getRelationships( RelationshipTypes.KNOWS ) )&lt;br /&gt;        {&lt;br /&gt;            Node node = rel.getOtherNode( rootNode );&lt;br /&gt;            if ( (depth &amp;gt; 1 &amp;&amp; buddies.contains( node )) || path.contains( node ) )&lt;br /&gt;            {&lt;br /&gt;                continue;&lt;br /&gt;            }&lt;br /&gt;            List&amp;lt;String&amp;gt; newMatches = new ArrayList&amp;lt;String&amp;gt;();&lt;br /&gt;            for ( String match : matches )&lt;br /&gt;            {&lt;br /&gt;                if ( node.getProperty( match ).equals( rootNode.getProperty( match ) ) )&lt;br /&gt;                {&lt;br /&gt;                    newMatches.add( match );&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            if ( newMatches.size() &amp;gt; 0 )&lt;br /&gt;            {&lt;br /&gt;                List&amp;lt;Node&amp;gt; newPath = new ArrayList&amp;lt;Node&amp;gt;( path );&lt;br /&gt;                newPath.add( node );&lt;br /&gt;                if ( depth &amp;gt; 1 )&lt;br /&gt;                {&lt;br /&gt;                    result.add( newPath );&lt;br /&gt;                }&lt;br /&gt;                if ( depth != maxDistance )&lt;br /&gt;                {&lt;br /&gt;                    findFriends( node, newPath, newMatches, depth + 1 );&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Now there's a few things we need to think about to get this code right. It's not hard if you keep the network structure in your mind. To begin with there are some nodes we have to avoid. As soon as we have passed by (&lt;code&gt;depth &amp;gt; 1&lt;/code&gt;) the &lt;code&gt;buddies&lt;/code&gt;, we don't want to meet them again. We also want to avoid nodes which are already contained in the path we are investigating, thus avoiding cycles in the graph.&lt;/p&gt;&lt;p&gt;When we know we are looking at the right nodes it's time to compare their features. We only look at the features that are matching everyone in the path behind us, so the &lt;code&gt;newMatches&lt;/code&gt; list will get shorter than the &lt;code&gt;matches&lt;/code&gt; list if one or more features don't match any more. If there are no &lt;code&gt;newMatches&lt;/code&gt; we're finished with this branch. Otherwise we construct a &lt;code&gt;newPath&lt;/code&gt;. Then we have to make sure not to add &lt;code&gt;buddies&lt;/code&gt; to the &lt;code&gt;result&lt;/code&gt; and to stop recursing when the &lt;code&gt;maxDistance&lt;/code&gt; has been reached.&lt;/p&gt;&lt;p&gt;Finally, this is how to use the class:&lt;/p&gt;&lt;pre class="brush: java"&gt;String[] features = new String[] { "feat1", "feat2" };&lt;br /&gt;YouMightKnow mightKnow = new YouMightKnow( node5, features, 2 );&lt;br /&gt;// get result from mightKnow.result&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The graphical view of this problem looks like this, when searching for "might-know" nodes of &lt;code&gt;node5&lt;/code&gt;:&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_sm_3KdSgQMg/Sq-KNiBsFvI/AAAAAAAAAFk/wTf7UBBMDrk/s1600-h/socnet-mightknow.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 262px;" src="http://4.bp.blogspot.com/_sm_3KdSgQMg/Sq-KNiBsFvI/AAAAAAAAAFk/wTf7UBBMDrk/s400/socnet-mightknow.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5381672044807853810" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;If you would like to do something more advanced it would be a small step to add in you own feature matching operations instead of the simple &lt;code&gt;equals()&lt;/code&gt; method used in this example.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Difference graph-based/table-based:&lt;/strong&gt; If you compare the code, you'll note that the graph database code is more intuitive. This is because it works with abstractions (nodes, relationships etc.) that fit the domain better. But I think the most important difference in this case appears when it's time to evolve the code. How do you change the traversal depth in the SQL solution? How to change the traversal depth dynamically depending on facts found in the attributes/features?&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;It should be noted that the examples above are all very trivial. When dealing with real-world problems differences that may seem small from the tiny code examples could prove to have a strong impact. Also, I didn't mention performance so far, but in many cases this could be the main reason to move graph data to a native graph database.&lt;/p&gt;&lt;p&gt;What is actually the root cause of the differences between relational databases and graph databases outlined in this article? It lies in a fundamental difference in design of the underlying data models. The relational model is based on the assumption that database records are what primarily matters while relationships between records come second place.&lt;/p&gt;&lt;p&gt;Graph databases instead assume that the relationships are as important as the records. This difference has numerous consequences for ease of use as well as for performance. A table-based system makes a good fit for static and simple data structures, while a graph-based fits complex and dynamic data better. What actually matters in your data? Think about it!&lt;/p&gt;&lt;h2&gt;Further reading&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Full source code of all the examples is found at &lt;a href="https://svn.neo4j.org/examples/socnet/trunk/"&gt;https://svn.neo4j.org/examples/socnet/trunk/&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;The starting point to learn how to use Neo4j: the &lt;a href="http://wiki.neo4j.org/content/Main_Page"&gt;Neo4j Wiki&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Additional components for Neo4j are found at the &lt;a href="http://components.neo4j.org/"&gt;Neo4j Component site&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Update 2009-09-21: &lt;/strong&gt;changes to the you-might-know code and description&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-2897939188649956439?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/2897939188649956439/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=2897939188649956439" title="9 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/2897939188649956439?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/2897939188649956439?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/Pr0AD-V0I28/social-networks-in-database-using-graph.html" title="Social networks in the database: using a graph database" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_sm_3KdSgQMg/Sq-IYSqcw8I/AAAAAAAAAEs/-B-87_4OmXQ/s72-c/socnet-start.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">9</thr:total><feedburner:origLink>http://blog.neo4j.org/2009/09/social-networks-in-database-using-graph.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcHRXk6cSp7ImA9WxJXEkk.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-17104617130445621</id><published>2009-06-06T00:44:00.002+02:00</published><updated>2009-06-06T00:47:14.719+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-06T00:47:14.719+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="buzz" /><category scheme="http://www.blogger.com/atom/ns#" term="semantic web" /><category scheme="http://www.blogger.com/atom/ns#" term="spring" /><title>Community buzz heating up!</title><content type="html">&lt;p&gt;It's been a lot of fun to take part in the &lt;a href="http://neo4j.org/"&gt;Neo4j&lt;/a&gt; community the last few weeks. There's been quite some mentions on &lt;a href="http://search.twitter.com/search?q=neo4j"&gt;Twitter&lt;/a&gt; and increasing contributions to the &lt;a href="http://www.mail-archive.com/user@lists.neo4j.org/info.html"&gt;mailing list&lt;/a&gt;. Among the themes discussed on the mailing list are new features like &lt;a href="http://wiki.neo4j.org/content/Online_Backup"&gt;online backup&lt;/a&gt; and &lt;a href="http://wiki.neo4j.org/content/Batch_Insert"&gt;batch insert&lt;/a&gt;. There was also recently a design thread on &lt;a href="http://www.mail-archive.com/user@lists.neo4j.org/msg01193.html"&gt;how to model entities with versions&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;a href="http://twitter.com/mattiasask"&gt;Mattias Ask&lt;/a&gt; (founder of &lt;a href="http://www.opencauses.org/"&gt;Open Causes&lt;/a&gt;) published the article &lt;a href="http://blog.jayway.com/2009/05/26/spring-and-load-time-weaving-of-neo4j-based-domain-objects/"&gt;Spring and load-time weaving of Neo4j-based domain objects&lt;/a&gt; which demonstrates how Spring can be used to inject Neo4j nodes into domain objects. Mattias previously wrote the article &lt;a href="http://blog.jayway.com/2008/10/06/neo4j-matches-my-mental-model-of-information/"&gt;Neo4j matches my mental model of information&lt;/a&gt;. In this article he shows an alternative to the domain entity pattern suggested by the Neo4j &lt;a href="http://wiki.neo4j.org/content/Design_Guide"&gt;Design Guide&lt;/a&gt;. Here's how Mattias describes his encounter with Neo4j:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;When I first started looking at Neo4j I was blown away by how precise the graph database structure matched my mental model of information. You have blobs of informations (nodes with properties) that relates to other blobs of information. Perfect!&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;a href="http://www.linkedin.com/pub/sujit-pal/1/a66/198"&gt;Sujit Pal&lt;/a&gt; contributed some &lt;a href="http://en.wikipedia.org/wiki/Semantic_Web"&gt;semantic web&lt;/a&gt; goodness with his article &lt;a href="http://sujitpal.blogspot.com/2009/05/using-neo4j-to-load-and-query-owl.html"&gt;Using Neo4J to load and query OWL ontologies&lt;/a&gt;. The code is part of his &lt;a href="http://jtmt.sourceforge.net/"&gt;Java Text Mining Toolkit&lt;/a&gt; open source project. In the blog post, he shows how to load ontologies using &lt;a href="http://jena.sourceforge.net/"&gt;Jena&lt;/a&gt; for parsing and Neo4j for storage, thus achieving a cleaner solution than the previous one which didn't use a graph database. From his conclusion:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;I have barely scratched the surface of the Jena API with this, but I think I have exercised quite a bit of the Neo4J API, and I was quite impressed with the latter.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;a href="http://twitter.com/Aurametrix"&gt;Irene Gabashvili&lt;/a&gt; commented on Web 3.0 databases in an awesome way:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;This world is too complex to be described by rigid tables. The 40-year old relational technology may be here to stay, but not to rule.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Her &lt;a href="http://aurametrix.blogspot.com/2009/05/building-dynamic-web-30-databases.html"&gt;blog post&lt;/a&gt; goes on to mention graph databases as her favorite amongst the emerging storage alternatives and links to two introductory graph db presentations.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-17104617130445621?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/17104617130445621/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=17104617130445621" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/17104617130445621?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/17104617130445621?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/KzhapayMU1M/community-buzz-heating-up.html" title="Community buzz heating up!" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.neo4j.org/2009/06/community-buzz-heating-up.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYAR3w6fCp7ImA9WxVbGUg.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-6219538518945177246</id><published>2009-04-05T20:37:00.002+02:00</published><updated>2009-04-05T20:45:46.214+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-05T20:45:46.214+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="buzz" /><category scheme="http://www.blogger.com/atom/ns#" term="graphdb" /><category scheme="http://www.blogger.com/atom/ns#" term="graph database" /><category scheme="http://www.blogger.com/atom/ns#" term="future" /><title>The current database debate and graph databases</title><content type="html">&lt;p&gt;During the latest month or so there has been a lot of new energy in the database debate. People are questioning the RDBMS to an extent that we're not used to. &lt;a href="http://www.readwriteweb.com/about_tonybain.php"&gt;Tony Bain&lt;/a&gt; asks: &lt;a href="http://www.readwriteweb.com/archives/is_the_relational_database_doomed.php"&gt;Is the Relational Database Doomed?&lt;/a&gt;. He talks about the simplicity, robustness, flexibility, performance, scalability, and compatibility of databases, where the RDBMS has been "good enough" in all areas in most cases. He goes on to say:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Today, we are in a slightly different situation. For an increasing number of applications, one of these benefits is becoming more and more critical; and while still considered a niche, it is rapidly becoming mainstream, so much so that for an increasing number of database users this requirement is beginning to eclipse others in importance. That benefit is scalability.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;He goes on to describe alternatives to the traditional RDBMS, foremost he gives an overview over key/value databases.&lt;/p&gt;&lt;p&gt;&lt;a href="http://havemacwillblog.com/site-help/about-the-blogger/"&gt;Robin Bloor&lt;/a&gt; &lt;a href="http://havemacwillblog.com/2009/02/13/is-the-relational-database-doomed/"&gt;commented&lt;/a&gt; on the article and among other things comes up with three flaws in &lt;em&gt;the relational data model:&lt;/em&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;it has problems representing common data structures like ordered lists, hierarchies, trees or web page content&lt;/li&gt;&lt;li&gt;it isn't helpful when the data model evolves over time&lt;/li&gt;&lt;li&gt;there's a lack in access semantics, being restricted to the semantics provided by storing items as rows in tables&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;What about the alternatives to RDBMS? Most of the buzz is around &lt;em&gt;key/value stores&lt;/em&gt; and &lt;em&gt;schema-less databases&lt;/em&gt;. Richard Jones wrote the article &lt;a href="http://www.metabrew.com/article/anti-rdbms-a-list-of-distributed-key-value-stores/"&gt;Anti-RDBMS: A list of distributed key-value stores&lt;/a&gt;, listing the most important projects. Going schema-less can look very different, and &lt;a href="http://bret.appspot.com/entry/how-friendfeed-uses-mysql"&gt;the solution FriendFeed uses&lt;/a&gt; may not be the most common way to implement this.&lt;/p&gt;&lt;p&gt;What's then the most important difference between key/value stores and a graph database? Key/value stores lack built-in support for representing relationships between entities, and to capture such relationships is fundamental for data modeling. As &lt;a href="http://neo4j.org/"&gt;Neo4j&lt;/a&gt; supports arbitrary key/value pairs on nodes and relationships it could as well be viewed as a key/value store with full built-in support for relationships.&lt;/p&gt;&lt;p&gt;Because of the advantages of using a graph database and the lack of products available in the market today, companies tend to build their own graph database as underpinning to highly scalable applications. Recently Scott Wheeler of Directed Edge wrote about their in-house database solution: &lt;a href="http://blog.directededge.com/2009/02/27/on-building-a-stupidly-fast-graph-database/"&gt;On Building a Stupidly Fast Graph Database&lt;/a&gt;. In the &lt;a href="http://news.ycombinator.com/item?id=497039"&gt;associated Hacker News discussion&lt;/a&gt; he also mentioned that they tried Neo4j but were disappointed with the performance. This puzzles us since Neo4j is used in production with way larger amounts of data than what's mentioned in the discussion.&lt;/p&gt;&lt;p&gt;In summary, there's an increasing awareness that the 30+ year old relational model may not be optimal for a lot use cases that we as developers encounter today. It's great to see that the community is seriously starting to tackle the challenges of efficiently handling information in the 21st century!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-6219538518945177246?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/6219538518945177246/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=6219538518945177246" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/6219538518945177246?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/6219538518945177246?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/9HVvsLCvOEs/current-database-debate-and-graph.html" title="The current database debate and graph databases" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">8</thr:total><feedburner:origLink>http://blog.neo4j.org/2009/04/current-database-debate-and-graph.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cAQH86eCp7ImA9WxVXGUU.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-6350449191201947137</id><published>2009-02-18T19:42:00.008+01:00</published><updated>2009-02-18T20:24:01.110+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-18T20:24:01.110+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="buzz" /><category scheme="http://www.blogger.com/atom/ns#" term="graphdb" /><category scheme="http://www.blogger.com/atom/ns#" term="graph database" /><title>The most important algorithm</title><content type="html">&lt;p&gt;Danny Nieuwegein wrote in the blog post &lt;a href="http://tastyimportant.blogspot.com/2009/02/persistency-solution-decision-algorithm.html"&gt;Persistency solution decision algorithm&lt;/a&gt; about his strategy for picking a persistence solution:&lt;/p&gt;&lt;pre class="brush: plain"&gt;&lt;br /&gt;IF rdbms is already in use THEN&lt;br /&gt;  IF problem is trivial THEN&lt;br /&gt;     Spring JDBC&lt;br /&gt;  ELSE&lt;br /&gt;     iBATIS&lt;br /&gt;ELSE&lt;br /&gt;  a graph DB&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;He also gives some thoughts on the problems with object-relational mapping as well. Last but not least &lt;a href="http://neo4j.org/"&gt;neo4j&lt;/a&gt; gets mentioned. It's really nice to see that developers are starting to think about using a graph database!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-6350449191201947137?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/6350449191201947137/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=6350449191201947137" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/6350449191201947137?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/6350449191201947137?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/mPIAEdBVFWY/most-important-algorithm.html" title="The most important algorithm" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.neo4j.org/2009/02/most-important-algorithm.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU8HRns-eip7ImA9WxVSFUU.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-2715357285111624658</id><published>2009-01-10T11:12:00.004+01:00</published><updated>2009-01-10T11:37:17.552+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-10T11:37:17.552+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="buzz" /><title>What's the buzz?</title><content type="html">&lt;p&gt;Here's what was buzzing around &lt;a href="http://neo4j.org/"&gt;Neo4j&lt;/a&gt; last year on &lt;a href="http://planet.neo4j.org/"&gt;planet.neo4j.org&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_sm_3KdSgQMg/SWh2IaiJc8I/AAAAAAAAABc/LmLI6kzNrLU/s1600-h/neo4j-planet-wordle.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 289px;" src="http://1.bp.blogspot.com/_sm_3KdSgQMg/SWh2IaiJc8I/AAAAAAAAABc/LmLI6kzNrLU/s400/neo4j-planet-wordle.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5289607649280226242" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-2715357285111624658?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/2715357285111624658/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=2715357285111624658" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/2715357285111624658?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/2715357285111624658?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/2eDOeaqF-pU/whats-buzz.html" title="What's the buzz?" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_sm_3KdSgQMg/SWh2IaiJc8I/AAAAAAAAABc/LmLI6kzNrLU/s72-c/neo4j-planet-wordle.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.neo4j.org/2009/01/whats-buzz.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE4DRHY-fyp7ImA9WxVSE0o.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-8896724955154753633</id><published>2009-01-07T13:11:00.007+01:00</published><updated>2009-01-08T01:02:55.857+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-08T01:02:55.857+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="graph database" /><category scheme="http://www.blogger.com/atom/ns#" term="future" /><title>Future of databases</title><content type="html">&lt;p&gt;&lt;a href="http://www.kleineikenscheidt.de/stefan/about"&gt;Stefan Kleineikenscheidt&lt;/a&gt; wrote a &lt;a href="http://www.kleineikenscheidt.de/stefan/archives/2009/01/2009-databases-and-persistence.html"&gt;short entry&lt;/a&gt; on his thoughts/wishes for databases in 2009. This is part the future according to him:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Non-relational databases will become more popular this year. Examples include document oriented data stores or as graphs databases.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;It seems quite clear that &lt;a href="http://stackoverflow.com/questions/418146/ideas-on-this-alternative-to-orm-rdbms"&gt;developers&lt;/a&gt; &lt;a href="http://stackoverflow.com/questions/51027/database-system-that-is-not-relational"&gt;want&lt;/a&gt; &lt;a href="http://stackoverflow.com/questions/282783/the-next-gen-databases"&gt;alternatives&lt;/a&gt; to tradtitional RDBMS, either as a replacement or a complement.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-8896724955154753633?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/8896724955154753633/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=8896724955154753633" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/8896724955154753633?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/8896724955154753633?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/X9OFchP_UBE/future-of-databases.html" title="Future of databases" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.neo4j.org/2009/01/future-of-databases.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkMGRXY6eCp7ImA9WxVXE0g.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-8452521155995515817</id><published>2008-12-10T16:28:00.005+01:00</published><updated>2009-02-11T12:07:04.810+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-11T12:07:04.810+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="jruby" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="release" /><title>Neo4j.rb version 0.0.7: Rails support</title><content type="html">&lt;p&gt;&lt;a href="http://twitter.com/ronge"&gt;Andreas Ronge&lt;/a&gt; just released version 0.0.7 of Neo4j.rb. See the &lt;a href="http://github.com/andreasronge/neo4j/tree/master"&gt;project page&lt;/a&gt; for more information. Highlights from the &lt;a href="http://github.com/andreasronge/neo4j/tree/master/CHANGELOG"&gt;changelog&lt;/a&gt;: added value object stuff to support &lt;a href="http://www.rubyonrails.org/"&gt;Rails&lt;/a&gt;, made the neo4j engine start and stop automagically.&lt;/p&gt;&lt;p&gt;Neo4j.rb can now be used as a complement or replacement for ActiveRecord in Ruby on Rails. All what is needed is to add the neo4j gem in the rails config/environment.rb file.&lt;/p&gt;&lt;p&gt;Here is an example how to use a Neo4j.rb model in a rails controller:&lt;/p&gt;&lt;pre class="brush: ruby"&gt;   def new&lt;br /&gt;     # creates a empty value object from the node class:&lt;br /&gt;     @movie = Movie.value_object.new&lt;br /&gt;   end&lt;br /&gt;&lt;br /&gt;   def create&lt;br /&gt;     @movie = Movie.new&lt;br /&gt;     # update the new movie node &lt;br /&gt;     # by using the request parameters&lt;br /&gt;     @movie.update(params[:id])&lt;br /&gt;   end&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-8452521155995515817?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/8452521155995515817/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=8452521155995515817" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/8452521155995515817?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/8452521155995515817?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/F424z8ZwOoA/neo4jrb-version-007-rails-support.html" title="Neo4j.rb version 0.0.7: Rails support" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.neo4j.org/2008/12/neo4jrb-version-007-rails-support.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cMSHY7eSp7ImA9WxRbGUw.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-8281377492173064183</id><published>2008-12-08T11:29:00.007+01:00</published><updated>2008-12-10T14:18:09.801+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-10T14:18:09.801+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><category scheme="http://www.blogger.com/atom/ns#" term="bindings" /><title>Neo4j wrapper for Clojure</title><content type="html">&lt;p&gt;Julian Morrison has started to develop a &lt;a href="http://github.com/JulianMorrison/neo4j-clojure/tree/master"&gt;wrapper around Neo4j&lt;/a&gt; for &lt;a href="http://clojure.org/"&gt;Clojure&lt;/a&gt;, a Lisp dialect running on the JVM. Here's how the code using the wrapper can look:&lt;/p&gt;&lt;p&gt;&lt;pre class="prettyprint lang-lisp" style="font-family: Consolas, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;(use 'neo4j)&lt;br /&gt;&lt;br /&gt;(with-neo &amp;quot;test&amp;quot;&lt;br /&gt;  (tx&lt;br /&gt;    (let [c (new-node) b (new-node)]&lt;br /&gt;      (relate (top-node) :customers c)&lt;br /&gt;      (relate c :customer b)&lt;br /&gt;      (.setProperty b &amp;quot;name&amp;quot; &amp;quot;Bob&amp;quot;)&lt;br /&gt;      (success))))&lt;br /&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;The neo4j-clojure wrapper library was announced in &lt;a href="http://groups.google.com/group/clojure/browse_thread/thread/10027c09e419bf72"&gt;this thread&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-8281377492173064183?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/8281377492173064183/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=8281377492173064183" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/8281377492173064183?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/8281377492173064183?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/eHBGcHFz614/neo4j-wrapper-for-clojure.html" title="Neo4j wrapper for Clojure" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.neo4j.org/2008/12/neo4j-wrapper-for-clojure.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8GQ3wzfSp7ImA9WxRbF0o.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-2032341756554914761</id><published>2008-12-08T10:58:00.007+01:00</published><updated>2008-12-09T00:27:02.285+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-09T00:27:02.285+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="maven" /><category scheme="http://www.blogger.com/atom/ns#" term="groovy" /><title>Simplified Groovy + Neo4j setup</title><content type="html">&lt;p&gt;&lt;a href="http://twitter.com/stig_lau"&gt;Stig Lau&lt;/a&gt; wrote on using &lt;a href="http://stigl.wordpress.com/2008/12/06/groovy-does-neo4j-thanks-to-maven-simplicity/"&gt;Groovy, Neo4j and Maven&lt;/a&gt; together.&lt;/p&gt;&lt;p&gt;The result is a Groovy demo on top of Neo4j, distributed as a Maven &lt;a href="http://books.sonatype.com/maven-book/reference/archetypes.html"&gt;archetype&lt;/a&gt;. Setting it up on your machine is a single Maven command. Stig concludes:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Groovy just might have a nice syntax for writing the data-entries. However, I didn’t get it up and running as proposed, and therefore I am quite happy with getting a demo up and running on Groovy, and am passing the task of making the proposition work to Guillaume and the Neo4J team.&lt;/p&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-2032341756554914761?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/2032341756554914761/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=2032341756554914761" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/2032341756554914761?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/2032341756554914761?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/dvSKO2ANztw/simplified-groovy-neo4j-setup.html" title="Simplified Groovy + Neo4j setup" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.neo4j.org/2008/12/simplified-groovy-neo4j-setup.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck4FRnk-eSp7ImA9WxRbFE4.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-430023298635160084</id><published>2008-12-04T10:35:00.010+01:00</published><updated>2008-12-04T23:48:37.751+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-04T23:48:37.751+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="django" /><category scheme="http://www.blogger.com/atom/ns#" term="rubymanor" /><category scheme="http://www.blogger.com/atom/ns#" term="groovy" /><category scheme="http://www.blogger.com/atom/ns#" term="bindings" /><title>How Groovy is Neo4j?</title><content type="html">&lt;p&gt;After hearing about Neo4j at &lt;a href="http://rubymanor.org/"&gt;RubyManor&lt;/a&gt; Robert Rees tried using it from Groovy and experienced some &lt;a href="http://rrees.wordpress.com/2008/12/03/playing-around-with-neo4j-and-groovy/"&gt;problems getting started&lt;/a&gt;. This was &lt;a href="http://www.mail-archive.com/user@lists.neo4j.org/msg00901.html"&gt;discussed&lt;/a&gt; on the Neo4j mailinglist as well. Topics mentioned are the packaging of Neo4j in multiple jar files, using transactions, the Neo4j API and the need for explicit shutdown.&lt;/p&gt;&lt;p&gt;Reading Emil's QCon &lt;a href="http://www.slideshare.net/emileifrem/neo4j-presentation-at-qcon-sf-2008-presentation"&gt;slides&lt;/a&gt; &lt;a href="http://glaforge.free.fr/weblog/"&gt;Guillame Laforge&lt;/a&gt;, project lead of the &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt; language, got interested in how to bring in some Groovyisms to Neo4j. This topic got &lt;a href="http://www.mail-archive.com/user@lists.neo4j.org/msg00892.html"&gt;discussed&lt;/a&gt; on the mailing list, with input from the people working on bindings for Python and Ruby. One more topic that surfaced was to use Neo4j as a &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt; backend.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-430023298635160084?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/430023298635160084/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=430023298635160084" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/430023298635160084?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/430023298635160084?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/JNYAg31BwzQ/how-groovy-is-neo4j.html" title="How Groovy is Neo4j?" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.neo4j.org/2008/12/how-groovy-is-neo4j.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQER306eip7ImA9WxRbE0k.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-3972299487317069211</id><published>2008-12-03T23:33:00.006+01:00</published><updated>2008-12-03T23:45:06.312+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-03T23:45:06.312+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="jruby" /><category scheme="http://www.blogger.com/atom/ns#" term="release" /><category scheme="http://www.blogger.com/atom/ns#" term="bindings" /><title>Neo4j.rb version 0.0.6 released</title><content type="html">&lt;p&gt;Today &lt;a href="http://twitter.com/ronge"&gt;Andreas Ronge&lt;/a&gt; released version 0.0.6 of Neo4j.rb. See the &lt;a href="http://github.com/andreasronge/neo4j/tree/master"&gt;project page&lt;/a&gt; for more information. Highlights from the &lt;a href="http://github.com/andreasronge/neo4j/tree/master/CHANGELOG"&gt;changelog&lt;/a&gt;: new sort_by method, lazy loading of search results, support for Lucene query language.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-3972299487317069211?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/3972299487317069211/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=3972299487317069211" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/3972299487317069211?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/3972299487317069211?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/IbXw_Oyh8z4/neo4jrb-version-006-released.html" title="Neo4j.rb version 0.0.6 released" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.neo4j.org/2008/12/neo4jrb-version-006-released.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkAHQH06eip7ImA9WxRbEUo.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-4757911496898663538</id><published>2008-12-01T18:58:00.007+01:00</published><updated>2008-12-01T23:32:11.312+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-01T23:32:11.312+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="rubymanor" /><category scheme="http://www.blogger.com/atom/ns#" term="qcon" /><title>QCon and RubyManor roundup</title><content type="html">&lt;p&gt;Recent presentations about Neo4j have created buzz in the community. Here are a few links that we thought were worth highlighting:&lt;/p&gt;&lt;p&gt;The slides from Emil's presentation at &lt;a href="http://qconsf.com"&gt;QCon SF 2008&lt;/a&gt; are online on &lt;a href="http://www.slideshare.net/emileifrem/neo4j-presentation-at-qcon-sf-2008-presentation"&gt;SlideShare&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Age Mooy of &lt;a href="http://www.xebia.com/"&gt;Xebia&lt;/a&gt; writes about his &lt;a href="http://blog.xebia.com/2008/11/25/qcon-san-francisco-2008-impressions/"&gt;QCon impressions&lt;/a&gt; and says:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Alternative storage solutions like CouchDb, AtomServer, and Neo4J are very hot.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;There was also a presentation of &lt;a href="http://github.com/andreasronge/neo4j/tree/master"&gt;neo4j.rb&lt;/a&gt; over at &lt;a href="http://www.rubymanor.org/"&gt;RubyManor&lt;/a&gt; by &lt;a href="http://www.jaikoo.com/pages/about"&gt;Jonathan Conway&lt;/a&gt;. The slides are &lt;a href="http://jaikoo.com/assets/presentations/neo4j.pdf"&gt;online&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Notes from the RubyManor presentation were published by &lt;a href="http://twitter.com/grahamashton"&gt;Graham Ashton&lt;/a&gt; in a &lt;a href="http://effectif.com/2008/11/23/notes-from-the-ruby-manor-part-2"&gt;great blog post&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;It sounds pretty interesting – well worth a look if you’re interested in database technology.&lt;/p&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-4757911496898663538?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/4757911496898663538/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=4757911496898663538" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/4757911496898663538?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/4757911496898663538?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/C3QPm2PPXkY/qcon-and-rubymanor-roundup.html" title="QCon and RubyManor roundup" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.neo4j.org/2008/12/qcon-and-rubymanor-roundup.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUQEQ3c7cSp7ImA9WxRbEUg.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-5363738430373784022</id><published>2008-11-30T09:16:00.010+01:00</published><updated>2008-12-01T18:41:42.909+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-01T18:41:42.909+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="fowler" /><category scheme="http://www.blogger.com/atom/ns#" term="integration" /><category scheme="http://www.blogger.com/atom/ns#" term="qcon" /><title>Fowler on new DBs (and Neo4j)</title><content type="html">&lt;a href="http://www.martinfowler.com/"&gt;Martin Fowler&lt;/a&gt; has a great blog post about the future of databases in &lt;a href="http://martinfowler.com/bliki/DatabaseThaw.html"&gt;DatabaseThaw&lt;/a&gt;.&lt;br /&gt;&lt;blockquote&gt;but perhaps a more important thaw that might be beginning - the longer and deeper freeze in thinking about databases&lt;br /&gt;&lt;br/&gt;...&lt;br/&gt;&lt;br /&gt;As well as this talk, there was a whole track on alternative databases hosted by Kresten Krab Thorup. One of the additional tools mentioned there was Neo4J - a graph (network) database tool that earned some rare praise from Jim Webber.&lt;/blockquote&gt;&lt;br /&gt;Fowler's article concludes that databases need to move closer to applications, and not be the base of integration any more.&lt;br /&gt;&lt;blockquote&gt;If you integrate through HTTP it no longer matters how an application stores its own data, which in turn means an application can choose a data model that makes sense for its own needs.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-5363738430373784022?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/5363738430373784022/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=5363738430373784022" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/5363738430373784022?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/5363738430373784022?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/dz9eEqeCiu0/fowler-on-new-dbs-and-neo4j.html" title="Fowler on new DBs (and Neo4j)" /><author><name>Emil Eifrem</name><uri>http://www.blogger.com/profile/02983279286672964952</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="14235606685657954214" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.neo4j.org/2008/11/fowler-on-new-dbs-and-neo4j.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08MQ3gzeyp7ImA9WxRUFUo.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-1949234266719982479</id><published>2008-11-22T17:39:00.010+01:00</published><updated>2008-11-25T01:11:22.683+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-25T01:11:22.683+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="talks" /><category scheme="http://www.blogger.com/atom/ns#" term="qcon" /><title>Neo4j talk @ QCon SF</title><content type="html">Yesterday &lt;a href="http://qconsf.com/sf2008/presentation/Neo4j+--+the+benefits+of+graph+databases"&gt;Emil&lt;/a&gt; gave a talk at &lt;a href="http://qconsf.com/"&gt;QCon SF&lt;/a&gt;. The &lt;a href="http://www.slideshare.net/emileifrem/neo4j-presentation-at-qcon-sf-2008-presentation"&gt;slides&lt;/a&gt; are online, and there have been comments from &lt;a href="http://twitter.com/pmorelli/status/1017214245"&gt;Peter&lt;/a&gt; &lt;a href="http://twitter.com/pmorelli"&gt;Morelli&lt;/a&gt; of SalesForce:&lt;br /&gt;&lt;blockquote&gt;Graph db talk interesting. Would like to see perf nums. Good speaker. #qcon neo4j&lt;br /&gt;&lt;/blockquote&gt;and &lt;a href="http://twitter.com/tastapod/statuses/1017299319"&gt;Dan&lt;/a&gt; &lt;a href="http://dannorth.net/"&gt;North&lt;/a&gt; of ThoughtWorks:&lt;br /&gt;&lt;blockquote&gt;just been learning about neo4j - a &lt;b&gt;graph&lt;/b&gt; database for java. Looks really rather nice&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-1949234266719982479?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/1949234266719982479/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=1949234266719982479" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/1949234266719982479?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/1949234266719982479?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/uJo_ePCrnR8/neo4j-talk-qcon-sf.html" title="Neo4j talk @ QCon SF" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.neo4j.org/2008/11/neo4j-talk-qcon-sf.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQDQ3g-eyp7ImA9WxRUEk8.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-5897388801043104829</id><published>2008-11-21T00:24:00.010+01:00</published><updated>2008-11-21T01:12:52.653+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-21T01:12:52.653+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="jruby" /><category scheme="http://www.blogger.com/atom/ns#" term="release" /><category scheme="http://www.blogger.com/atom/ns#" term="bindings" /><title>Neo4j.rb version 0.0.5 released</title><content type="html">A few days ago &lt;a href="http://twitter.com/ronge"&gt;Andreas Ronge&lt;/a&gt; released version 0.0.5 of Neo4j.rb. This  is a graph database framework for JRuby built on top of the neo4j Java library. There's short &lt;a href="http://wiki.neo4j.org/content/Ruby"&gt;example code&lt;/a&gt; in the neo4j wiki and &lt;a href="http://github.com/andreasronge/neo4j/tree/master"&gt;downloads and documentation&lt;/a&gt; at github. Highlights from the &lt;a href="http://github.com/andreasronge/neo4j/tree/master/CHANGELOG"&gt;changelog&lt;/a&gt;: now runs on JRuby 1.1.5, better lucene support, more example code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-5897388801043104829?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/5897388801043104829/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=5897388801043104829" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/5897388801043104829?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/5897388801043104829?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/c0X0ckU5_64/neo4jrb-version-005-released.html" title="Neo4j.rb version 0.0.5 released" /><author><name>Anders Nawroth</name><uri>http://www.blogger.com/profile/02538334376288340169</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02361133308408145972" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.neo4j.org/2008/11/neo4jrb-version-005-released.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4CQ3Y_fCp7ImA9WxRUE0Q.&quot;"><id>tag:blogger.com,1999:blog-5194400562660165576.post-9144573048442711589</id><published>2008-11-16T20:23:00.003+01:00</published><updated>2008-11-23T00:52:42.844+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-23T00:52:42.844+01:00</app:edited><title>Neo4j on the Neo FreeRunner</title><content type="html">Hi there,&lt;div&gt;some time ago I tested the &lt;a href="http://www.neo4j.org/"&gt;Neo4j&lt;/a&gt; graph database as a backend to &lt;a href="http://www.qi4j.org/"&gt;Qi4j&lt;/a&gt; on the &lt;a href="http://wiki.openmoko.org/wiki/Neo_FreeRunner"&gt;Neo FreeRunner&lt;/a&gt;. I installed the 2008.09 distribution (Debian and XFCE, OpenJDK or Harmony works, too, but is very slow of course) and FDOM, to get some more goodies onto the system.&lt;/div&gt;&lt;div&gt;In order to get the Neo4j and Java code running at all, you will need to install some for of JVM. In my case, I chose to install classpath, jamvm and for possible GUI use, the GTK-SWT bindings. I installed&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;opkg install classpath jamvm libswt3.4-&lt;em&gt;gtk&lt;/em&gt;-&lt;em&gt;java&lt;br /&gt;&lt;br /&gt;then deployed my .jar neo4j test onto the device via SCP, and voila, starting it brings up the whole database! This even works with Qi4j, although very slow, but in principle this opens up small linux devices for Neo4j!&lt;br /&gt;&lt;/em&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5194400562660165576-9144573048442711589?l=blog.neo4j.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.neo4j.org/feeds/9144573048442711589/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5194400562660165576&amp;postID=9144573048442711589" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/9144573048442711589?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5194400562660165576/posts/default/9144573048442711589?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Neo4jBlog/~3/e7wLMzjK_qs/neo4j-on-neo-freerunner.html" title="Neo4j on the Neo FreeRunner" /><author><name>Peter Neubauer</name><uri>http://www.blogger.com/profile/08648014346248909032</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="03899237397995011553" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.neo4j.org/2008/11/neo4j-on-neo-freerunner.html</feedburner:origLink></entry></feed>
