diff --git a/arangod/V8Server/V8Traverser.cpp b/arangod/V8Server/V8Traverser.cpp index d9c7586583..0c86e8f8e0 100644 --- a/arangod/V8Server/V8Traverser.cpp +++ b/arangod/V8Server/V8Traverser.cpp @@ -45,22 +45,75 @@ using namespace std; using namespace triagens::basics; using namespace triagens::arango; -struct WeightInfo { - string keyWeight; - double defaultWeight; - bool usesWeight; +//////////////////////////////////////////////////////////////////////////////// +/// @brief callback to weight an edge +//////////////////////////////////////////////////////////////////////////////// - WeightInfo( - string keyWeight, - double defaultWeight - ) : - keyWeight(keyWeight), defaultWeight(defaultWeight), usesWeight(true) - { - }; +typedef function WeightCalculatorFunction; - WeightInfo() : usesWeight(false) { - }; +//////////////////////////////////////////////////////////////////////////////// +/// @brief Define edge weight by the number of hops. +/// Respectively 1 for any edge. +//////////////////////////////////////////////////////////////////////////////// +class HopWeightCalculator { + public: + HopWeightCalculator() {}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Callable weight calculator for edge +//////////////////////////////////////////////////////////////////////////////// + double operator() (TRI_doc_mptr_copy_t& edge) { + return 1; + }; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Define edge weight by ony special attribute. +/// Respectively 1 for any edge. +//////////////////////////////////////////////////////////////////////////////// +class AttributeWeightCalculator { + + TRI_shape_pid_t _shape_pid; + double _defaultWeight; + TRI_shaper_t* _shaper; + + public: + AttributeWeightCalculator( + string keyWeight, + double defaultWeight, + TRI_shaper_t* shaper + ) : _defaultWeight(defaultWeight), + _shaper(shaper) + { + _shape_pid = _shaper->lookupAttributePathByName(_shaper, keyWeight.c_str()); + }; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Callable weight calculator for edge +//////////////////////////////////////////////////////////////////////////////// + double operator() (TRI_doc_mptr_copy_t& edge) { + if (_shape_pid == 0) { + return _defaultWeight; + } + TRI_shape_sid_t sid; + TRI_EXTRACT_SHAPE_IDENTIFIER_MARKER(sid, edge.getDataPtr()); + TRI_shape_access_t const* accessor = TRI_FindAccessorVocShaper(_shaper, sid, _shape_pid); + TRI_shaped_json_t shapedJson; + TRI_EXTRACT_SHAPED_JSON_MARKER(shapedJson, edge.getDataPtr()); + TRI_shaped_json_t resultJson; + TRI_ExecuteShapeAccessor(accessor, &shapedJson, &resultJson); + if (resultJson._sid != TRI_SHAPE_NUMBER) { + return _defaultWeight; + } + TRI_json_t* json = TRI_JsonShapedJson(_shaper, &resultJson); + if (json == nullptr) { + return _defaultWeight; + } + double realResult = json->_value._number; + TRI_FreeJson(_shaper->_memoryZone, json); + return realResult ; + }; }; class SimpleEdgeExpander { @@ -90,33 +143,20 @@ class SimpleEdgeExpander { CollectionNameResolver* resolver; //////////////////////////////////////////////////////////////////////////////// -/// @brief this is the information required to compute weight by a given -/// attribute. It contains an indicator if weight should be used. -/// Also it includes a default weight and the name of the weight -/// attribute. +/// @brief the weight calculation function //////////////////////////////////////////////////////////////////////////////// - WeightInfo weightInfo; + WeightCalculatorFunction weighter; public: - SimpleEdgeExpander(TRI_edge_direction_e direction, - TRI_document_collection_t* edgeCollection, - string edgeCollectionName, - CollectionNameResolver* resolver) - : direction(direction), edgeCollection(edgeCollection), - resolver(resolver) - { - edgeIdPrefix = edgeCollectionName + "/"; - }; - SimpleEdgeExpander(TRI_edge_direction_e direction, TRI_document_collection_t* edgeCollection, string edgeCollectionName, CollectionNameResolver* resolver, - WeightInfo weightInfo) + WeightCalculatorFunction weighter) : direction(direction), edgeCollection(edgeCollection), - resolver(resolver), weightInfo(weightInfo) + resolver(resolver), weighter(weighter) { edgeIdPrefix = edgeCollectionName + "/"; }; @@ -170,61 +210,32 @@ class SimpleEdgeExpander { unordered_map candidates; Traverser::VertexId from; Traverser::VertexId to; - if (weightInfo.usesWeight) { - for (size_t j = 0; j < edges.size(); ++j) { - from = extractFromId(edges[j]); - to = extractToId(edges[j]); - double currentWeight = weightInfo.defaultWeight; - if (from != source) { - auto cand = candidates.find(from); - if (cand == candidates.end()) { - // Add weight - result.emplace_back(to, from, currentWeight, extractEdgeId(edges[j])); - candidates.emplace(from, result.size() - 1); - } else { - // Compare weight - auto oldWeight = result[cand->second].weight(); - if (currentWeight < oldWeight) { - result[cand->second].setWeight(currentWeight); - } - } - } - else if (to != source) { - auto cand = candidates.find(to); - if (cand == candidates.end()) { - // Add weight - result.emplace_back(to, from, currentWeight, extractEdgeId(edges[j])); - candidates.emplace(to, result.size() - 1); - } else { - auto oldWeight = result[cand->second].weight(); - if (currentWeight < oldWeight) { - result[cand->second].setWeight(currentWeight); - } - } - } - } - } - else { - for (size_t j = 0; j < edges.size(); ++j) { - from = extractFromId(edges[j]); - to = extractToId(edges[j]); - if (from != source) { - auto cand = candidates.find(from); - if (cand == candidates.end()) { - result.emplace_back(from, to, 1, extractEdgeId(edges[j])); - candidates.emplace(from, result.size()-1); - } - } - else if (to != source) { - auto cand = candidates.find(to); - if (cand == candidates.end()) { - result.emplace_back(to, from, 1, extractEdgeId(edges[j])); - candidates.emplace(to, result.size()-1); + for (size_t j = 0; j < edges.size(); ++j) { + from = extractFromId(edges[j]); + to = extractToId(edges[j]); + double currentWeight = weighter(edges[j]); + auto inserter = [&](Traverser::VertexId s, Traverser::VertexId t) { + auto cand = candidates.find(t); + if (cand == candidates.end()) { + // Add weight + result.emplace_back(t, s, currentWeight, extractEdgeId(edges[j])); + candidates.emplace(t, result.size() - 1); + } else { + // Compare weight + auto oldWeight = result[cand->second].weight(); + if (currentWeight < oldWeight) { + result[cand->second].setWeight(currentWeight); } } + }; + if (from != source) { + inserter(to, from); + } + else if (to != source) { + inserter(from, to); } } - } + } }; static v8::Handle pathIdsToV8(v8::Isolate* isolate, Traverser::Path& p) { @@ -283,7 +294,7 @@ void TRI_RunDijkstraSearch (const v8::FunctionCallbackInfo& args) { vector writeCollections; double lockTimeout = (double) (TRI_TRANSACTION_DEFAULT_LOCK_TIMEOUT / 1000000ULL); - bool embed = false; + bool embed = true; bool waitForSync = false; // get the vertex collection @@ -409,15 +420,16 @@ void TRI_RunDijkstraSearch (const v8::FunctionCallbackInfo& args) { unique_ptr forwardExpander; unique_ptr backwardExpander; + WeightCalculatorFunction weighter; if (useWeight) { - forwardExpander.reset(new SimpleEdgeExpander(forward, ecol, edgeCollectionName, - &resolver1, WeightInfo(weightAttribute, defaultWeight))); - backwardExpander.reset(new SimpleEdgeExpander(backward, ecol, edgeCollectionName, - &resolver2, WeightInfo(weightAttribute, defaultWeight))); + weighter = AttributeWeightCalculator( + weightAttribute, defaultWeight, ecol->getShaper() + ); } else { - forwardExpander.reset(new SimpleEdgeExpander(forward, ecol, edgeCollectionName, &resolver1)); - backwardExpander.reset(new SimpleEdgeExpander(backward, ecol, edgeCollectionName, &resolver2)); + weighter = HopWeightCalculator(); } + forwardExpander.reset(new SimpleEdgeExpander(forward, ecol, edgeCollectionName, &resolver1, weighter)); + backwardExpander.reset(new SimpleEdgeExpander(backward, ecol, edgeCollectionName, &resolver2, weighter)); Traverser traverser(*forwardExpander, *backwardExpander, bidirectional); diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index abe69ce860..bef3e4d857 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -2806,7 +2806,7 @@ void TRI_InitV8VocBridge (v8::Isolate* isolate, TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERY_SLEEP"), JS_QuerySleepAql, true); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERY_IS_KILLED"), JS_QueryIsKilledAql, true); - TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_SHORTEST_PATH"), JS_QueryShortestPath, true); + TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("CPP_SHORTEST_PATH"), JS_QueryShortestPath, true); diff --git a/js/apps/system/_admin/aardvark/APP/clusterFrontend/build/style.css b/js/apps/system/_admin/aardvark/APP/clusterFrontend/build/style.css index 0afa95a0c9..b0adfaca5b 100644 --- a/js/apps/system/_admin/aardvark/APP/clusterFrontend/build/style.css +++ b/js/apps/system/_admin/aardvark/APP/clusterFrontend/build/style.css @@ -4328,8 +4328,8 @@ div.resizecontainer { width: 2258px; } } div.centralRow { - margin-top: 65px; - margin-bottom: 65px; } + margin-top: 40px; + margin-bottom: 40px; } div.centralContent { background-color: rgba(0, 0, 0, 0.0675); diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/collections/airportCollection.js b/js/apps/system/_admin/aardvark/APP/frontend/js/collections/airportCollection.js index f9b95f4ff2..ffc3b22dd5 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/collections/airportCollection.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/collections/airportCollection.js @@ -7,7 +7,8 @@ window.Airports = Backbone.Collection.extend({ - initialize: function() { + initialize: function(options) { + this.collectionName = options.collectionName; }, getAirports: function(callback) { @@ -35,6 +36,50 @@ }); }, + getShortestFlight: function(from, to, callback) { + $.ajax({ + type: "POST", + url: "/_api/cursor", + data: JSON.stringify({ + query: "RETURN SHORTEST_PATH(@@airports,@@flights,@start,@dest,'outbound',{})", + bindVars: { + "@flights": this.collectionName, + "@airports": "airports", + "start": "airports/" + from, + "dest": "airports/" + to + } + }), + contentType: "application/json", + processData: false, + success: function (data) { + callback(data.result[0]); + }, + error: function (data) { + } + }); + }, + + getFlightDistribution: function(callback) { + $.ajax({ + type: "POST", + url: "/_api/cursor", + data: JSON.stringify({ + query: "FOR f IN @@flights COLLECT dest = f._to " + + "WITH COUNT INTO n SORT n RETURN {Dest: SPLIT(dest, '/')[1], count: n}", + bindVars: { + "@flights": this.collectionName + } + }), + contentType: "application/json", + processData: false, + success: function (data) { + callback(data.result); + }, + error: function (data) { + } + }); + }, + getFlightsForAirport: function(airport, callback) { var self = this; @@ -42,9 +87,12 @@ type: "POST", url: "/_api/cursor", data: JSON.stringify({ - query: "for f in flights12 filter f.Origin == @airport COLLECT dest = f.Dest " + - "WITH COUNT INTO n SORT n RETURN {Dest: dest, count: n}", - bindVars: {"airport": airport} + query: "for f in @@flights filter f._from == @airport COLLECT dest = f._to " + + "WITH COUNT INTO n SORT n RETURN {Dest: SPLIT(dest, '/')[1], count: n}", + bindVars: { + "airport": "airports/" + airport, + "@flights": this.collectionName + } }), contentType: "application/json", processData: false, diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/routers/router.js b/js/apps/system/_admin/aardvark/APP/frontend/js/routers/router.js index 04d5092b62..59fd1b064b 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/routers/router.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/routers/router.js @@ -26,13 +26,18 @@ "userManagement": "userManagement", "userProfile": "userProfile", "logs": "logs", - "demo": "demo" + "demo": "demo", + "demo/:collection": "demo" }, - demo: function () { - + demo: function (collection) { + if (!collection) { + collection = "flights"; + } if (!this.demoView) { - this.demoView = new window.DemoView({}); + this.demoView = new window.DemoView({ + collectionName: collection + }); } this.demoView.render(); diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/templates/demoView.ejs b/js/apps/system/_admin/aardvark/APP/frontend/js/templates/demoView.ejs index 03da9831ce..abdbc3708f 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/templates/demoView.ejs +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/templates/demoView.ejs @@ -5,6 +5,7 @@
+