Class: Neo4j::Core::Traversal::Traverser

Inherits:
Object
  • Object
show all
Includes:
Enumerable, Neo4j::Core::ToJava
Defined in:
lib/neo4j-core/traversal/traverser.rb

Overview

By using this class you can both specify traversals and create new relationships. This object is return from the Neo4j::Core::Traversal methods.

See Also:

Instance Method Summary collapse

Methods included from Neo4j::Core::ToJava

dir_from_java, dir_to_java, type_to_java, types_to_java

Constructor Details

#initialize(from, dir = :both, type = nil) ⇒ Traverser

Returns a new instance of Traverser.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/neo4j-core/traversal/traverser.rb', line 62

def initialize(from, dir=:both, type=nil)
  @from = from
  @depth = 1
  if type.nil?
    raise "Traversing all relationship in direction #{dir.inspect} not supported, only :both supported" unless dir == :both
    @td = Java::OrgNeo4jKernelImplTraversal::TraversalDescriptionImpl.new.breadth_first()
  elsif (dir == :both)
    both(type)
  elsif (dir == :incoming)
    incoming(type)
  elsif (dir == :outgoing)
    outgoing(type)
  else
    raise "Illegal direction #{dir.inspect}, expected :outgoing, :incoming or :both"
  end
end

Instance Method Details

#<<(other_node) ⇒ Neo4j::Relationship

Creates a new relationship between given node and self It can create more then one relationship

Examples:

One outgoing relationships

node.outgoing(:foo) << other_node

Two outgoing relationships

node.outgoing(:foo).outgoing(:bar) << other_node

Parameters:

  • other_node (Neo4j::Node)

    the node to which we want to create a relationship

Returns:



191
192
193
194
# File 'lib/neo4j-core/traversal/traverser.rb', line 191

def <<(other_node)
  new(other_node)
  self
end

#[](index) ⇒ Object

Parameters:

  • index (Fixnum)

    the n’th node that will be return from the traversal



332
333
334
# File 'lib/neo4j-core/traversal/traverser.rb', line 332

def [](index)
  each_with_index { |node, i| break node if index == i }
end

#_add_rel(dir, type) ⇒ Object



279
280
281
282
283
# File 'lib/neo4j-core/traversal/traverser.rb', line 279

def _add_rel(dir, type)
  t = type_to_java(type)
  d = dir_to_java(dir)
  @td = @td ? @td.relationships(t, d) : Java::OrgNeo4jKernelImplTraversal::TraversalDescriptionImpl.new.breadth_first().relationships(t, d)
end

#_new_both(other_node, type, props) ⇒ Object



234
235
236
237
# File 'lib/neo4j-core/traversal/traverser.rb', line 234

def _new_both(other_node, type, props)
  _new_out(other_node, type, props)
  _new_in(other_node, type, props)
end

#_new_in(other_node, type, props) ⇒ Object



229
230
231
# File 'lib/neo4j-core/traversal/traverser.rb', line 229

def _new_in(other_node, type, props)
  other_node.create_relationship_to(@from, type_to_java(type)).update(props)
end

#_new_out(other_node, type, props) ⇒ Object



224
225
226
# File 'lib/neo4j-core/traversal/traverser.rb', line 224

def _new_out(other_node, type, props)
  @from.create_relationship_to(other_node, type_to_java(type)).update(props)
end

#both(type) ⇒ Object



241
242
243
244
245
246
# File 'lib/neo4j-core/traversal/traverser.rb', line 241

def both(type)
  @both_rel_types ||= []
  @both_rel_types << type
  _add_rel(:both, type)
  self
end

#breadth_first(pre_or_post = :pre) ⇒ Object

Sets traversing breadth first (default).

This is the default ordering if none is defined. The pre_or_post parameter parameter can have two values: :pre or :post

  • :pre - Traversing breadth first, visiting each node before visiting its child nodes (default)

  • :post - Traversing breadth first, visiting each node after visiting its child nodes.

