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.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/neo4j-core/traversal/traverser.rb', line 52

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:



181
182
183
184
# File 'lib/neo4j-core/traversal/traverser.rb', line 181

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

#[](index) ⇒ Object

Parameters:

  • index (Fixnum)

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



322
323
324
# File 'lib/neo4j-core/traversal/traverser.rb', line 322

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

#_add_rel(dir, type) ⇒ Object



269
270
271
272
273
# File 'lib/neo4j-core/traversal/traverser.rb', line 269

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



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

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



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

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



214
215
216
# File 'lib/neo4j-core/traversal/traverser.rb', line 214

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

#both(type) ⇒ Object



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

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



114
115
116
117
118
119
120
121
122
123
124
# File 'lib/neo4j-core/traversal/traverser.rb', line 114

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



308
309
310
311
# File 'lib/neo4j-core/traversal/traverser.rb', line 308

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



87
88
89
90
91
92
93
94
95
96
97
# File 'lib/neo4j-core/traversal/traverser.rb', line 87

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



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

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.



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

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

#empty?true, false

Returns:

  • (true, false)


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

def empty?
  first == nil
end

#eval_paths(&eval_path_block) ⇒ Object



127
128
129
130
# File 'lib/neo4j-core/traversal/traverser.rb', line 127

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:



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

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:



295
296
297
298
299
300
301
302
303
# File 'lib/neo4j-core/traversal/traverser.rb', line 295

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.evaluator(@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



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

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:



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

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



364
365
366
367
368
369
370
371
372
373
374
375
376
377
# File 'lib/neo4j-core/traversal/traverser.rb', line 364

def iterator
  unless @include_start_node
    @td = @td.evaluator(Java::OrgNeo4jGraphdbTraversal::Evaluators.exclude_start_position)
  end
  @td = @td.evaluator(Java::OrgNeo4jGraphdbTraversal::Evaluators.toDepth(@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:



207
208
209
210
211
# File 'lib/neo4j-core/traversal/traverser.rb', line 207

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:



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

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



357
358
359
360
361
# File 'lib/neo4j-core/traversal/traverser.rb', line 357

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:



282
283
284
285
# File 'lib/neo4j-core/traversal/traverser.rb', line 282

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

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



70
71
72
73
74
75
76
77
# File 'lib/neo4j-core/traversal/traverser.rb', line 70

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



350
351
352
353
# File 'lib/neo4j-core/traversal/traverser.rb', line 350

def raw
  @raw = true
  self
end

#relsObject

Returns an enumerable of relationships instead of nodes

Returns:

  • self



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

def rels
  @traversal_result = :rels
  self
end

#to_aryObject

Returns an real ruby array.



187
188
189
# File 'lib/neo4j-core/traversal/traverser.rb', line 187

def to_ary
  self.to_a
end

#to_sObject



165
166
167
# File 'lib/neo4j-core/traversal/traverser.rb', line 165

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


136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/neo4j-core/traversal/traverser.rb', line 136

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