10000 Bug fix/internal issue #316 by gnusi · Pull Request #7911 · arangodb/arangodb · GitHub
[go: up one dir, main page]

Skip to content

Bug fix/internal issue #316 #7911

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Jan 10, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
714c08f
allow using scorers outside ArangoSearch view context
gnusi Dec 21, 2018
9bd05ae
ensure query is properly optimized after replacement of scorer functions
gnusi Dec 23, 2018
104c9db
do not apply `handleViewsRule` to queries without views
gnusi Dec 24, 2018
30a9e29
simplify optimization rule for ArangoSearch views
gnusi Dec 24, 2018
b440b63
show ArangoSearch view scorers in query explanation
gnusi Dec 25, 2018
31d273c
fix tests
gnusi Dec 25, 2018
0e5da98
Merge branch 'devel' of https://github.com/arangodb/arangodb into bug…
gnusi Dec 25, 2018
a6d1805
fix tests
gnusi Dec 26, 2018
3f985c0
add stub for scorer related tests
gnusi Dec 26, 2018
cffbead
Merge branch 'devel' of https://github.com/arangodb/arangodb into bug…
gnusi Jan 8, 2019
aa3ca2e
reformat
gnusi Jan 8, 2019
e0591ca
check variable depth in `ViewExpressionContext::getVariableValue`
gnusi Jan 8, 2019
6c7ef9e
add some tests
gnusi Jan 8, 2019
08504d2
address js test failures
gnusi Jan 8, 2019
a8bda86
address jslint errors
gnusi Jan 9, 2019
d930573
ensure `IResearchViewNode` exposes variables used in scorers
gnusi Jan 9, 2019
5733b0a
ensure scorers with expressions are deduplicated
gnusi Jan 9, 2019
4030503
fix deduplication for indexed access
gnusi Jan 10, 2019
ece771e
more tests
gnusi Jan 10, 2019
6ebe204
partially address review comments
gnusi Jan 10, 2019
6772e87
address review comments
gnusi Jan 10, 2019
99779ce
simplify code
gnusi Jan 10, 2019
bb0d969
remove irrelevant, commented out code
gnusi Jan 10, 2019
b8ccf1b
merge
gnusi Jan 10, 2019
f3af469
ensure array comparisons are properly handled
gnusi Jan 10, 2019
886f19f
update changelog & loki
gnusi Jan 10, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
ensure query is properly optimized after replacement of scorer functions
  • Loading branch information
