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



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

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

#_add_rel(dir, type) ⇒ Object



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

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



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

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



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

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.



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

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

#empty?true, false

Returns:

  • (true, false)


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

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
245
# File 'lib/neo4j-core/traversal/traverser.rb', line 241

def expander(&expander)
  exp = RelExpander.create_pair(&expander)
  @td = Java::Neo4jRb::Adaptor.expandPath(@td.java_object, exp)
  self
end

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

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

The optional @branch_state@ parameter is an accessor for a state associated with a TraversalBranch during a traversal. TraversalBranch can have an associated state which follows down the branch as the traversal goes. If the state is modified with setState(Object) it means that branches further down will have the newly set state, until it potentially gets overridden again. The state returned from getState() represents the state associated with the parent branch, which by this point has followed down to the branch calling getState().

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

  • branch_state (Java::org.neo4j.graphdb.traversal.BranchState)

    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:



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

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



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

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:



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

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



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

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:



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

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



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

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

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

Cuts of of parts of the traversal.

The optional @branch_state@ parameter is an accessor for a state associated with a TraversalBranch during a traversal. TraversalBranch can have an associated state which follows down the branch as the traversal goes. If the state is modified with setState(Object) it means that branches further down will have the newly set state, until it potentially gets overridden again. The state returned from getState() represents the state associated with the parent branch, which by this point has followed down to the branch calling getState().

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

  • branch_state (Java::org.neo4j.graphdb.traversal.BranchState)

    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:



288
289
290
291
# File 'lib/neo4j-core/traversal/traverser.rb', line 288

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



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

def raw
  @raw = true
  self
end

#relsObject

Returns an enumerable of relationships instead of nodes

Returns:

  • self



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

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