{"id":31998,"date":"2014-10-24T16:00:57","date_gmt":"2014-10-24T13:00:57","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=31998"},"modified":"2014-10-24T06:45:04","modified_gmt":"2014-10-24T03:45:04","slug":"neo4j-cypher-avoiding-the-eager","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html","title":{"rendered":"Neo4j: Cypher \u2013 Avoiding the Eager"},"content":{"rendered":"<p><figure id=\"attachment_32033\" aria-describedby=\"caption-attachment-32033\" style=\"width: 219px\" class=\"wp-caption alignright\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/10\/neverwhere.jpg\"><img decoding=\"async\" class=\"size-medium wp-image-32033\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/10\/neverwhere-219x300.jpg\" alt=\"Beware of the eager pipe\" width=\"219\" height=\"300\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/10\/neverwhere-219x300.jpg 219w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/10\/neverwhere.jpg 288w\" sizes=\"(max-width: 219px) 100vw, 219px\" \/><\/a><figcaption id=\"caption-attachment-32033\" class=\"wp-caption-text\">Beware of the eager pipe<\/figcaption><\/figure><\/p>\n<p>&nbsp;<br \/>\nAlthough I love how easy Cypher\u2019s <a href=\"http:\/\/neo4j.com\/docs\/stable\/query-load-csv.html\">LOAD CSV<\/a> command makes it to get data into Neo4j, it currently breaks <a href=\"http:\/\/www.faqs.org\/docs\/artu\/ch11s01.html\">the rule of least surprise<\/a> in the way it eagerly loads in all rows for some queries even those using <a href=\"http:\/\/neo4j.com\/docs\/stable\/query-periodic-commit.html\">periodic commit<\/a>.<\/p>\n<p>This is something that my colleague Michael noted in the <a href=\"http:\/\/jexp.de\/blog\/2014\/10\/load-cvs-with-success\/\">second<\/a> of his blog posts explaining <a href=\"http:\/\/jexp.de\/blog\/2014\/06\/load-csv-into-neo4j-quickly-and-successfully\/\">how to use LOAD CSV successfully<\/a>:<\/p>\n<p>&nbsp;<\/p>\n<blockquote>\n<p>The <strong>biggest issue<\/strong> that people ran into, even when following the advice I gave earlier, was that for large imports of more than one million rows, Cypher ran into an out-of-memory situation.<\/p>\n<p>That was <strong>not related to commit sizes<\/strong>, so it happened even with PERIODIC COMMIT of small batches.<\/p>\n<\/blockquote>\n<p>I recently spent a few days importing data into Neo4j on a Windows machine with 4GB RAM so I was seeing this problem even earlier than Michael suggested.<\/p>\n<p>Michael explains how to work out whether your query is suffering from unexpected eager evaluation:<\/p>\n<blockquote>\n<p>If you profile that query you see that there is an \u201cEager\u201d step in the query plan.<\/p>\n<p>That is where the \u201cpull in all data\u201d happens.<\/p>\n<\/blockquote>\n<p>You can profile queries by prefixing the word \u2018PROFILE\u2019. You\u2019ll need to run your query in the console of <em>\/webadmin<\/em> in your web browser or with the <a href=\"http:\/\/neo4j.com\/docs\/stable\/shell-starting.html\">Neo4j shell<\/a>.<\/p>\n<p>I did this for my queries and was able to identify query patterns which get evaluated eagerly and in some cases we can work around it.<\/p>\n<p>We\u2019ll use the <a href=\"https:\/\/github.com\/mneedham\/neo4j-northwind\/blob\/master\/data\/customerDb.csv\">Northwind data set<\/a> to demonstrate how the Eager pipe can sneak into our queries but keep in mind that this data set is sufficiently small to not cause issues.<\/p>\n<p>This is what a row in the file looks like:<\/p>\n<pre class=\" brush:bash;wrap-lines:false\">$ head -n 2 data\/customerDb.csv\r\nOrderID,CustomerID,EmployeeID,OrderDate,RequiredDate,ShippedDate,ShipVia,Freight,ShipName,ShipAddress,ShipCity,ShipRegion,ShipPostalCode,ShipCountry,CustomerID,CustomerCompanyName,ContactName,ContactTitle,Address,City,Region,PostalCode,Country,Phone,Fax,EmployeeID,LastName,FirstName,Title,TitleOfCourtesy,BirthDate,HireDate,Address,City,Region,PostalCode,Country,HomePhone,Extension,Photo,Notes,ReportsTo,PhotoPath,OrderID,ProductID,UnitPrice,Quantity,Discount,ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued,SupplierID,SupplierCompanyName,ContactName,ContactTitle,Address,City,Region,PostalCode,Country,Phone,Fax,HomePage,CategoryID,CategoryName,Description,Picture\r\n10248,VINET,5,1996-07-04,1996-08-01,1996-07-16,3,32.38,Vins et alcools Chevalier,59 rue de l'Abbaye,Reims,,51100,France,VINET,Vins et alcools Chevalier,Paul Henriot,Accounting Manager,59 rue de l'Abbaye,Reims,,51100,France,26.47.15.10,26.47.15.11,5,Buchanan,Steven,Sales Manager,Mr.,1955-03-04,1993-10-17,14 Garrett Hill,London,,SW1 8JR,UK,(71) 555-4848,3453,\\x,\"Steven Buchanan graduated from St. Andrews University, Scotland, with a BSC degree in 1976.  Upon joining the company as a sales representative in 1992, he spent 6 months in an orientation program at the Seattle office and then returned to his permanent post in London.  He was promoted to sales manager in March 1993.  Mr. Buchanan has completed the courses \"\"Successful Telemarketing\"\" and \"\"International Sales Management.\"\"  He is fluent in French.\",2,http:\/\/accweb\/emmployees\/buchanan.bmp,10248,11,14,12,0,11,Queso Cabrales,5,4,1 kg pkg.,21,22,30,30,0,5,Cooperativa de Quesos 'Las Cabras',Antonio del Valle Saavedra,Export Administrator,Calle del Rosal 4,Oviedo,Asturias,33007,Spain,(98) 598 76 54,,,4,Dairy Products,Cheeses,\\x<\/pre>\n<h2>MERGE, MERGE, MERGE<\/h2>\n<p>The first thing we want to do is create a node for each employee and each order and then create a relationship between them.<\/p>\n<p>We might start with the following query:<\/p>\n<pre class=\" brush:java;wrap-lines:false\">USING PERIODIC COMMIT 1000\r\nLOAD CSV WITH HEADERS FROM \"file:\/Users\/markneedham\/projects\/neo4j-northwind\/data\/customerDb.csv\" AS row\r\nMERGE (employee:Employee {employeeId: row.EmployeeID})\r\nMERGE (order:Order {orderId: row.OrderID})\r\nMERGE (employee)-[:SOLD]-&gt;(order)<\/pre>\n<p>This does the job but if we profile the query like so\u2026<\/p>\n<pre class=\" brush:java;wrap-lines:false\">PROFILE LOAD CSV WITH HEADERS FROM \"file:\/Users\/markneedham\/projects\/neo4j-northwind\/data\/customerDb.csv\" AS row\r\nWITH row LIMIT 0\r\nMERGE (employee:Employee {employeeId: row.EmployeeID})\r\nMERGE (order:Order {orderId: row.OrderID})\r\nMERGE (employee)-[:SOLD]-&gt;(order)<\/pre>\n<p>\u2026we\u2019ll notice an \u2018Eager\u2019 lurking on the third line:<\/p>\n<pre class=\" brush:java;wrap-lines:false\">==&gt; +----------------+------+--------+----------------------------------+-----------------------------------------+\r\n==&gt; |       Operator | Rows | DbHits |                      Identifiers |                                   Other |\r\n==&gt; +----------------+------+--------+----------------------------------+-----------------------------------------+\r\n==&gt; |    EmptyResult |    0 |      0 |                                  |                                         |\r\n==&gt; | UpdateGraph(0) |    0 |      0 |    employee, order,   UNNAMED216 |                            MergePattern |\r\n==&gt; |          Eager |    0 |      0 |                                  |                                         |\r\n==&gt; | UpdateGraph(1) |    0 |      0 | employee, employee, order, order | MergeNode; :Employee; MergeNode; :Order |\r\n==&gt; |          Slice |    0 |      0 |                                  |                            {  AUTOINT0} |\r\n==&gt; |        LoadCSV |    1 |      0 |                              row |                                         |\r\n==&gt; +----------------+------+--------+----------------------------------+-----------------------------------------+<\/pre>\n<p><em>You\u2019ll notice that when we profile each query we\u2019re stripping off the periodic commit section and adding a \u2018WITH row LIMIT 0\u2032. This allows us to generate enough of the query plan to identify the \u2018Eager\u2019 operator without actually importing any data.<\/em><div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<p>We want to split that query into two so it can be processed in a non eager manner:<\/p>\n<pre class=\" brush:java;wrap-lines:false\">USING PERIODIC COMMIT 1000\r\nLOAD CSV WITH HEADERS FROM \"file:\/Users\/markneedham\/projects\/neo4j-northwind\/data\/customerDb.csv\" AS row\r\nWITH row LIMIT 0\r\nMERGE (employee:Employee {employeeId: row.EmployeeID})\r\nMERGE (order:Order {orderId: row.OrderID})<\/pre>\n<pre class=\" brush:java;wrap-lines:false\">==&gt; +-------------+------+--------+----------------------------------+-----------------------------------------+\r\n==&gt; |    Operator | Rows | DbHits |                      Identifiers |                                   Other |\r\n==&gt; +-------------+------+--------+----------------------------------+-----------------------------------------+\r\n==&gt; | EmptyResult |    0 |      0 |                                  |                                         |\r\n==&gt; | UpdateGraph |    0 |      0 | employee, employee, order, order | MergeNode; :Employee; MergeNode; :Order |\r\n==&gt; |       Slice |    0 |      0 |                                  |                            {  AUTOINT0} |\r\n==&gt; |     LoadCSV |    1 |      0 |                              row |                                         |\r\n==&gt; +-------------+------+--------+----------------------------------+-----------------------------------------+<\/pre>\n<p>Now that we\u2019ve created the employees and orders we can join them together:<\/p>\n<pre class=\" brush:java;wrap-lines:false\">USING PERIODIC COMMIT 1000\r\nLOAD CSV WITH HEADERS FROM \"file:\/Users\/markneedham\/projects\/neo4j-northwind\/data\/customerDb.csv\" AS row\r\nMATCH (employee:Employee {employeeId: row.EmployeeID})\r\nMATCH (order:Order {orderId: row.OrderID})\r\nMERGE (employee)-[:SOLD]-&gt;(order)<\/pre>\n<pre class=\" brush:java;wrap-lines:false\">==&gt; +----------------+------+--------+-------------------------------+-----------------------------------------------------------+\r\n==&gt; |       Operator | Rows | DbHits |                   Identifiers |                                                     Other |\r\n==&gt; +----------------+------+--------+-------------------------------+-----------------------------------------------------------+\r\n==&gt; |    EmptyResult |    0 |      0 |                               |                                                           |\r\n==&gt; |    UpdateGraph |    0 |      0 | employee, order,   UNNAMED216 |                                              MergePattern |\r\n==&gt; |      Filter(0) |    0 |      0 |                               |          Property(order,orderId) == Property(row,OrderID) |\r\n==&gt; | NodeByLabel(0) |    0 |      0 |                  order, order |                                                    :Order |\r\n==&gt; |      Filter(1) |    0 |      0 |                               | Property(employee,employeeId) == Property(row,EmployeeID) |\r\n==&gt; | NodeByLabel(1) |    0 |      0 |            employee, employee |                                                 :Employee |\r\n==&gt; |          Slice |    0 |      0 |                               |                                              {  AUTOINT0} |\r\n==&gt; |        LoadCSV |    1 |      0 |                           row |                                                           |\r\n==&gt; +----------------+------+--------+-------------------------------+-----------------------------------------------------------+<\/pre>\n<p>Not an Eager in sight!<\/p>\n<h2>MATCH, MATCH, MATCH, MERGE, MERGE<\/h2>\n<p>If we fast forward a few steps we may now have refactored our import script to the point where we create our nodes in one query and the relationships in another query.<\/p>\n<p>Our create query works as expected:<\/p>\n<pre class=\" brush:java;wrap-lines:false\">USING PERIODIC COMMIT 1000\r\nLOAD CSV WITH HEADERS FROM \"file:\/Users\/markneedham\/projects\/neo4j-northwind\/data\/customerDb.csv\" AS row\r\nMERGE (employee:Employee {employeeId: row.EmployeeID})\r\nMERGE (order:Order {orderId: row.OrderID})\r\nMERGE (product:Product {productId: row.ProductID})<\/pre>\n<pre class=\" brush:bash;wrap-lines:false\">==&gt; +-------------+------+--------+----------------------------------------------------+--------------------------------------------------------------+\r\n==&gt; |    Operator | Rows | DbHits |                                        Identifiers |                                                        Other |\r\n==&gt; +-------------+------+--------+----------------------------------------------------+--------------------------------------------------------------+\r\n==&gt; | EmptyResult |    0 |      0 |                                                    |                                                              |\r\n==&gt; | UpdateGraph |    0 |      0 | employee, employee, order, order, product, product | MergeNode; :Employee; MergeNode; :Order; MergeNode; :Product |\r\n==&gt; |       Slice |    0 |      0 |                                                    |                                                 {  AUTOINT0} |\r\n==&gt; |     LoadCSV |    1 |      0 |                                                row |                                                              |\r\n==&gt; +-------------+------+--------+----------------------------------------------------+------------------------------------------------------------<\/pre>\n<p>We\u2019ve now got employees, products and orders in the graph. Now let\u2019s create relationships between the trio:<\/p>\n<pre class=\" brush:java;wrap-lines:false\">USING PERIODIC COMMIT 1000\r\nLOAD CSV WITH HEADERS FROM \"file:\/Users\/markneedham\/projects\/neo4j-northwind\/data\/customerDb.csv\" AS row\r\nMATCH (employee:Employee {employeeId: row.EmployeeID})\r\nMATCH (order:Order {orderId: row.OrderID})\r\nMATCH (product:Product {productId: row.ProductID})\r\nMERGE (employee)-[:SOLD]-&gt;(order)\r\nMERGE (order)-[:PRODUCT]-&gt;(product)<\/pre>\n<p>If we profile that we\u2019ll notice Eager has sneaked in again!<\/p>\n<pre class=\" brush:bash;wrap-lines:false\">==&gt; +----------------+------+--------+-------------------------------+-----------------------------------------------------------+\r\n==&gt; |       Operator | Rows | DbHits |                   Identifiers |                                                     Other |\r\n==&gt; +----------------+------+--------+-------------------------------+-----------------------------------------------------------+\r\n==&gt; |    EmptyResult |    0 |      0 |                               |                                                           |\r\n==&gt; | UpdateGraph(0) |    0 |      0 |  order, product,   UNNAMED318 |                                              MergePattern |\r\n==&gt; |          Eager |    0 |      0 |                               |                                                           |\r\n==&gt; | UpdateGraph(1) |    0 |      0 | employee, order,   UNNAMED287 |                                              MergePattern |\r\n==&gt; |      Filter(0) |    0 |      0 |                               |    Property(product,productId) == Property(row,ProductID) |\r\n==&gt; | NodeByLabel(0) |    0 |      0 |              product, product |                                                  :Product |\r\n==&gt; |      Filter(1) |    0 |      0 |                               |          Property(order,orderId) == Property(row,OrderID) |\r\n==&gt; | NodeByLabel(1) |    0 |      0 |                  order, order |                                                    :Order |\r\n==&gt; |      Filter(2) |    0 |      0 |                               | Property(employee,employeeId) == Property(row,EmployeeID) |\r\n==&gt; | NodeByLabel(2) |    0 |      0 |            employee, employee |                                                 :Employee |\r\n==&gt; |          Slice |    0 |      0 |                               |                                              {  AUTOINT0} |\r\n==&gt; |        LoadCSV |    1 |      0 |                           row |                                                           |\r\n==&gt; +----------------+------+--------+-------------------------------+-----------------------------------------------------------+<\/pre>\n<p>In this case the Eager happens on our second call to MERGE as Michael identified in his post:<\/p>\n<blockquote>\n<p>The issue is that within a single Cypher statement you have to isolate changes that affect matches further on, e.g. when you CREATE nodes with a label that are suddenly matched by a later MATCH or MERGE operation.<\/p>\n<\/blockquote>\n<p>We can work around the problem in this case by having separate queries to create the relationships:<\/p>\n<pre class=\" brush:java;wrap-lines:false\">LOAD CSV WITH HEADERS FROM \"file:\/Users\/markneedham\/projects\/neo4j-northwind\/data\/customerDb.csv\" AS row\r\nMATCH (employee:Employee {employeeId: row.EmployeeID})\r\nMATCH (order:Order {orderId: row.OrderID})\r\nMERGE (employee)-[:SOLD]-&gt;(order)<\/pre>\n<pre class=\" brush:bash;wrap-lines:false\">==&gt; +----------------+------+--------+-------------------------------+-----------------------------------------------------------+\r\n==&gt; |       Operator | Rows | DbHits |                   Identifiers |                                                     Other |\r\n==&gt; +----------------+------+--------+-------------------------------+-----------------------------------------------------------+\r\n==&gt; |    EmptyResult |    0 |      0 |                               |                                                           |\r\n==&gt; |    UpdateGraph |    0 |      0 | employee, order,   UNNAMED236 |                                              MergePattern |\r\n==&gt; |      Filter(0) |    0 |      0 |                               |          Property(order,orderId) == Property(row,OrderID) |\r\n==&gt; | NodeByLabel(0) |    0 |      0 |                  order, order |                                                    :Order |\r\n==&gt; |      Filter(1) |    0 |      0 |                               | Property(employee,employeeId) == Property(row,EmployeeID) |\r\n==&gt; | NodeByLabel(1) |    0 |      0 |            employee, employee |                                                 :Employee |\r\n==&gt; |          Slice |    0 |      0 |                               |                                              {  AUTOINT0} |\r\n==&gt; |        LoadCSV |    1 |      0 |                           row |                                                           |\r\n==&gt; +----------------+------+--------+-------------------------------+-----------------------------------------------------------+<\/pre>\n<pre class=\" brush:java;wrap-lines:false\">USING PERIODIC COMMIT 1000\r\nLOAD CSV WITH HEADERS FROM \"file:\/Users\/markneedham\/projects\/neo4j-northwind\/data\/customerDb.csv\" AS row\r\nMATCH (order:Order {orderId: row.OrderID})\r\nMATCH (product:Product {productId: row.ProductID})\r\nMERGE (order)-[:PRODUCT]-&gt;(product)<\/pre>\n<pre class=\" brush:bash;wrap-lines:false\">==&gt; +----------------+------+--------+------------------------------+--------------------------------------------------------+\r\n==&gt; |       Operator | Rows | DbHits |                  Identifiers |                                                  Other |\r\n==&gt; +----------------+------+--------+------------------------------+--------------------------------------------------------+\r\n==&gt; |    EmptyResult |    0 |      0 |                              |                                                        |\r\n==&gt; |    UpdateGraph |    0 |      0 | order, product,   UNNAMED229 |                                           MergePattern |\r\n==&gt; |      Filter(0) |    0 |      0 |                              | Property(product,productId) == Property(row,ProductID) |\r\n==&gt; | NodeByLabel(0) |    0 |      0 |             product, product |                                               :Product |\r\n==&gt; |      Filter(1) |    0 |      0 |                              |       Property(order,orderId) == Property(row,OrderID) |\r\n==&gt; | NodeByLabel(1) |    0 |      0 |                 order, order |                                                 :Order |\r\n==&gt; |          Slice |    0 |      0 |                              |                                           {  AUTOINT0} |\r\n==&gt; |        LoadCSV |    1 |      0 |                          row |                                                        |\r\n==&gt; +----------------+------+--------+------------------------------+--------------------------------------------------------+<\/pre>\n<h2>MERGE, SET<\/h2>\n<p>I try to make LOAD CSV scripts as idempotent as possible so that if we add more rows or columns of data to our CSV we can rerun the query without having to recreate everything.<\/p>\n<p>This can lead you towards the following pattern where we\u2019re creating suppliers:<\/p>\n<pre class=\" brush:java;wrap-lines:false\">USING PERIODIC COMMIT 1000\r\nLOAD CSV WITH HEADERS FROM \"file:\/Users\/markneedham\/projects\/neo4j-northwind\/data\/customerDb.csv\" AS row\r\nMERGE (supplier:Supplier {supplierId: row.SupplierID})\r\nSET supplier.companyName = row.SupplierCompanyName<\/pre>\n<p>We want to ensure that there\u2019s only one Supplier with that SupplierID but we might be incrementally adding new properties and decide to just replace everything by using the \u2018SET\u2019 command. If we profile that query, the Eager lurks:<\/p>\n<pre class=\" brush:bash\">==&gt; +----------------+------+--------+--------------------+----------------------+\r\n==&gt; |       Operator | Rows | DbHits |        Identifiers |                Other |\r\n==&gt; +----------------+------+--------+--------------------+----------------------+\r\n==&gt; |    EmptyResult |    0 |      0 |                    |                      |\r\n==&gt; | UpdateGraph(0) |    0 |      0 |                    |          PropertySet |\r\n==&gt; |          Eager |    0 |      0 |                    |                      |\r\n==&gt; | UpdateGraph(1) |    0 |      0 | supplier, supplier | MergeNode; :Supplier |\r\n==&gt; |          Slice |    0 |      0 |                    |         {  AUTOINT0} |\r\n==&gt; |        LoadCSV |    1 |      0 |                row |                      |\r\n==&gt; +----------------+------+--------+--------------------+----------------------+<\/pre>\n<p>We can work around this at the cost of a bit of duplication using \u2018ON CREATE SET\u2019 and \u2018ON MATCH SET&#8217;:<\/p>\n<pre class=\" brush:java;wrap-lines:false\">USING PERIODIC COMMIT 1000\r\nLOAD CSV WITH HEADERS FROM \"file:\/Users\/markneedham\/projects\/neo4j-northwind\/data\/customerDb.csv\" AS row\r\nMERGE (supplier:Supplier {supplierId: row.SupplierID})\r\nON CREATE SET supplier.companyName = row.SupplierCompanyName\r\nON MATCH SET supplier.companyName = row.SupplierCompanyName<\/pre>\n<pre class=\" brush:bash\">==&gt; +-------------+------+--------+--------------------+----------------------+\r\n==&gt; |    Operator | Rows | DbHits |        Identifiers |                Other |\r\n==&gt; +-------------+------+--------+--------------------+----------------------+\r\n==&gt; | EmptyResult |    0 |      0 |                    |                      |\r\n==&gt; | UpdateGraph |    0 |      0 | supplier, supplier | MergeNode; :Supplier |\r\n==&gt; |       Slice |    0 |      0 |                    |         {  AUTOINT0} |\r\n==&gt; |     LoadCSV |    1 |      0 |                row |                      |\r\n==&gt; +-------------+------+--------+--------------------+----------------------+<\/pre>\n<p>With the data set I\u2019ve been working with I was able to avoid OutOfMemory exceptions in some cases and reduce the amount of time it took to run the query by a factor of 3 in others.<\/p>\n<p>As time goes on I expect all of these scenarios will be addressed but as of Neo4j 2.1.5 these are the patterns that I\u2019ve identified as being overly eager.<\/p>\n<p>If you know of any others do let me know and I can add them to the post or write a second part.<\/p>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td><span class=\"reference\">Reference: <\/span><\/td>\n<td><a href=\"http:\/\/www.markhneedham.com\/blog\/2014\/10\/23\/neo4j-cypher-avoiding-the-eager\/\">Neo4j: Cypher \u2013 Avoiding the Eager<\/a> from our <a href=\"http:\/\/www.javacodegeeks.com\/jcg\/\">JCG partner<\/a> Mark Needham at the <a href=\"http:\/\/www.markhneedham.com\/blog\/\">Mark Needham Blog<\/a> blog.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Although I love how easy Cypher\u2019s LOAD CSV command makes it to get data into Neo4j, it currently breaks the rule of least surprise in the way it eagerly loads in all rows for some queries even those using periodic commit. This is something that my colleague Michael noted in the second of his &hellip;<\/p>\n","protected":false},"author":134,"featured_media":191,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[349],"class_list":["post-31998","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-neo4j"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Neo4j: Cypher \u2013 Avoiding the Eager<\/title>\n<meta name=\"description\" content=\"&nbsp; Although I love how easy Cypher\u2019s LOAD CSV command makes it to get data into Neo4j, it currently breaks the rule of least surprise in the way it\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Neo4j: Cypher \u2013 Avoiding the Eager\" \/>\n<meta property=\"og:description\" content=\"&nbsp; Although I love how easy Cypher\u2019s LOAD CSV command makes it to get data into Neo4j, it currently breaks the rule of least surprise in the way it\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2014-10-24T13:00:57+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/neo4j-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Mark Needham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Mark Needham\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/10\\\/neo4j-cypher-avoiding-the-eager.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/10\\\/neo4j-cypher-avoiding-the-eager.html\"},\"author\":{\"name\":\"Mark Needham\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/fdb35381baa5059768d6788cfb685313\"},\"headline\":\"Neo4j: Cypher \u2013 Avoiding the Eager\",\"datePublished\":\"2014-10-24T13:00:57+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/10\\\/neo4j-cypher-avoiding-the-eager.html\"},\"wordCount\":808,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/10\\\/neo4j-cypher-avoiding-the-eager.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/neo4j-logo.jpg\",\"keywords\":[\"Neo4j\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/10\\\/neo4j-cypher-avoiding-the-eager.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/10\\\/neo4j-cypher-avoiding-the-eager.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/10\\\/neo4j-cypher-avoiding-the-eager.html\",\"name\":\"Neo4j: Cypher \u2013 Avoiding the Eager\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/10\\\/neo4j-cypher-avoiding-the-eager.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/10\\\/neo4j-cypher-avoiding-the-eager.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/neo4j-logo.jpg\",\"datePublished\":\"2014-10-24T13:00:57+00:00\",\"description\":\"&nbsp; Although I love how easy Cypher\u2019s LOAD CSV command makes it to get data into Neo4j, it currently breaks the rule of least surprise in the way it\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/10\\\/neo4j-cypher-avoiding-the-eager.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/10\\\/neo4j-cypher-avoiding-the-eager.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/10\\\/neo4j-cypher-avoiding-the-eager.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/neo4j-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/neo4j-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/10\\\/neo4j-cypher-avoiding-the-eager.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Neo4j: Cypher \u2013 Avoiding the Eager\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/fdb35381baa5059768d6788cfb685313\",\"name\":\"Mark Needham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5489baed26ce2d932bf951ecfb47afe80bec45d3648c23521d87c83b8f1c3ea9?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5489baed26ce2d932bf951ecfb47afe80bec45d3648c23521d87c83b8f1c3ea9?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5489baed26ce2d932bf951ecfb47afe80bec45d3648c23521d87c83b8f1c3ea9?s=96&d=mm&r=g\",\"caption\":\"Mark Needham\"},\"sameAs\":[\"http:\\\/\\\/www.markhneedham.com\\\/blog\\\/\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/Mark-Needham\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Neo4j: Cypher \u2013 Avoiding the Eager","description":"&nbsp; Although I love how easy Cypher\u2019s LOAD CSV command makes it to get data into Neo4j, it currently breaks the rule of least surprise in the way it","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html","og_locale":"en_US","og_type":"article","og_title":"Neo4j: Cypher \u2013 Avoiding the Eager","og_description":"&nbsp; Although I love how easy Cypher\u2019s LOAD CSV command makes it to get data into Neo4j, it currently breaks the rule of least surprise in the way it","og_url":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2014-10-24T13:00:57+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/neo4j-logo.jpg","type":"image\/jpeg"}],"author":"Mark Needham","twitter_card":"summary_large_image","twitter_creator":"@javacodegeeks","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Mark Needham","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html"},"author":{"name":"Mark Needham","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/fdb35381baa5059768d6788cfb685313"},"headline":"Neo4j: Cypher \u2013 Avoiding the Eager","datePublished":"2014-10-24T13:00:57+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html"},"wordCount":808,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/neo4j-logo.jpg","keywords":["Neo4j"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html","url":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html","name":"Neo4j: Cypher \u2013 Avoiding the Eager","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/neo4j-logo.jpg","datePublished":"2014-10-24T13:00:57+00:00","description":"&nbsp; Although I love how easy Cypher\u2019s LOAD CSV command makes it to get data into Neo4j, it currently breaks the rule of least surprise in the way it","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/neo4j-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/neo4j-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2014\/10\/neo4j-cypher-avoiding-the-eager.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Neo4j: Cypher \u2013 Avoiding the Eager"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/fdb35381baa5059768d6788cfb685313","name":"Mark Needham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/5489baed26ce2d932bf951ecfb47afe80bec45d3648c23521d87c83b8f1c3ea9?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/5489baed26ce2d932bf951ecfb47afe80bec45d3648c23521d87c83b8f1c3ea9?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5489baed26ce2d932bf951ecfb47afe80bec45d3648c23521d87c83b8f1c3ea9?s=96&d=mm&r=g","caption":"Mark Needham"},"sameAs":["http:\/\/www.markhneedham.com\/blog\/"],"url":"https:\/\/www.javacodegeeks.com\/author\/Mark-Needham"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/31998","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/134"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=31998"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/31998\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/191"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=31998"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=31998"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=31998"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}