Note

Please note that breadth first traversals have a higher memory overhead than depth first traversals. BranchSelectors carries state and hence needs to be uniquely instantiated for each traversal. Therefore it is supplied to the TraversalDescription through a BranchOrderingPolicy interface, which is a factory of BranchSelector instances.

Parameters:

  • pre_or_post (:pre, :post) (defaults to: :pre)

    The traversal order

Returns:

  • self



124
125
126
127
128
129
130
131
132
133
134
# File 'lib/neo4j-core/traversal/traverser.rb', line 124

def breadth_first(pre_or_post = :pre)
  case pre_or_post
    when :pre then
      @td = @td.order(Java::OrgNeo4jKernel::Traversal.preorderBreadthFirst())
    when :post then
      @td = @td.order(Java::OrgNeo4jKernel::Traversal.postorderBreadthFirst())
    else
      raise "Unknown type #{pre_or_post}, should be :pre or :post"
  end
  self
end

#depth(d) ⇒ Object

Sets depth, if :all then it will traverse any depth

Parameters:

  • d (Fixnum, :all)

    the depth of traversal, or all

Returns:

  • self



318
319
320
321
# File 'lib/neo4j-core/traversal/traverser.rb', line 318

def depth(d)
  @depth = d
  self
end

#depth_first(pre_or_post = :pre) ⇒ Object

Sets traversing depth first.

The pre_or_post parameter parameter can have two values: :pre or :post

  • :pre - Traversing depth first, visiting each node before visiting its child nodes (default)

  • :post - Traversing depth first, visiting each node after visiting its child nodes.

Parameters:

  • pre_or_post (:pre, :post) (defaults to: :pre)

Returns:

  • self



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/neo4j-core/traversal/traverser.rb', line 97

def depth_first(pre_or_post = :pre)
  case pre_or_post
    when :pre then
      @td = @td.order(Java::OrgNeo4jKernel::Traversal.preorderDepthFirst())
    when :post then
      @td = @td.order(Java::OrgNeo4jKernel::Traversal.postorderDepthFirst())
    else
      raise "Unknown type #{pre_or_post}, should be :pre or :post"
  end
  self
end

#eachObject

Required by the Ruby Enumerable Mixin



342
343
344
# File 'lib/neo4j-core/traversal/traverser.rb', line 342

def each
  @raw ? iterator.each { |i| yield i } : iterator.each { |i| yield i.wrapper }
end

#each_rawObject

Same as #each but does not wrap each node in a Ruby class, yields the Java Neo4j Node instance instead.



347
348
349
# File 'lib/neo4j-core/traversal/traverser.rb', line 347

def each_raw
  iterator.each { |i| yield i }
end

#empty?true, false

Returns:

  • (true, false)


337
338
339
# File 'lib/neo4j-core/traversal/traverser.rb', line 337

def empty?
  first == nil
end

#eval_paths(&eval_path_block) ⇒ Object



137
138
139
140
# File 'lib/neo4j-core/traversal/traverser.rb', line 137

def eval_paths(&eval_path_block)
  @td = @td.evaluator(Evaluator.new(&eval_path_block))
  self
end

#expander(&expander) ⇒ Object

Returns self.

Returns:

  • self

See Also:



251
252
253
254
# File 'lib/neo4j-core/traversal/traverser.rb', line 251

def expander(&expander)
  @td = @td.expand(RelExpander.create_pair(&expander))
  self
end

#filter {|path| ... } ⇒ Object

Only include nodes in the traversal in which the provided block returns true.

Examples:

Return nodes that are exact at depth 2 from me

a_node.outgoing(:friends).depth(2).filter{|path| path.length == 2}

Yields:

  • (path)

Yield Parameters:

  • path (Java::OrgNeo4jGraphdb::Path)

    the path which can be used to filter nodes

Yield Returns:

  • (true, false)

    only if true the node will be included in the traversal result.

See Also:



