Loading

图数据库入门教程(十三)怎么坐地铁最快?

两站之间最短路径

gremlin提供了repeat..until语法来循环执行一个逻辑,直到满足某个条件。通过repeat..until来进行最短路径查询非常适合。

下面语句来查询西单地铁站到东单地铁站的路径,并限制前10个

g.V().has("station","name","西单").repeat(out().simplePath()).until(has("name","东单")).path().by('name').limit(10)

//输出
[
  path[西单, 天安门西, 天安门东, 王府井, 东单], 
  path[西单, 宣武门, 和平门, 前门, 崇文门, 东单], 
  path[西单, 宣武门, 和平门, 前门, 王府井, 东单], 
  path[西单, 天安门西, 天安门东, 王府井, 前门, 崇文门, 东单], 
  path[西单, 宣武门, 和平门, 前门, 崇文门, 北京站, 建国门, 东单], 
  path[西单, 宣武门, 菜市口, 虎坊桥, 珠市口, 前门, 崇文门, 东单], 
  path[西单, 宣武门, 菜市口, 虎坊桥, 珠市口, 前门, 王府井, 东单], 
  path[西单, 复兴门, 长椿街, 宣武门, 和平门, 前门, 崇文门, 东单], 
  path[西单, 复兴门, 长椿街, 宣武门, 和平门, 前门, 王府井, 东单], 
  path[西单, 灵境胡同, 西四, 平安里, 北海北, 南锣鼓巷, 东四, 灯市口, 东单]
]

同时,我们也可以用emit代替until来对结果进行过滤

g.V().has("station","name","西单").repeat(out().simplePath()).emit(has("name","东单")).path().by('name').limit(10)

//输出
[
  path[西单, 天安门西, 天安门东, 王府井, 东单], 
  path[西单, 宣武门, 和平门, 前门, 崇文门, 东单], 
  path[西单, 宣武门, 和平门, 前门, 王府井, 东单], 
  path[西单, 天安门西, 天安门东, 王府井, 前门, 崇文门, 东单], 
  path[西单, 宣武门, 和平门, 前门, 崇文门, 北京站, 建国门, 东单], 
  path[西单, 宣武门, 菜市口, 虎坊桥, 珠市口, 前门, 崇文门, 东单], 
  path[西单, 宣武门, 菜市口, 虎坊桥, 珠市口, 前门, 王府井, 东单], 
  path[西单, 复兴门, 长椿街, 宣武门, 和平门, 前门, 崇文门, 东单], 
  path[西单, 复兴门, 长椿街, 宣武门, 和平门, 前门, 王府井, 东单], 
  path[西单, 灵境胡同, 西四, 平安里, 北海北, 南锣鼓巷, 东四, 灯市口, 东单]
]

这里使用simplePath是为了让遍历不走回头路。我们也可以吧until放到前面

g.V().has("station","name","西单").until(has("name","东单")).repeat(out().simplePath()).path().by('name').limit(10)

//输出
[
  path[西单, 天安门西, 天安门东, 王府井, 东单],
  path[西单, 宣武门, 和平门, 前门, 崇文门, 东单], 
  path[西单, 宣武门, 和平门, 前门, 王府井, 东单], 
  path[西单, 天安门西, 天安门东, 王府井, 前门, 崇文门, 东单], 
  path[西单, 宣武门, 和平门, 前门, 崇文门, 北京站, 建国门, 东单], 
  path[西单, 宣武门, 菜市口, 虎坊桥, 珠市口, 前门, 崇文门, 东单], 
  path[西单, 宣武门, 菜市口, 虎坊桥, 珠市口, 前门, 王府井, 东单], 
  path[西单, 复兴门, 长椿街, 宣武门, 和平门, 前门, 崇文门, 东单], 
  path[西单, 复兴门, 长椿街, 宣武门, 和平门, 前门, 王府井, 东单], 
  path[西单, 灵境胡同, 西四, 平安里, 北海北, 南锣鼓巷, 东四, 灯市口, 东单]
]

从西单出发,坐5站能到东单的路线

g.V().has("station","name","西单").repeat(out().simplePath()).times(5).has("name","东单").path().by('name')

//输出
[
  path[西单, 宣武门, 和平门, 前门, 崇文门, 东单], 
  path[西单, 宣武门, 和平门, 前门, 王府井, 东单]
]

times用来指定repeat中操作执行的次数。

从西单出发,坐5站以内能到东单的路线

g.V().has("station","name","西单").repeat(out().simplePath()).times(5).emit().has("name","东单").path().by('name')

//输出
[
  path[西单, 天安门西, 天安门东, 王府井, 东单], 
  path[西单, 宣武门, 和平门, 前门, 崇文门, 东单], 
  path[西单, 宣武门, 和平门, 前门, 王府井, 东单]
]

emit的作用是包括指定次数以内的路径结果,代表"最多五站"的含义。

西单-东单,20站以内有多少种坐法

g.V().has("station","name","西单").repeat(out().simplePath()).times(20).emit().has("name","东单").count()

//输出
[1141]

查询两站间路径,并按照路径长度排序

g.V().has("station","name","西单").repeat(outE().inV().simplePath()).emit(has("name","东单")).project('path','total').by(path().by('name').by('dist')).by(path().unfold().values('dist').sum()).limit(5).order().by(select('total'))

//输出
[
  {path=path[西单, 1217, 天安门西, 925, 天安门东, 852, 王府井, 774, 东单], total=3768}, 
  {path=path[西单, 815, 宣武门, 851, 和平门, 1171, 前门, 1634, 崇文门, 822, 东单], total=5293}, 
  {path=path[西单, 815, 宣武门, 851, 和平门, 1171, 前门, 1857, 王府井, 774, 东单], total=5468}, 
  {path=path[西单, 1217, 天安门西, 925, 天安门东, 852, 王府井, 1857, 前门, 1634, 崇文门, 822, 东单], total=7307}, 
  {path=path[西单, 815, 宣武门, 851, 和平门, 1171, 前门, 1634, 崇文门, 1023, 北京站, 946, 建国门, 1230, 东单], total=7670}
]

怎么理解这个语句?主要是by(path().unfold().values('dist').sum())这句。

我们先看看西单到东单的一个路径

g.V().has("station","name","西单").repeat(outE().inV().simplePath()).emit(has("name","东单")).path().limit(1).next()

//输出
{
  path[
  		v[323672], 
      e[7nrf-6xqw-74l-7gnc][323672-route->348168], 
      v[348168], 
      e[7ls1-7gnc-74l-65fc][348168-route->286968], 
      v[286968], 
      e[7okf-65fc-74l-68l4][286968-route->291064], 
      v[291064], 
      e[7pcv-68l4-74l-6bqw][291064-route->295160], 
      v[295160]
  ]
}

这里的unfold(),是把path数组展开,然后通过values('dist')提取它们的距离集合,然后对集合求sum,赋值给total。

posted @ 2022-08-29 14:50  树先生1024  阅读(190)  评论(1编辑  收藏  举报