From 2b2e69a22ced85174932bb122906cbbf193b25f3 Mon Sep 17 00:00:00 2001 From: Jamie Gaskins Date: Sun, 24 Sep 2017 13:51:14 -0400 Subject: [PATCH 1/2] Add response-level identity map When response rows reference the same node or relationship, the response currently returns new object instances for each one. Since they're all part of the same response, it's reasonable to assume they can be the same object, so this identity-map prototype makes that happen, saving a bit of RAM and possibly a bit of CPU time for the conversion from hash to ActiveNode/ActiveRel. --- .../core/cypher_session/responses/http.rb | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/lib/neo4j/core/cypher_session/responses/http.rb b/lib/neo4j/core/cypher_session/responses/http.rb index 5d8300cb..0a7bbb99 100644 --- a/lib/neo4j/core/cypher_session/responses/http.rb +++ b/lib/neo4j/core/cypher_session/responses/http.rb @@ -21,22 +21,27 @@ def initialize(faraday_response, options = {}) end def result_from_data(columns, entities_data) + cache = { + node: {}, + relationship: {}, + } + rows = entities_data.map do |entity_data| - wrap_entity entity_data[:row], entity_data[:rest] + wrap_entity entity_data[:row], entity_data[:rest], cache: cache end Result.new(columns, rows) end - def wrap_entity(row_datum, rest_datum) + def wrap_entity(row_datum, rest_datum, cache: {}) case when rest_datum.is_a?(Array) - row_datum.zip(rest_datum).map { |row, rest| wrap_entity(row, rest) } + row_datum.zip(rest_datum).map { |row, rest| wrap_entity(row, rest, cache: cache) } when ident = identify_entity(rest_datum) - send("wrap_#{ident}", rest_datum, row_datum) + send("wrap_#{ident}", rest_datum, row_datum, cache: cache) when rest_datum.is_a?(Hash) rest_datum.each_with_object({}) do |(k, v), result| - result[k.to_sym] = wrap_entity(row_datum[k], v) + result[k.to_sym] = wrap_entity(row_datum[k], v, cache: cache) end else row_datum @@ -56,23 +61,31 @@ def identify_entity(rest_datum) end end - def wrap_node(rest_datum, row_datum) - wrap_by_level(row_datum) do - metadata_data = rest_datum[:metadata] - ::Neo4j::Core::Node.new(id_from_rest_datum(rest_datum), - metadata_data && metadata_data[:labels], - rest_datum[:data]) + def wrap_node(rest_datum, row_datum, cache:) + cache = cache.fetch(:node) + + cache.fetch(id_from_rest_datum(rest_datum)) do |id| + cache[id] = wrap_by_level(row_datum) do + metadata_data = rest_datum[:metadata] + ::Neo4j::Core::Node.new(id, + metadata_data && metadata_data[:labels], + rest_datum[:data]) + end end end - def wrap_relationship(rest_datum, row_datum) - wrap_by_level(row_datum) do - metadata_data = rest_datum[:metadata] - ::Neo4j::Core::Relationship.new(id_from_rest_datum(rest_datum), - metadata_data && metadata_data[:type], - rest_datum[:data], - id_from_url(rest_datum[:start]), - id_from_url(rest_datum[:end])) + def wrap_relationship(rest_datum, row_datum, cache:) + cache = cache.fetch(:relationship) + + cache.fetch(id_from_rest_datum(rest_datum)) do |id| + cache[id] = wrap_by_level(row_datum) do + metadata_data = rest_datum[:metadata] + ::Neo4j::Core::Relationship.new(id, + metadata_data && metadata_data[:type], + rest_datum[:data], + id_from_url(rest_datum[:start]), + id_from_url(rest_datum[:end])) + end end end From 0123743c89bbe36d783555a07c0b0da4272ae3c5 Mon Sep 17 00:00:00 2001 From: Jamie Gaskins Date: Sun, 24 Sep 2017 14:23:00 -0400 Subject: [PATCH 2/2] Extract identity map to an instance variable --- .../core/cypher_session/responses/http.rb | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/neo4j/core/cypher_session/responses/http.rb b/lib/neo4j/core/cypher_session/responses/http.rb index 0a7bbb99..e4d0248e 100644 --- a/lib/neo4j/core/cypher_session/responses/http.rb +++ b/lib/neo4j/core/cypher_session/responses/http.rb @@ -10,6 +10,10 @@ class HTTP < Base def initialize(faraday_response, options = {}) @faraday_response = faraday_response @request_data = request_data + @identity_map = { + node: {}, + relationship: {} + } validate_faraday_response!(faraday_response) @@ -21,27 +25,22 @@ def initialize(faraday_response, options = {}) end def result_from_data(columns, entities_data) - cache = { - node: {}, - relationship: {}, - } - rows = entities_data.map do |entity_data| - wrap_entity entity_data[:row], entity_data[:rest], cache: cache + wrap_entity entity_data[:row], entity_data[:rest] end Result.new(columns, rows) end - def wrap_entity(row_datum, rest_datum, cache: {}) + def wrap_entity(row_datum, rest_datum) case when rest_datum.is_a?(Array) - row_datum.zip(rest_datum).map { |row, rest| wrap_entity(row, rest, cache: cache) } + row_datum.zip(rest_datum).map { |row, rest| wrap_entity(row, rest) } when ident = identify_entity(rest_datum) - send("wrap_#{ident}", rest_datum, row_datum, cache: cache) + send("wrap_#{ident}", rest_datum, row_datum) when rest_datum.is_a?(Hash) rest_datum.each_with_object({}) do |(k, v), result| - result[k.to_sym] = wrap_entity(row_datum[k], v, cache: cache) + result[k.to_sym] = wrap_entity(row_datum[k], v) end else row_datum @@ -61,8 +60,8 @@ def identify_entity(rest_datum) end end - def wrap_node(rest_datum, row_datum, cache:) - cache = cache.fetch(:node) + def wrap_node(rest_datum, row_datum) + cache = @identity_map.fetch(:node) cache.fetch(id_from_rest_datum(rest_datum)) do |id| cache[id] = wrap_by_level(row_datum) do @@ -74,8 +73,8 @@ def wrap_node(rest_datum, row_datum, cache:) end end - def wrap_relationship(rest_datum, row_datum, cache:) - cache = cache.fetch(:relationship) + def wrap_relationship(rest_datum, row_datum) + cache = @identity_map.fetch(:relationship) cache.fetch(id_from_rest_datum(rest_datum)) do |id| cache[id] = wrap_by_level(row_datum) do