305
306
307
308
309
310
311
312
313
# File 'lib/neo4j-core/traversal/traverser.rb', line 305

def filter(&block)
  # we keep a reference to filter predicate since only one filter is allowed and we might want to modify it
  @filter_predicate ||= FilterPredicate.new
  @filter_predicate.add(block)


  @td = @td.filter(@filter_predicate)
  self
end

#include_start_nodeObject

By default the start node is not included in the traversal Specifies that the start node should be included

Returns:

  • self



326
327
328
329
# File 'lib/neo4j-core/traversal/traverser.rb', line 326

def include_start_node
  @include_start_node = true
  self
end

#incoming(type) ⇒ Object

Adds one incoming relationship type to the traversal

Parameters:

  • type (String, Symbol)

    the relationship type

Returns:

  • self

See Also:



271
272
273
274
275
276
# File 'lib/neo4j-core/traversal/traverser.rb', line 271

def incoming(type)
  @incoming_rel_types ||= []
  @incoming_rel_types << type
  _add_rel(:incoming, type)
  self
end

#iteratorObject

Returns the java iterator.

Returns:

  • the java iterator



374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
# File 'lib/neo4j-core/traversal/traverser.rb', line 374

def iterator
  unless @include_start_node
    if @filter_predicate
      @filter_predicate.include_start_node
    else
      @td = @td.filter(Java::OrgNeo4jKernel::Traversal.return_all_but_start_node)
    end
  end
  @td = @td.prune(Java::OrgNeo4jKernel::Traversal.pruneAfterDepth(@depth)) unless @depth == :all
  if @traversal_result == :rels
    @td.traverse(@from._java_node).relationships
  elsif @traversal_result == :paths
    @td.traverse(@from._java_node).iterator
  else
    @td.traverse(@from._java_node).nodes
  end

end

#new(other_node, props = {}) ⇒ Neo4j::Relationship

Creates a new relationship between self and given node. It can create more then one relationship This method is used by the << operator.

Examples:

create one relationship

node.outgoing(:bar).new(other_node, rel_props)

two relationships

node.outgoing(:bar).outgoing(:foo).new(other_node, rel_props)

both incoming and outgoing - two relationships

node.both(:bar).new(other_node, rel_props)

Parameters:

  • props (Hash) (defaults to: {})

    properties of new relationship

Returns:

See Also:



217
218
219
220
221
# File 'lib/neo4j-core/traversal/traverser.rb', line 217

def new(other_node, props = {})
  @outgoing_rel_types && @outgoing_rel_types.each { |type| _new_out(other_node, type, props) }
  @incoming_rel_types && @incoming_rel_types.each { |type| _new_in(other_node, type, props) }
  @both_rel_types && @both_rel_types.each { |type| _new_both(other_node, type, props) }
end

#outgoing(type) ⇒ Object

Adds one outgoing relationship type to the traversal

Parameters:

  • type (String, Symbol)

    the relationship type

Returns:

  • self

See Also:



260
261
262
263
264
265
# File 'lib/neo4j-core/traversal/traverser.rb', line 260

def outgoing(type)
  @outgoing_rel_types ||= []
  @outgoing_rel_types << type
  _add_rel(:outgoing, type)
  self
end

#pathsObject

Specifies that we should return an enumerable of paths instead of nodes.

Returns:

  • self



367
368
369
370
371
# File 'lib/neo4j-core/traversal/traverser.rb', line 367

def paths
  @traversal_result = :paths
  @raw = true
  self
end

#prune {|path| ... } ⇒ Object

Cuts of of parts of the traversal.

Examples:

a.outgoing(:friends).outgoing(:recommend).depth(:all).prune{|path| path.end_node[:name] == 'B'}

Yields:

  • (path)

Yield Parameters:

  • path (Java::OrgNeo4jGraphdb::Path)

    the path which can be used to filter nodes

Yield Returns:

  • (true, false)

    only if true the path should be cut of, no traversal beyond this.

See Also:



