在 XQuery 中搜索两个图节点之间的路径 [英] search a path between two graph nodes in XQuery

查看:27
本文介绍了在 XQuery 中搜索两个图节点之间的路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一种算法,该算法在 xQuery 中的图形中搜索并返回两个节点之间的路径,到目前为止我没有运气,因为它只返回一个节点并且它是相邻节点.首先,我应该明确该图是一个有向图,每个节点都可以有零个、一个或多个原点,在 XML 中,一个节点只有到它的原点的链接,但没有到它的后续节点的链接

I'm trying to make an algorithm that searchs and returns a path between two nodes in a graph in xQuery, i've had no luck so far as it returns just one node and it's adyacent nodes. First i should make clear that the graph is a directed graph and every node can have zero, one or more origins, in the XML a node only has the link to it's origin but not to it's following nodes

这是一些节点及其 XML 的示例

Here's an example of some nodes and their XML

<node>
  <id> 123-456-789</id>
  <name> something </name>
  <Links>
     <Link>
        <origin></origin>
     </Link>
  <Links>

 <node>
  <id> 245-678-901</id>
  <name> node 2</name>
  <Links>
     <Link>
        <origin> 123-456-789 </origin>
     </Link>
  <Links>

  <node>
  <id> xxx-xxx-xxx</id>
  <name> node 3</name>
  <Links>
     <Link>
        <origin> 123-456-789 </origin>
     </Link>
  <Links>

  <node>
  <id> 234-546-768</id>
  <name> node 4</name>
  <Links>
     <Link>
        <origin> 245-678-901</origin>
     </Link>
  <Links>

从那个 XML 我想得到从节点 1 到节点 4 的路径(节点 1-> 节点 2 -> 节点 4)但无论我尝试做什么只会给我 node1-node2 和 node3 而不是 node4另一件事是我想选择一个不是直接的路径,我的意思是,如果我想要 node5 和 node7 之间的路径,但是 node5 和 node7 都指向 node6

From that XML i would like to get the path from node 1 to node 4 ( node1-> node2 -> node4) but whatever i try to do would just give me node1-node2 and node3 but not node4 another thing is that i want to select a path that is not direct, i mean, if i want the path between node5 and node7 but both node5 and node7 are directed towards node6

我已经尝试将此 python 代码改编为 xquery

I've tried adapting this python code to xquery

def BFS(graph,start,end,q):

temp_path = [start]

q.enqueue(temp_path)

while q.IsEmpty() == False:
    tmp_path = q.dequeue()
    last_node = tmp_path[len(tmp_path)-1]
    print tmp_path
    if last_node == end:
        print "VALID_PATH : ",tmp_path
    for link_node in graph[last_node]:
        if link_node not in tmp_path:
            new_path = []
            new_path = tmp_path + [link_node]
            q.enqueue(new_path)

(代码不是我的,它属于 这个 activestate 页面)

(code not mine, it belongs to it's rightful coder at this activestate page)

这是我尝试做的:

declare function local:BFS($graph as element()* , $ini_node as element(Node)*, $end_node as element(Node)*) as element()*
{
    let $seq := $ini_node
    let $queue := ($seq)
    for $item in $queue
        return
            if ( count($queue) > 0) then
                let $seq := remove($queue, count($queue))
                let $last := $seq[last()] return if (deep-equal($last, $end_node)) then $seq
                else
                    for $node in $graph[contains(.,$graph/id[contains(.,$last/Links/Link/origin/text())])] (: what i've tried was to get the graph nodes which id is equal to the origins of the last node :)
                        return if(not(functx:is-node-in-sequence-deep-equal($node,$seq))) then
                            let $new_path:= ()
                            let $new_path:= insert-before($seq, count($seq)+1, $node)
                            let $queue := insert-before($queue,1, $new_path) return $queue
                        else ()

            else
                ()


};

推荐答案

XQuery 和 Python 的根本区别在于 XQuery 是一个 函数式编程语言.这意味着绑定到变量的值之后无法修改.例如,在您的函数 local:BFS(...) 中,您不能在循环内更改 $queue 的值,您要做的就是创建一个新变量 $queue 遮住外面的那个.

The fundamental difference between XQuery and Python is that XQuery is a functional programming language. This means that the value bound to a variable cannot be modified afterwards. In your function local:BFS(...) for example you cannot change the value of $queue inside the loop, all you do is create a new variable $queue that shadows the outer one.

为了让它工作,你可以把外循环写成一个递归函数 而是将当前队列作为参数.循环的每次迭代都是使用队列的更新版本调用函数:

In order to get it to work, you can write the outer loop as a recursive function instead that takes the current queue as an argument. Each iteration of the loop is then one invocation of the function with an updated version of the queue:

declare function local:BFS($graph, $queue, $steps, $end) {
  if(empty($queue)) then error(xs:QName('local:NOTFOUND'), 'No path found.')
  else (
    let $curr := $queue[1], $rest-queue := $queue[position() > 1]
    return (
      if($curr eq $end) then local:result($steps, $end)
      else (
        let $successors :=
          $graph//node[Links/Link/origin = $curr and not($steps/@to = id)]/id/string()
        let $new-steps  :=
          for $succ in $successors
          return <edge from="{$curr}" to="{$succ}" />
        return local:BFS(
          $graph,
          ($rest-queue, $successors),
          ($steps, $new-steps),
          $end
        )
      )
    )
  )
};

可以通过向起始节点提供第一条边来调用它:

It can be called by supplying the first edge to the start node:

declare function local:BFS($graph, $start, $end) {
  local:BFS($graph, $start, <edge to="{$start}" />, $end)
};

所有使用的边都存储在 $steps 中.为了在我们找到目的地后重建路径,我们可以向后遍历它们,直到找到初始边:

All used edges are stored in $steps. In order to reconstruct the path after we found the destination, we can just traverse them backwards until we find the initial edge:

declare function local:result($steps, $dest) {
  let $pred := $steps[@to = $dest]/@from/string()
  return if(exists($pred)) then (local:result($steps, $pred), $dest)
  else $dest
};

如果您关心性能,XQuery 序列可能不是用作队列的最佳数据结构.用于查找的 XML 片段也是如此.因此,如果您可以访问 XQuery 3.0 处理器,您可以查看一些(至少渐近地)我在 https://github.com/LeoWoerteler/xq-modules 上写的更高效的数据结构.我什至将 Dijkstra 算法 作为一个示例.

If you are concerned about performance, XQuery sequences are probably not the best data structure to use as a queue. The same can be said about XML fragments for lookups. So if you have access to an XQuery 3.0 processor, you can have a look at some (at least asymptotically) more efficient data structures I wrote at https://github.com/LeoWoerteler/xq-modules. I even included Dijkstra's algorithm as an example.

这篇关于在 XQuery 中搜索两个图节点之间的路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