1
0
Fork 0

Added an improved version for neighbors search.

This commit is contained in:
Michael Hackstein 2016-10-24 07:35:27 -07:00
parent d19beb661f
commit 3be60c7e54
7 changed files with 148 additions and 8 deletions

View File

@ -92,6 +92,12 @@ TraversalBlock::TraversalBlock(ExecutionEngine* engine, TraversalNode const* ep)
_traverser.reset(
new arangodb::traverser::SingleServerTraverser(_opts, _trx));
}
if (!ep->usesEdgeOutVariable() && !ep->usesPathOutVariable() &&
_opts->useBreadthFirst &&
_opts->uniqueVertices ==
traverser::TraverserOptions::UniquenessLevel::GLOBAL) {
_traverser->allowOptimizedNeighbors();
}
if (!ep->usesInVariable()) {
_vertexId = ep->getStartVertex();
} else {

View File

@ -26,6 +26,7 @@
using DepthFirstEnumerator = arangodb::traverser::DepthFirstEnumerator;
using BreadthFirstEnumerator = arangodb::traverser::BreadthFirstEnumerator;
using NeighborsEnumerator = arangodb::traverser::NeighborsEnumerator;
using Traverser = arangodb::traverser::Traverser;
using TraverserOptions = arangodb::traverser::TraverserOptions;
@ -388,3 +389,77 @@ void BreadthFirstEnumerator::computeEnumeratedPath(size_t index) {
_enumeratedPath.vertices[0] = current->vertex;
}
NeighborsEnumerator::NeighborsEnumerator(Traverser* traverser,
VPackSlice startVertex,
TraverserOptions const* opts)
: PathEnumerator(traverser, startVertex, opts),
_searchDepth(0) {
_allFound.insert(startVertex);
_currentDepth.insert(startVertex);
_iterator = _currentDepth.begin();
}
bool NeighborsEnumerator::next() {
if (_isFirst) {
_isFirst = false;
if (_opts->minDepth == 0) {
return true;
}
}
if (_iterator == _currentDepth.end() || ++_iterator == _currentDepth.end()) {
do {
// This depth is done. Get next
if (_opts->maxDepth == _searchDepth) {
// We are finished.
return false;
}
_lastDepth.swap(_currentDepth);
_currentDepth.clear();
size_t cursorIdx;
for (auto const& nextVertex : _lastDepth) {
cursorIdx = 0;
std::unique_ptr<arangodb::traverser::EdgeCursor> cursor(_opts->nextCursor(nextVertex, _searchDepth));
while (cursor->readAll(_tmpEdges, cursorIdx)) {
if (!_tmpEdges.empty()) {
_traverser->_readDocuments += _tmpEdges.size();
VPackSlice v;
for (auto const& e : _tmpEdges) {
if (_traverser->getSingleVertex(e, nextVertex, _searchDepth, v)) {
if (_allFound.find(v) == _allFound.end()) {
_currentDepth.emplace(v);
_allFound.emplace(v);
}
}
}
_tmpEdges.clear();
}
}
}
if (_currentDepth.empty()) {
// Nothing found. Cannot do anything more.
return false;
}
++_searchDepth;
} while (_searchDepth < _opts->minDepth);
_iterator = _currentDepth.begin();
}
TRI_ASSERT(_iterator != _currentDepth.end());
return true;
}
arangodb::aql::AqlValue NeighborsEnumerator::lastVertexToAqlValue() {
TRI_ASSERT(_iterator != _currentDepth.end());
return _traverser->fetchVertexData(*_iterator);
}
arangodb::aql::AqlValue NeighborsEnumerator::lastEdgeToAqlValue() {
// TODO should return Optimizer failed
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
arangodb::aql::AqlValue NeighborsEnumerator::pathToAqlValue(arangodb::velocypack::Builder& result) {
// TODO should return Optimizer failed
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}

View File

@ -248,11 +248,6 @@ class BreadthFirstEnumerator final : public PathEnumerator {
bool next() override;
//////////////////////////////////////////////////////////////////////////////
/// @brief Prunes the current path prefix, the next function should not return
/// any path having this prefix anymore.
//////////////////////////////////////////////////////////////////////////////
aql::AqlValue lastVertexToAqlValue() override;
aql::AqlValue lastEdgeToAqlValue() override;
@ -278,6 +273,56 @@ class BreadthFirstEnumerator final : public PathEnumerator {
void computeEnumeratedPath(size_t index);
};
// @brief Enumerator optimized for neighbors. Does not allow edge access
class NeighborsEnumerator final : public PathEnumerator {
std::unordered_set<arangodb::velocypack::Slice,
arangodb::basics::VelocyPackHelper::VPackStringHash,
arangodb::basics::VelocyPackHelper::VPackStringEqual>
_allFound;
std::unordered_set<arangodb::velocypack::Slice,
arangodb::basics::VelocyPackHelper::VPackStringHash,
arangodb::basics::VelocyPackHelper::VPackStringEqual>
_currentDepth;
std::unordered_set<arangodb::velocypack::Slice,
arangodb::basics::VelocyPackHelper::VPackStringHash,
arangodb::basics::VelocyPackHelper::VPackStringEqual>
_lastDepth;
std::unordered_set<VPackSlice>::iterator _iterator;
size_t _searchDepth;
//////////////////////////////////////////////////////////////////////////////
/// @brief Vector storing the position at current search depth
//////////////////////////////////////////////////////////////////////////////
std::unordered_set<arangodb::velocypack::Slice> _tmpEdges;
public:
NeighborsEnumerator(Traverser* traverser,
arangodb::velocypack::Slice startVertex,
TraverserOptions const* opts);
~NeighborsEnumerator() {
}
//////////////////////////////////////////////////////////////////////////////
/// @brief Get the next Path element from the traversal.
//////////////////////////////////////////////////////////////////////////////
bool next() override;
aql::AqlValue lastVertexToAqlValue() override;
aql::AqlValue lastEdgeToAqlValue() override;
aql::AqlValue pathToAqlValue(arangodb::velocypack::Builder& result) override;
};
} // namespace traverser
} // namespace arangodb

View File

@ -225,7 +225,11 @@ void SingleServerTraverser::setStartVertex(std::string const& v) {
_vertexGetter->reset(idSlice);
if (_opts->useBreadthFirst) {
_enumerator.reset(new BreadthFirstEnumerator(this, idSlice, _opts));
if (_canUseOptimizedNeighbors) {
_enumerator.reset(new NeighborsEnumerator(this, idSlice, _opts));
} else {
_enumerator.reset(new BreadthFirstEnumerator(this, idSlice, _opts));
}
} else {
_enumerator.reset(new DepthFirstEnumerator(this, idSlice, _opts));
}

View File

@ -82,7 +82,6 @@ class SingleServerTraverser final : public Traverser {
void setStartVertex(std::string const& v) override;
protected:
/// @brief Function to load the other sides vertex of an edge
/// Returns true if the vertex passes filtering conditions

View File

@ -340,7 +340,8 @@ Traverser::Traverser(arangodb::traverser::TraverserOptions* opts, arangodb::Tran
_readDocuments(0),
_filteredPaths(0),
_done(true),
_opts(opts) {
_opts(opts),
_canUseOptimizedNeighbors(false) {
if (opts->uniqueVertices == TraverserOptions::UniquenessLevel::GLOBAL) {
_vertexGetter = std::make_unique<UniqueVertexGetter>(this);
} else {
@ -392,3 +393,7 @@ arangodb::aql::AqlValue arangodb::traverser::Traverser::pathToAqlValue(
VPackBuilder& builder) {
return _enumerator->pathToAqlValue(builder);
}
void arangodb::traverser::Traverser::allowOptimizedNeighbors() {
_canUseOptimizedNeighbors = true;
}

View File

@ -211,6 +211,7 @@ class TraversalPath {
class Traverser {
friend class BreadthFirstEnumerator;
friend class DepthFirstEnumerator;
friend class NeighborsEnumerator;
protected:
@ -376,6 +377,8 @@ class Traverser {
bool vertexMatchesConditions(arangodb::velocypack::Slice, size_t);
void allowOptimizedNeighbors();
protected:
/// @brief Outer top level transaction
@ -405,6 +408,8 @@ class Traverser {
/// @brief options for traversal
TraverserOptions* _opts;
bool _canUseOptimizedNeighbors;
/// @brief Function to fetch the real data of a vertex into an AQLValue
virtual aql::AqlValue fetchVertexData(arangodb::velocypack::Slice) = 0;
@ -418,6 +423,7 @@ class Traverser {
/// @brief Function to add the real data of an edge into a velocypack builder
virtual void addEdgeToVelocyPack(arangodb::velocypack::Slice,
arangodb::velocypack::Builder&) = 0;
};
} // traverser
} // arangodb