gnusi committed Dec 23, 2018
commit 9bd05aed64955856a499c44b543340669301989d
8 changes: 4 additions & 4 deletions arangod/Aql/OptimizerRule.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,15 @@ struct OptimizerRule {
// remove redundant filters statements
removeFiltersCoveredByTraversal,

// remove calculations that are redundant
// needs to run after filter removal
removeUnnecessaryCalculationsRule2,

#ifdef USE_IRESEARCH
// move filters and sort conditions into views and remove them
handleArangoSearchViewsRule,
#endif

// remove calculations that are redundant
// needs to run after filter removal
removeUnnecessaryCalculationsRule2,

// remove now obsolete path variables
removeTraversalPathVariable,
prepareTraversalsRule,
Expand Down
82 changes: 48 additions & 34 deletions arangod/IResearch/IResearchOrderFactory.cpp
10000
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#include "VelocyPackHelper.h"
#include "Aql/Ast.h"
#include "Aql/AstNode.h"
#include "Aql/Expression.h"
#include "Aql/ExecutionNode.h"
#include "Aql/Function.h"
#include "Aql/SortCondition.h"
#include "Basics/fasthash.h"
Expand Down Expand Up @@ -239,46 +239,30 @@ NS_BEGIN(arangodb)
NS_BEGIN(iresearch)

// ----------------------------------------------------------------------------
// --SECTION-- OrderFactory implementation
// --SECTION-- ScorerReplacer implementation
// ----------------------------------------------------------------------------

/*static*/ bool OrderFactory::scorer(
irs::sort::ptr* scorer,
arangodb::aql::AstNode const& node,
arangodb::iresearch::QueryContext const& ctx
) {
switch (node.type) {
case arangodb::aql::NODE_TYPE_FCALL: // function call
return fromFCall(scorer, node, ctx);
case arangodb::aql::NODE_TYPE_FCALL_USER: // user function call
return fromFCallUser(scorer, node, ctx);
default:
// IResearch does not support any
// expressions except function calls
return false;
void ScorerReplacer::replace(aql::CalculationNode& node) {
if (!node.expression()) {
return;
}
}

/*static*/ void OrderFactory::replaceScorers(
OrderFactory::VarToScorers& vars,
OrderFactory::DedupScorers& scorers,
aql::Expression& expr
) {
auto& expr = *node.expression();
auto* ast = expr.ast();

if (!expr.ast()) {
// ast is not set
return;
}

auto* node = expr.nodeForModification();
auto* exprNode = expr.nodeForModification();

if (!node) {
if (!exprNode) {
// node is not set
return;
}

auto replaceScorers = [&scorers, ast](aql::AstNode* node) {
auto replaceScorers = [this, ast](aql::AstNode* node) {
if (aql::NODE_TYPE_FCALL == node->type || aql::NODE_TYPE_FCALL_USER == node->type) {
auto* ref = getScorerRef(node->getMember(0));

Expand All @@ -296,13 +280,13 @@ NS_BEGIN(iresearch)

Scorer const key(ref, node);

auto it = scorers.find(key);
auto it = _dedup.find(key);

if (it == scorers.end()) {
if (it == _dedup.end()) {
// create variable
auto* var = ast->variables()->createTemporaryVariable();

it = scorers.emplace(key, var).first;
it = _dedup.emplace(key, var).first;
}

return ast->createNodeReference(it->second);
Expand All @@ -312,18 +296,48 @@ NS_BEGIN(iresearch)
};

// Try to modify root node of the expression
auto newNode = replaceScorers(node);
auto newNode = replaceScorers(exprNode);

if (node != newNode) {
if (exprNode != newNode) {
// simple expression, e.g LET x = BM25(d)
expr.replaceNode(newNode);
} else {
aql::Ast::traverseAndModify(node, replaceScorers);
aql::Ast::traverseAndModify(exprNode, replaceScorers);
}
}

void ScorerReplacer::extract(
aql::Variable const& var,
std::vector<Scorer>& scorers
) {
for (auto it = _dedup.begin(), end = _dedup.end(); it != end; ) {
if (it->first.var == &var) {
scorers.emplace_back(it->second, it->first.node);
it = _dedup.erase(it);
} else {
++it;
}
}
}

for (auto& scorer : scorers) {
auto& nodes = vars[scorer.first.var];
nodes.emplace_back(scorer.second, scorer.first.node);
// ----------------------------------------------------------------------------
// --SECTION-- OrderFactory implementation
// ----------------------------------------------------------------------------

/*static*/ bool OrderFactory::scorer(
irs::sort::ptr* scorer,
arangodb::aql::AstNode const& node,
arangodb::iresearch::QueryContext const& ctx
) {
switch (node.type) {
case arangodb::aql::NODE_TYPE_FCALL: // function call
return fromFCall(scorer, node, ctx);
case arangodb::aql::NODE_TYPE_FCALL_USER: // user function call
return fromFCallUser(scorer, node, ctx);
default:
// IResearch does not support any
// expressions except function calls
return false;
}
}

Expand Down
122 changes: 76 additions & 46 deletions arangod/IResearch/IResearchOrderFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ NS_BEGIN(aql)

class Ast;
struct AstNode;
class CalculationNode;
struct Expression;
struct Variable;

Expand All @@ -54,53 +55,10 @@ NS_END // transaction

NS_BEGIN(iresearch)

////////////////////////////////////////////////////////////////////////////////
/// @struct OrderFactory
////////////////////////////////////////////////////////////////////////////////
struct OrderFactory {
struct Scorer {
Scorer() = default;

constexpr Scorer(
aql::Variable const* var,
aql::AstNode const* node
) noexcept
: var(var), node(node) {
}

constexpr bool operator==(Scorer const& rhs) const noexcept {
return var == rhs.var && node == rhs.node;
}

constexpr bool operator!=(Scorer const& rhs) const noexcept {
return !(*this == rhs);
}

aql::Variable const* var{}; // scorer variable
aql::AstNode const* node{}; // scorer node
}; // Scorer

struct ScorerHash {
size_t operator()(Scorer const& key) const noexcept {
return iresearch::hash(key.node);
}
};

struct ScorerEqualTo {
bool operator()(Scorer const& lhs, Scorer const& rhs) const {
return iresearch::equalTo(lhs.node, rhs.node);
}
};

typedef std::map<aql::Variable const*, std::vector<Scorer>> VarToScorers; // key - loop variable
typedef std::unordered_map<Scorer, aql::Variable const*, ScorerHash, ScorerEqualTo> DedupScorers;

////////////////////////////////////////////////////////////////////////////////
/// @brief replaces scorer functions in a specified expression
////////////////////////////////////////////////////////////////////////////////
static void replaceScorers(
VarToScorers& vars,
DedupScorers& scorers,
aql::Expression& expr
);

////////////////////////////////////////////////////////////////////////////////
/// @brief determine if the 'node' can be converted into an iresearch scorer
/// if 'scorer' != nullptr then also append build iresearch scorer there
Expand All @@ -111,12 +69,84 @@ struct OrderFactory {
iresearch::QueryContext const& ctx
);

////////////////////////////////////////////////////////////////////////////////
/// @brief determine if the 'node' can be converted into an iresearch scorer
/// if 'scorer' != nullptr then also append build iresearch comparer there
////////////////////////////////////////////////////////////////////////////////
static bool comparer(
irs::sort::ptr* scorer,
aql::AstNode const& node
);

OrderFactory() = delete;
}; // OrderFactory

////////////////////////////////////////////////////////////////////////////////
/// @struct Scorer
/// @brief represents IResearch scorer in AQL terms
////////////////////////////////////////////////////////////////////////////////
struct Scorer {
Scorer() = default;

constexpr Scorer(
aql::Variable const* var,
aql::AstNode const* node
) noexcept
: var(var), node(node) {
}

constexpr bool operator==(Scorer const& rhs) const noexcept {
return var == rhs.var && node == rhs.node;
}

constexpr bool operator!=(Scorer const& rhs) const noexcept {
return !(*this == rhs);
}

aql::Variable const* var{}; // scorer variable
aql::AstNode const* node{}; // scorer node
}; // Scorer

////////////////////////////////////////////////////////////////////////////////
/// @class ScorerReplacer
/// @brief utility class that replaces scorer function call with corresponding
/// reference access
////////////////////////////////////////////////////////////////////////////////
class ScorerReplacer {
public:
ScorerReplacer() = default;

////////////////////////////////////////////////////////////////////////////////
/// @brief replaces all occurences of IResearch scorers in a specified node with
/// corresponding reference access
////////////////////////////////////////////////////////////////////////////////
void replace(aql::CalculationNode& node);

////////////////////////////////////////////////////////////////////////////////
/// @brief extracts replacement results for a given variable
////////////////////////////////////////////////////////////////////////////////
void extract(aql::Variable const& var, std::vector<Scorer>& scorers);

private:
struct ScorerHash {
size_t operator()(Scorer const& key) const noexcept {
return iresearch::hash(key.node);
}
}; // ScorerHash

struct ScorerEqualTo {
bool operator()(Scorer const& lhs, Scorer const& rhs) const {
return iresearch::equalTo(lhs.node, rhs.node);
}
}; // ScorerEqualTo

typedef std::unordered_map<
Scorer, aql::Variable const*, ScorerHash, ScorerEqualTo
> DedupScorers;

DedupScorers _dedup;
}; // ScorerReplacer

NS_END // iresearch
NS_END // arangodb

Expand Down
18 changes: 9 additions & 9 deletions arangod/IResearch/IResearchViewNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ inline bool filterConditionIsEmpty(aql::AstNode const* filterCondition) {

void toVelocyPack(
velocypack::Builder& builder,
std::vector<arangodb::iresearch::OrderFactory::Scorer> const& scorers,
std::vector<arangodb::iresearch::Scorer> const& scorers,
bool verbose
) {
VPackArrayBuilder arrayScope(&builder);
Expand All @@ -71,7 +71,7 @@ void toVelocyPack(
}
}

std::vector<arangodb::iresearch::OrderFactory::Scorer> fromVelocyPack(
std::vector<arangodb::iresearch::Scorer> fromVelocyPack(
arangodb::aql::ExecutionPlan& plan,
arangodb::velocypack::Slice const& slice
) {
Expand All @@ -86,7 +86,7 @@ std::vector<arangodb::iresearch::OrderFactory::Scorer> fromVelocyPack(
auto const* vars = plan.getAst()->variables();
TRI_ASSERT(vars);

std::vector<arangodb::iresearch::OrderFactory::Scorer> scorers;
std::vector<arangodb::iresearch::Scorer> scorers;

size_t i = 0;
for (auto const sortSlice : velocypack::ArrayIterator(slice)) {
Expand Down Expand Up @@ -328,12 +328,12 @@ IResearchViewNode::IResearchViewNode(
aql::ExecutionPlan& plan,
size_t id,
TRI_vocbase_t& vocbase,
std::shared_ptr<const arangodb::LogicalView> const& view,
arangodb::aql::Variable const& outVariable,
arangodb::aql::AstNode* filterCondition,
arangodb::aql::AstNode* options,
std::vector<arangodb::iresearch::OrderFactory::Scorer>&& scorers)
: arangodb::aql::ExecutionNode(&plan, id),
std::shared_ptr<const LogicalView> const& view,
aql::Variable const& outVariable,
aql::AstNode* filterCondition,
aql::AstNode* options,
std::vector<Scorer>&& scorers)
: aql::ExecutionNode(&plan, id),
_vocbase(vocbase),
_view(view),
_outVariable(&outVariable),
Expand Down
8 changes: 4 additions & 4 deletions arangod/IResearch/IResearchViewNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class IResearchViewNode final : public arangodb::aql::ExecutionNode {
aql::Variable const& outVariable,
aql::AstNode* filterCondition,
aql::AstNode* options,
std::vector<OrderFactory::Scorer>&& scorers
std::vector<Scorer>&& scorers
);

IResearchViewNode(
Expand Down Expand Up @@ -143,12 +143,12 @@ class IResearchViewNode final : public arangodb::aql::ExecutionNode {
}

/// @brief return the condition to pass to the view
std::vector<OrderFactory::Scorer> const& scorers() const noexcept {
std::vector<Scorer> const& scorers() const noexcept {
return _scorers;
}

/// @brief set the sort condition to pass to the view
void scorers(std::vector<OrderFactory::Scorer>&& scorers) noexcept {
void scorers(std::vector<Scorer>&& scorers) noexcept {
_scorers = std::move(scorers);
}

Expand Down Expand Up @@ -202,7 +202,7 @@ class IResearchViewNode final : public arangodb::aql::ExecutionNode {
aql::AstNode const* _filterCondition;

/// @brief scorers related to the view
std::vector<OrderFactory::Scorer> _scorers;
std::vector<Scorer> _scorers;

/// @brief list of shards involved, need this for the cluster
std::vector<std::string> _shards;
Expand Down
Loading
0