Skip to content
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

Improved the check that determines if the pattern trick should be used. #118

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
143 changes: 109 additions & 34 deletions src/engine/QueryPlanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,38 +47,12 @@ QueryExecutionTree QueryPlanner::createExecutionTree(ParsedQuery& pq) const {
LOG(DEBUG) << "Got " << patternPlans.size() << " subplans to create."
<< std::endl;

// look for ql:has-predicate to determine if the pattern trick should be used
bool usePatternTrick = false;
// Look for ql:has-predicate to determine if the pattern trick should be used.
// If the pattern trick is used the ql:has-predicate triple will be removed
// from the list of where clause triples. Otherwise the ql:has-relation triple
// will be handled using a HasRelationScan.
SparqlTriple patternTrickTriple("", "", "");
// Check if the query has the right number of variables for aliases, select
// and group by.
if (pq._groupByVariables.size() == 1 && pq._aliases.size() == 1 &&
pq._selectedVariables.size() == 2) {
const ParsedQuery::Alias& alias = pq._aliases.back();
// Check if the alias is a non distinct count alias
if (alias._isAggregate &&
alias._function.find("DISTINCT") == std::string::npos &&
alias._function.find("distinct") == std::string::npos &&
(ad_utility::startsWith(alias._function, "COUNT") ||
ad_utility::startsWith(alias._function, "count"))) {
// look for a HAS_RELATION_PREDICATE triple
for (size_t i = 0; i < pq._rootGraphPattern._whereClauseTriples.size();
i++) {
const SparqlTriple& t = pq._rootGraphPattern._whereClauseTriples[i];
if (t._p == HAS_PREDICATE_PREDICATE && alias._inVarName == t._o &&
pq._groupByVariables[0] == t._o &&
pq._selectedVariables[0] == t._o &&
pq._selectedVariables[1] == alias._outVarName) {
LOG(DEBUG) << "Using the pattern trick to answer the query." << endl;
usePatternTrick = true;
patternTrickTriple = t;
// remove the triple from the graph
pq._rootGraphPattern._whereClauseTriples.erase(
pq._rootGraphPattern._whereClauseTriples.begin() + i);
}
}
}
}
bool usePatternTrick = checkUsePatternTrick(&pq, &patternTrickTriple);

bool doGrouping = pq._groupByVariables.size() > 0 || usePatternTrick;
if (!doGrouping) {
Expand Down Expand Up @@ -275,7 +249,7 @@ QueryExecutionTree QueryPlanner::createExecutionTree(ParsedQuery& pq) const {
std::shared_ptr<Operation> orderByOp(
new OrderBy(_qec, final._qet, sortIndices));

if (isSorted) {
if (!isSorted) {
orderByPlan._qet->setVariableColumns(
final._qet->getVariableColumnMap());
orderByPlan._qet->setOperation(QueryExecutionTree::ORDER_BY, orderByOp);
Expand All @@ -294,8 +268,8 @@ QueryExecutionTree QueryPlanner::createExecutionTree(ParsedQuery& pq) const {
countPred);

final = patternTrickPlan;
std::cout << "Plan after pattern trick: " << endl
<< final._qet->asString() << endl;
LOG(DEBUG) << "Plan after pattern trick: " << endl
<< final._qet->asString() << endl;
} else {
// Use the pattern trick without a subtree
SubtreePlan patternTrickPlan(_qec);
Expand Down Expand Up @@ -434,6 +408,107 @@ QueryExecutionTree QueryPlanner::createExecutionTree(ParsedQuery& pq) const {
return *final._qet.get();
}

bool QueryPlanner::checkUsePatternTrick(
ParsedQuery* pq, SparqlTriple* patternTrickTriple) const {
bool usePatternTrick = false;
// Check if the query has the right number of variables for aliases and group
// by.
if (pq->_groupByVariables.size() == 1 && pq->_aliases.size() == 1) {
const ParsedQuery::Alias& alias = pq->_aliases.back();
// Create a lower case version of the aliases function string to allow
// for case insensitive keyword detection.
std::string aliasFunctionLower =
ad_utility::getLowercaseUtf8(alias._function);
// Check if the alias is a non distinct count alias
if (alias._isAggregate &&
aliasFunctionLower.find("distinct") == std::string::npos &&
ad_utility::startsWith(aliasFunctionLower, "count")) {
// look for a HAS_RELATION_PREDICATE triple
for (size_t i = 0; i < pq->_rootGraphPattern._whereClauseTriples.size();
i++) {
const SparqlTriple& t = pq->_rootGraphPattern._whereClauseTriples[i];
// Check that the triples predicates is the HAS_PREDICATE_PREDICATE.
// Also check that the triples object matches the aliases input variable
// and the group by variable.
if (t._p == HAS_PREDICATE_PREDICATE && alias._inVarName == t._o &&
pq->_groupByVariables[0] == t._o) {
// Assume we will use the pattern trick for now but run several more
// checks before actually modifying the query.
usePatternTrick = true;
// check that all selected variables are outputs of
// CountAvailablePredicates
for (const std::string& s : pq->_selectedVariables) {
if (s != t._o && s != alias._outVarName) {
usePatternTrick = false;
break;
}
}
// Check for triples containing the ql:has-predicate triple's object.
for (size_t j = 0;
usePatternTrick &&
j < pq->_rootGraphPattern._whereClauseTriples.size();
j++) {
const SparqlTriple& other =
pq->_rootGraphPattern._whereClauseTriples[j];
if (j != i &&
(other._s == t._o || other._p == t._o || other._o == t._o)) {
usePatternTrick = false;
}
}
// Don't run any more checks if we already determined that the pattern
// trick is not going to be used.
if (usePatternTrick) {
// Check for filters on the ql:has-predicate triple's subject or
// object
for (const SparqlFilter& filter : pq->_rootGraphPattern._filters) {
if (filter._lhs == t._o || filter._lhs == t._s ||
filter._rhs == t._o || filter._rhs == t._s) {
usePatternTrick = false;
break;
}
}
}
// Don't run any more checks if we already determined that the pattern
// trick is not going to be used.
if (usePatternTrick) {
// Check for optional parts containing the ql:has-predicate triple's
// object
std::vector<const ParsedQuery::GraphPattern*> graphsToProcess;
graphsToProcess.insert(graphsToProcess.end(),
pq->_rootGraphPattern._children.begin(),
pq->_rootGraphPattern._children.end());
while (!graphsToProcess.empty()) {
const ParsedQuery::GraphPattern* pattern = graphsToProcess.back();
graphsToProcess.pop_back();
graphsToProcess.insert(graphsToProcess.end(),
pattern->_children.begin(),
pattern->_children.end());
for (const SparqlTriple& other : pattern->_whereClauseTriples) {
if (other._s == t._o || other._p == t._o || other._o == t._o) {
usePatternTrick = false;
break;
}
}
if (!usePatternTrick) {
break;
}
}
}
if (usePatternTrick) {
LOG(DEBUG) << "Using the pattern trick to answer the query."
<< endl;
*patternTrickTriple = t;
// remove the triple from the graph
pq->_rootGraphPattern._whereClauseTriples.erase(
pq->_rootGraphPattern._whereClauseTriples.begin() + i);
}
}
}
}
}
return usePatternTrick;
}

// _____________________________________________________________________________
vector<QueryPlanner::SubtreePlan> QueryPlanner::getOrderByRow(
const ParsedQuery& pq, const vector<vector<SubtreePlan>>& dpTab) const {
Expand Down
14 changes: 14 additions & 0 deletions src/engine/QueryPlanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,18 @@ class QueryPlanner {
SubtreePlan getTextLeafPlan(const TripleGraph::Node& node) const;

SubtreePlan optionalJoin(const SubtreePlan& a, const SubtreePlan& b) const;

/**
* @brief Determines if the pattern trick (and in turn the
* CountAvailablePredicates operation) are applicable to the given
* parsed query. If a ql:has-predicate triple is found and
* CountAvailblePredicates can be used for it, the triple will be removed from
* the parsed query.
* @param pq The parsed query.
* @param patternTrickTriple An output parameter in which the triple that
* satisfies the requirements for the pattern trick is stored.
* @return True if the pattern trick should be used.
*/
bool checkUsePatternTrick(ParsedQuery* pq,
SparqlTriple* patternTrickTriple) const;
};