CouchDB 中图形中的最短路径
Shortest path in graph in CouchDB
我正在尝试计算存储在 CouchDB 中的图形中的最短路径。我必须这样做 'in db' 因为我的任务是比较 3 个不同 DBMS 在不同情况下的查询速度。因此,在 python(或其他任何内容)中加载数据和 运行 dijkstra 不是一种选择。我对基于文档的数据库还很陌生,所以我可能是错的,但据我所知,我唯一的选择是视图。
我的数据库结构如下:
- 一份文件代表一张图表。
- 在带有键 'edges' 的文档中,有一个包含 3 个属性的对象数组:开始、结束、距离。
- start 和 end 是节点 ID,但没有关于节点的其他有趣信息,因此它们不会存储在其他任何地方。
- 距离是一个浮点数
我的想法是创建一个 returns 最短路径的视图。我有这个代码来计算它。它基于 this post。我只需要稍微修改一下,否则我会遇到 let,foreach:
之类的语法错误
function (doc) {
function Graph() {
this.nodes = [];
this.adjacencyList = {};
this.addNode = function(node) {
if(this.nodes.indexOf(node) != -1)
return;
this.nodes.push(node);
this.adjacencyList[node] = [];
}
this.addEdge = function(node1, node2, weight) {
this.adjacencyList[node1].push({node:node2, weight: weight});
//this.adjacencyList[node2].push({node:node1, weight: weight});
}
this.shortestPath = function(startNode, endNode){
var times = {};
var backtrace = {};
var pq = new PriorityQueue();
times[startNode] = 0;
for(var i = 0; i<this.nodes.length; i++){
if(this.nodes[i] != startNode){
times[node] = Infinity;
}
}
pq.enqueue([startNode, 0]);
while (!pq.isEmpty()) {
var shortestStep = pq.dequeue();
var currentNode = shortestStep[0];
for(var i=0;i< this.adjacencyList[currentNode].length; i++){
var neighbor = this.adjacencyList[currentNode][i];
var time = times[currentNode] + neighbor.weight;
if (time < times[neighbor.node]) {
times[neighbor.node] = time;
backtrace[neighbor.node] = currentNode;
pq.enqueue([neighbor.node, time]);
}
}
}
var path = [endNode];
var lastStep = endNode;
while(lastStep !== startNode) {
path.unshift(backtrace[lastStep]);
lastStep = backtrace[lastStep];
}
return 'Path is ${path} and time is ${times[endNode]}';
}
};
function PriorityQueue() {
this.collection = [];
this.enqueue = function(element){
if (this.isEmpty()){
this.collection.push(element);
} else {
var added = false;
for (var i = 1; i <= this.collection.length; i++){
if (element[1] < this.collection[i-1][1]){
this.collection.splice(i-1, 0, element);
added = true;
break;
}
}
if (!added){
this.collection.push(element);
}
}
};
this.dequeue = function() {
var value = this.collection.shift();
return value;
};
this.isEmpty = function() {
return (this.collection.length === 0)
};
};
var graph = new Graph();
var startNode = 118;
var endNode = 270;
for (var i = 0; i < doc.edges.length; ++i) {
graph.addNode(doc.edges[i].start);
graph.addNode(doc.edges[i].end);
graph.addEdge(doc.edges[i].start,doc.edges[i].end,doc.edges[i].distance);
}
emit("shortest", graph.shortestPath(startNode,endNode));
}
但是在查询视图时我得到 0 行。
编辑:
这是一个示例数据集:
{
"_id": "7c75c647957f57eaa47103d5795eab44",
"_rev": "3-4c8bc32cf6129209b1ce2fec35f6e6cd",
"edges": [
{
"start": "1609",
"end": "1622",
"distance": 57.403187
},
{
"start": "2471",
"end": "2479",
"distance": 29.718756
},
{
"start": "2463",
"end": "2471",
"distance": 61.706902
},
{
"start": "2443",
"end": "2448",
"distance": 19.080025
},
...
}
终于找到了。当我将 foreach 重写为传统的 for 时,我忘记更改这个:
for(var i = 0; i<this.nodes.length; i++){
if(this.nodes[i] != startNode){
times[node] = Infinity;
}
}
为此:
for(var i = 0; i<this.nodes.length; i++){
if(this.nodes[i] != startNode){
times[this.nodes[i]] = Infinity;
}
}
有趣的是,我在 CouchDB 中没有看到任何错误。我必须 运行 在本地使用 node.js 我的代码才能发现有错误。
我正在尝试计算存储在 CouchDB 中的图形中的最短路径。我必须这样做 'in db' 因为我的任务是比较 3 个不同 DBMS 在不同情况下的查询速度。因此,在 python(或其他任何内容)中加载数据和 运行 dijkstra 不是一种选择。我对基于文档的数据库还很陌生,所以我可能是错的,但据我所知,我唯一的选择是视图。
我的数据库结构如下:
- 一份文件代表一张图表。
- 在带有键 'edges' 的文档中,有一个包含 3 个属性的对象数组:开始、结束、距离。
- start 和 end 是节点 ID,但没有关于节点的其他有趣信息,因此它们不会存储在其他任何地方。
- 距离是一个浮点数
我的想法是创建一个 returns 最短路径的视图。我有这个代码来计算它。它基于 this post。我只需要稍微修改一下,否则我会遇到 let,foreach:
之类的语法错误function (doc) {
function Graph() {
this.nodes = [];
this.adjacencyList = {};
this.addNode = function(node) {
if(this.nodes.indexOf(node) != -1)
return;
this.nodes.push(node);
this.adjacencyList[node] = [];
}
this.addEdge = function(node1, node2, weight) {
this.adjacencyList[node1].push({node:node2, weight: weight});
//this.adjacencyList[node2].push({node:node1, weight: weight});
}
this.shortestPath = function(startNode, endNode){
var times = {};
var backtrace = {};
var pq = new PriorityQueue();
times[startNode] = 0;
for(var i = 0; i<this.nodes.length; i++){
if(this.nodes[i] != startNode){
times[node] = Infinity;
}
}
pq.enqueue([startNode, 0]);
while (!pq.isEmpty()) {
var shortestStep = pq.dequeue();
var currentNode = shortestStep[0];
for(var i=0;i< this.adjacencyList[currentNode].length; i++){
var neighbor = this.adjacencyList[currentNode][i];
var time = times[currentNode] + neighbor.weight;
if (time < times[neighbor.node]) {
times[neighbor.node] = time;
backtrace[neighbor.node] = currentNode;
pq.enqueue([neighbor.node, time]);
}
}
}
var path = [endNode];
var lastStep = endNode;
while(lastStep !== startNode) {
path.unshift(backtrace[lastStep]);
lastStep = backtrace[lastStep];
}
return 'Path is ${path} and time is ${times[endNode]}';
}
};
function PriorityQueue() {
this.collection = [];
this.enqueue = function(element){
if (this.isEmpty()){
this.collection.push(element);
} else {
var added = false;
for (var i = 1; i <= this.collection.length; i++){
if (element[1] < this.collection[i-1][1]){
this.collection.splice(i-1, 0, element);
added = true;
break;
}
}
if (!added){
this.collection.push(element);
}
}
};
this.dequeue = function() {
var value = this.collection.shift();
return value;
};
this.isEmpty = function() {
return (this.collection.length === 0)
};
};
var graph = new Graph();
var startNode = 118;
var endNode = 270;
for (var i = 0; i < doc.edges.length; ++i) {
graph.addNode(doc.edges[i].start);
graph.addNode(doc.edges[i].end);
graph.addEdge(doc.edges[i].start,doc.edges[i].end,doc.edges[i].distance);
}
emit("shortest", graph.shortestPath(startNode,endNode));
}
但是在查询视图时我得到 0 行。
编辑:
这是一个示例数据集:
{
"_id": "7c75c647957f57eaa47103d5795eab44",
"_rev": "3-4c8bc32cf6129209b1ce2fec35f6e6cd",
"edges": [
{
"start": "1609",
"end": "1622",
"distance": 57.403187
},
{
"start": "2471",
"end": "2479",
"distance": 29.718756
},
{
"start": "2463",
"end": "2471",
"distance": 61.706902
},
{
"start": "2443",
"end": "2448",
"distance": 19.080025
},
...
}
终于找到了。当我将 foreach 重写为传统的 for 时,我忘记更改这个:
for(var i = 0; i<this.nodes.length; i++){
if(this.nodes[i] != startNode){
times[node] = Infinity;
}
}
为此:
for(var i = 0; i<this.nodes.length; i++){
if(this.nodes[i] != startNode){
times[this.nodes[i]] = Infinity;
}
}
有趣的是,我在 CouchDB 中没有看到任何错误。我必须 运行 在本地使用 node.js 我的代码才能发现有错误。