292
293
294
295
# File 'lib/neo4j-core/traversal/traverser.rb', line 292

def prune(&block)
  @td = @td.prune(PruneEvaluator.new(block))
  self
end

#query(query_hash = nil, &block) ⇒ Object



80
81
82
83
84
85
86
87
# File 'lib/neo4j-core/traversal/traverser.rb', line 80

def query(query_hash = nil, &block)
  # only one direction is supported
  rel_types = [@outgoing_rel_types, @incoming_rel_types, @both_rel_types].find_all { |x| !x.nil? }
  raise "Only one direction is allowed, outgoing:#{@outgoing_rel_types}, incoming:#{@incoming_rel_types}, @both:#{@both_rel_types}" if rel_types.count != 1
  start_id = @from.neo_id
  dir = (@outgoing_rel_types && :outgoing) || (@incoming_rel_types && :incoming) || (@both_rel_types && :both)
  CypherQuery.new(start_id, dir, rel_types.first, query_hash, &block)
end

#rawObject

If this is called then it will not wrap the nodes but instead return the raw Java Neo4j::Node objects when traversing

Returns:

  • self



360
361
362
363
# File 'lib/neo4j-core/traversal/traverser.rb', line 360

def raw
  @raw = true
  self
end

#relsObject

Returns an enumerable of relationships instead of nodes

Returns:

  • self



353
354
355
356
# File 'lib/neo4j-core/traversal/traverser.rb', line 353

def rels
  @traversal_result = :rels
  self
end

#to_aryObject

Returns an real ruby array.



197
198
199
# File 'lib/neo4j-core/traversal/traverser.rb', line 197

def to_ary
  self.to_a
end

#to_sObject



175
176
177
# File 'lib/neo4j-core/traversal/traverser.rb', line 175

def to_s
  "NodeTraverser [from: #{@from.neo_id} depth: #{@depth}"
end

#unique(u = :node_global) ⇒ Object

Sets the rules for how positions can be revisited during a traversal as stated in Uniqueness.

Parameters:

  • u (:node_global, :node_path, :node_recent, :none, :rel_global, :rel_path, :rel_recent) (defaults to: :node_global)

    the uniqueness option

Returns:

  • self

See Also:

  • Neo4j::Core::Traverser#unique


146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/neo4j-core/traversal/traverser.rb', line 146

def unique(u = :node_global)
  case u
    when :node_global then
      # A node cannot be traversed more than once.
      @td = @td.uniqueness(Java::OrgNeo4jKernel::Uniqueness::NODE_GLOBAL)
    when :node_path then
      # For each returned node there 's a unique path from the start node to it.
      @td = @td.uniqueness(Java::OrgNeo4jKernel::Uniqueness::NODE_PATH)
    when :node_recent then
      # This is like NODE_GLOBAL, but only guarantees uniqueness among the most recent visited nodes, with a configurable count.
      @td = @td.uniqueness(Java::OrgNeo4jKernel::Uniqueness::NODE_RECENT)
    when :none then
      # No restriction (the user will have to manage it).
      @td = @td.uniqueness(Java::OrgNeo4jKernel::Uniqueness::NONE)
    when :rel_global then
      # A relationship cannot be traversed more than once, whereas nodes can.
      @td = @td.uniqueness(Java::OrgNeo4jKernel::Uniqueness::RELATIONSHIP_GLOBAL)
    when :rel_path then
      # No restriction (the user will have to manage it).
      @td = @td.uniqueness(Java::OrgNeo4jKernel::Uniqueness::RELATIONSHIP_PATH)
    when :rel_recent then
      # Same as for NODE_RECENT, but for relationships.
      @td = @td.uniqueness(Java::OrgNeo4jKernel::Uniqueness::RELATIONSHIP_RECENT)
    else
      raise "Got option for unique '#{u}' allowed: :node_global, :node_path, :node_recent, :none, :rel_global, :rel_path, :rel_recent"
  end
  self
end