首页 > 解决方案 > Neo4j.rb 和 Ruby On Rails 的最短加权路径

问题描述

我正在尝试计算两个节点之间的最短加权路径。这是我的用户类:

class User
  include Neo4j::ActiveNode
  property :name, type: String
  has_many :both, :friends, rel_class: :Friendship, model_class: :User
end

用户是节点,它们之间的关系是:

class Friendship
  include Neo4j::ActiveRel

  before_save :set_weight
  from_class :User
  to_class :User
  type 'FRIENDSHIP'
  property :weight

  def set_weight
    ...
  end

属性权重是两个节点之间的半正弦距离值。

我想出了如何编写查询以获取将 user_a 与 user_b 连接的所有路径:

all_paths = a.query_as(:a).match_nodes(b: b).match('p=((a)-[*]-(b))').pluck(:p)

而且我确信我可以将方法链接到该查询以根据权重获得最短路径,但我找不到正确的 Cypher 语法,所以我结束了迭代每条路径并计算每条路径的总权重以获得最短路径一:

def shortest_weighted_path(start_user_id, end_user_id)
  a = User.find(start_user_id)
  b = User.find(end_user_id)

  all_paths = a.query_as(:a).match_nodes(b: b).match('p=((a)-[*]-(b))').pluck(:p)
  paths_and_weights = {}
  all_paths.each_with_index do |path, index|
    total_weight = 0
    path.relationships.each { |relationship| total_weight = total_weight + relationship.properties[:weight] }
    paths_and_weights[index] = total_weight
  end
  paths_and_weights = paths_and_weights.sort_by {|_key, value| value}.to_h
  shortest_path_index = paths_and_weights.keys.first
  shortest_path = all_paths[shortest_path_index]

  nodes_in_path = []
  shortest_path.nodes.each { |node| nodes_in_path << node.properties[:uuid] }
  nodes_in_path
end

谷歌搜索我发现的更多内容以及如何使用 Cypher 计算最短路径的示例:

START  startNode=node:node_auto_index(name={startNode}),
   endNode=node:node_auto_index(name={endNode})
MATCH  p=(startNode)-[:CONNECTED_TO*1..4]->(endNode)
RETURN p AS shortestPath, 
       reduce(weight=0, r in relationships(p) : weight+r.weight) AS   totalWeight
     ORDER BY totalWeight ASC
     LIMIT 1

所以我的问题是:如何根据我的 User-Friendship 示例为 Neo4j.rb 编写此查询?

标签: ruby-on-railsneo4jcypherneo4j.rb

解决方案


推荐阅读