mirror of https://gitee.com/bigwinds/arangodb
Added an improved version for neighbors search.
This commit is contained in:
parent
d19beb661f
commit
3be60c7e54
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue