mirror of https://gitee.com/bigwinds/arangodb
within queries are now working
This commit is contained in:
parent
d858b9aa71
commit
9d04b37e58
|
@ -3929,7 +3929,7 @@ struct GeoIndexInfo{
|
|||
, executionNode(nullptr)
|
||||
, node(nullptr)
|
||||
, index(nullptr)
|
||||
, range(0)
|
||||
, range(nullptr)
|
||||
, executionNodeType(EN::ILLEGAL)
|
||||
, within(false)
|
||||
, lessgreaterequal(false)
|
||||
|
@ -3949,12 +3949,12 @@ struct GeoIndexInfo{
|
|||
};
|
||||
|
||||
std::unique_ptr<Condition> buildGeoCondition(ExecutionPlan* plan, GeoIndexInfo& info,
|
||||
AstNode* lat, AstNode* lon, AstNode* withRange = nullptr){
|
||||
AstNode* lat, AstNode* lon, bool lessEqual = false, AstNode const* withRange = nullptr){
|
||||
auto ast = plan->getAst();
|
||||
auto varAstNode = ast->createNodeReference(info.collectionNode->outVariable());
|
||||
|
||||
auto nAryAnd = ast->createNodeNaryOperator(NODE_TYPE_OPERATOR_NARY_AND);
|
||||
nAryAnd->reserve(withRange ? 3 : 2);
|
||||
nAryAnd->reserve(withRange ? 4 : 2);
|
||||
|
||||
auto latKey = ast->createNodeAttributeAccess(varAstNode, "latitude",8);
|
||||
auto latEq = ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_EQ, latKey, lat);
|
||||
|
@ -3968,6 +3968,11 @@ std::unique_ptr<Condition> buildGeoCondition(ExecutionPlan* plan, GeoIndexInfo&
|
|||
auto withKey = ast->createNodeAttributeAccess(varAstNode, "within",6);
|
||||
auto withEq = ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_EQ, withKey, withRange);
|
||||
nAryAnd->addMember(withEq);
|
||||
|
||||
auto lessKey = ast->createNodeAttributeAccess(varAstNode, "lesseq",6);
|
||||
auto lessValue = ast->createNodeValueBool(lessEqual);
|
||||
auto lessEq = ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_EQ, lessKey, lessValue);
|
||||
nAryAnd->addMember(lessEq);
|
||||
}
|
||||
|
||||
auto unAryOr = ast->createNodeNaryOperator(NODE_TYPE_OPERATOR_NARY_OR, nAryAnd);
|
||||
|
@ -3978,8 +3983,7 @@ std::unique_ptr<Condition> buildGeoCondition(ExecutionPlan* plan, GeoIndexInfo&
|
|||
return condition;
|
||||
}
|
||||
|
||||
GeoIndexInfo
|
||||
geoDistanceFunctionArgCheck(std::pair<AstNode*,AstNode*> const& pair, ExecutionPlan* plan, GeoIndexInfo info){
|
||||
GeoIndexInfo geoDistanceFunctionArgCheck(std::pair<AstNode*,AstNode*> const& pair, ExecutionPlan* plan, GeoIndexInfo info){
|
||||
using SV = std::vector<std::string>;
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << " enter argument check";
|
||||
// first and second should be based on the same document - need to provide the document
|
||||
|
@ -4046,7 +4050,7 @@ geoDistanceFunctionArgCheck(std::pair<AstNode*,AstNode*> const& pair, ExecutionP
|
|||
}
|
||||
|
||||
|
||||
bool applyGeoOptimization(bool near, ExecutionPlan* plan, GeoIndexInfo& info, bool asc){
|
||||
bool applyGeoOptimization(bool near, ExecutionPlan* plan, GeoIndexInfo& info){
|
||||
|
||||
// FIXME - this code should go to the candidate finding /////////////////////
|
||||
// get it running first
|
||||
|
@ -4066,7 +4070,7 @@ bool applyGeoOptimization(bool near, ExecutionPlan* plan, GeoIndexInfo& info, bo
|
|||
return false;
|
||||
}
|
||||
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << " FOUND DISTANCE RULE WITH ATTRIBUTE ACCESS";
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << " FOUND DISTANCE RULE WITH ATTRIBUTE ACCESS";
|
||||
|
||||
std::pair<AstNode*,AstNode*>* constantPair;
|
||||
GeoIndexInfo res;
|
||||
|
@ -4078,27 +4082,27 @@ bool applyGeoOptimization(bool near, ExecutionPlan* plan, GeoIndexInfo& info, bo
|
|||
constantPair = &argPair1;
|
||||
}
|
||||
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << " attributes: " << res.longitude[0]
|
||||
<< ", " << res.longitude
|
||||
<< " of collection:" << res.collectionNode->collection()->getName()
|
||||
<< " are geoindexed";
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << " attributes: " << res.longitude[0]
|
||||
// << ", " << res.longitude
|
||||
// << " of collection:" << res.collectionNode->collection()->getName()
|
||||
// << " are geoindexed";
|
||||
|
||||
//break; //remove this to make use of the index
|
||||
|
||||
// FIXME - END //////////////////////////////////////////////////////////////
|
||||
|
||||
std::unique_ptr<Condition> condition;
|
||||
if(functionArguments->numMembers() == 4){
|
||||
condition = buildGeoCondition(plan,res, constantPair->first, constantPair->second);
|
||||
if(info.within){
|
||||
condition = buildGeoCondition(plan,res, constantPair->first, constantPair->second, info.lessgreaterequal, info.range);
|
||||
} else {
|
||||
condition = buildGeoCondition(plan,res, constantPair->first, constantPair->second, functionArguments->getMember(4));
|
||||
condition = buildGeoCondition(plan,res, constantPair->first, constantPair->second);
|
||||
}
|
||||
|
||||
auto inode = new IndexNode(
|
||||
plan, plan->nextId(), res.collectionNode->vocbase(),
|
||||
res.collectionNode->collection(), res.collectionNode->outVariable(),
|
||||
std::vector<Transaction::IndexHandle>{Transaction::IndexHandle{res.index}},
|
||||
condition.get(), asc);
|
||||
condition.get(), false);
|
||||
plan->registerNode(inode);
|
||||
condition.release();
|
||||
|
||||
|
@ -4131,7 +4135,7 @@ GeoIndexInfo isDistanceFunction(AstNode const* node){
|
|||
if ( func->externalName != "DISTANCE" || node->numMembers() != 1 ) {
|
||||
return rv;
|
||||
}
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "FOUND DISTANCE FUNCTION";
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "FOUND DISTANCE FUNCTION";
|
||||
rv.node = node;
|
||||
return rv;
|
||||
}
|
||||
|
@ -4145,6 +4149,8 @@ GeoIndexInfo isGeoFilterExpression(AstNode const* node){
|
|||
&& node->type != NODE_TYPE_OPERATOR_BINARY_GT
|
||||
&& node->type != NODE_TYPE_OPERATOR_BINARY_LE
|
||||
&& node->type != NODE_TYPE_OPERATOR_BINARY_LT) {
|
||||
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "expression does not contain <,<=,>=,>";
|
||||
return rv;
|
||||
} else {
|
||||
if (node->type == NODE_TYPE_OPERATOR_BINARY_GE || node->type == NODE_TYPE_OPERATOR_BINARY_GT){
|
||||
|
@ -4155,30 +4161,40 @@ GeoIndexInfo isGeoFilterExpression(AstNode const* node){
|
|||
lessEqual = false;
|
||||
}
|
||||
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "binary operator found";
|
||||
// binary expression has 2 members
|
||||
if(node->numMembers() != 2){
|
||||
return rv;
|
||||
}
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "operator has 2 members";
|
||||
|
||||
auto first = node->getMember(0);
|
||||
auto second = node->getMember(1);
|
||||
|
||||
node->dump(0);
|
||||
|
||||
auto eval_stuff = [](bool dist_first, bool lessEqual, GeoIndexInfo&& dist_fun, AstNode const* value_node){
|
||||
if (!dist_first && dist_fun && value_node){
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "1: " << dist_first;
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "2: " << (bool)dist_fun;
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "3: " << (bool)value_node;
|
||||
if (dist_first && dist_fun && value_node){
|
||||
dist_fun.within = true;
|
||||
dist_fun.range = value_node; //FIXME
|
||||
dist_fun.lessgreaterequal = lessEqual;
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "FOUND WITHIN";
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "FOUND WITHIN";
|
||||
} else {
|
||||
dist_fun.invalidate();
|
||||
}
|
||||
return dist_fun;
|
||||
};
|
||||
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "frist check";
|
||||
rv = eval_stuff(dist_first, lessEqual, isDistanceFunction(first), isValueOrRefNode(second));
|
||||
if (!rv) {
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "second check";
|
||||
rv = eval_stuff(dist_first, lessEqual, isDistanceFunction(second), isValueOrRefNode(first));
|
||||
}
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "result " << (bool) rv;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -4188,8 +4204,10 @@ GeoIndexInfo identifyGeoOptimizationCandidate(ExecutionNode::NodeType type, Exec
|
|||
ExecutionNode* setter = nullptr;
|
||||
auto rv = GeoIndexInfo{};
|
||||
//TODO - iterate over elements of conjunction / disjunction
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "ENTER IDENTIFY";
|
||||
switch(type){
|
||||
case EN::SORT: {
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "found sort node";
|
||||
auto node = static_cast<SortNode*>(n);
|
||||
auto const& elements = node->getElements();
|
||||
|
||||
|
@ -4210,6 +4228,7 @@ GeoIndexInfo identifyGeoOptimizationCandidate(ExecutionNode::NodeType type, Exec
|
|||
break;
|
||||
|
||||
case EN::FILTER: {
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "found filter node";
|
||||
auto node = static_cast<FilterNode*>(n);
|
||||
|
||||
// filter nodes always have one input variable
|
||||
|
@ -4231,6 +4250,8 @@ GeoIndexInfo identifyGeoOptimizationCandidate(ExecutionNode::NodeType type, Exec
|
|||
if (setter == nullptr || setter->getType() != EN::CALCULATION) {
|
||||
return rv;
|
||||
}
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "found setter node for calcuation";
|
||||
|
||||
// downcast to calculation node and get expression
|
||||
auto cn = static_cast<CalculationNode*>(setter);
|
||||
auto const expression = cn->expression();
|
||||
|
@ -4243,6 +4264,7 @@ GeoIndexInfo identifyGeoOptimizationCandidate(ExecutionNode::NodeType type, Exec
|
|||
AstNode const* node = expression->node();
|
||||
|
||||
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "checking expression of calcaulation";
|
||||
switch(type){
|
||||
case EN::SORT: {
|
||||
rv = isDistanceFunction(node);
|
||||
|
@ -4274,7 +4296,7 @@ void checkNodesForGeoOptimization(ExecutionNode::NodeType type, ExecutionPlan* p
|
|||
continue;
|
||||
}
|
||||
infos.push_back(std::move(geoIndexInfo));
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << " FOUND NEAR OR WITHIN";
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << " FOUND NEAR OR WITHIN";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4290,13 +4312,13 @@ void arangodb::aql::optimizeGeoIndexRule(Optimizer* opt,
|
|||
|
||||
bool modified = false;
|
||||
for(auto& info : infos){
|
||||
if (applyGeoOptimization(true, plan, info, true)){
|
||||
if (applyGeoOptimization(true, plan, info)){
|
||||
modified = true;
|
||||
break; // break on first replacement - might be relaxed later
|
||||
}
|
||||
}
|
||||
opt->addPlan(plan, rule, modified);
|
||||
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "EXIT GEO RULE";
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "EXIT GEO RULE - modified: " << modified;
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "";
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ GeoIndexIterator::GeoIndexIterator(LogicalCollection* collection,
|
|||
_lon(0),
|
||||
_near(true),
|
||||
_withinRange(0),
|
||||
_withinInverse(false)
|
||||
_withinLessEq(false)
|
||||
// lookup will hold the inforamtion if this is a cursor for
|
||||
// near/within and the reference point
|
||||
//_lookups(trx, node, reference, index->fields()),
|
||||
|
@ -57,11 +57,9 @@ GeoIndexIterator::GeoIndexIterator(LogicalCollection* collection,
|
|||
}
|
||||
|
||||
void GeoIndexIterator::evaluateCondition() {
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "ENTER evaluate Condition";
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "ENTER evaluate Condition";
|
||||
|
||||
if (_condition) {
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "The Condition is";
|
||||
_condition->dump(0);
|
||||
auto numMembers = _condition->numMembers();
|
||||
|
||||
if(numMembers >= 2){
|
||||
|
@ -73,22 +71,24 @@ void GeoIndexIterator::evaluateCondition() {
|
|||
|
||||
if (numMembers == 2){ //near
|
||||
_near = true;
|
||||
} else if (numMembers == 3) { //within
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "INDEX CONFIGURED FOR NEAR";
|
||||
} else { //within
|
||||
_near = false;
|
||||
_withinRange = _condition->getMember(2)->getMember(1)->getDoubleValue();
|
||||
} else {
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "Invalid Number of arguments";
|
||||
_withinLessEq = _condition->getMember(3)->getMember(1)->getDoubleValue();
|
||||
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "INDEX CONFIGURED FOR WITHIN with range " << _withinRange;
|
||||
}
|
||||
|
||||
} else {
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "No Condition passed to constructor";
|
||||
LOG(ERR) << "No Condition passed to GeoIndexIterator constructor";
|
||||
}
|
||||
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "EXIT evaluate Condition";
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "EXIT evaluate Condition";
|
||||
}
|
||||
|
||||
IndexLookupResult GeoIndexIterator::next() {
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "ENTER next";
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "ENTER next";
|
||||
if (!_cursor){
|
||||
createCursor(_lat,_lon);
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ IndexLookupResult GeoIndexIterator::next() {
|
|||
}
|
||||
|
||||
void GeoIndexIterator::nextBabies(std::vector<IndexLookupResult>& result, size_t batchSize) {
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "ENTER nextBabies";
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "ENTER nextBabies " << batchSize;
|
||||
if (!_cursor){
|
||||
createCursor(_lat,_lon);
|
||||
}
|
||||
|
@ -114,19 +114,24 @@ void GeoIndexIterator::nextBabies(std::vector<IndexLookupResult>& result, size_t
|
|||
if (batchSize > 0) {
|
||||
auto coords = std::unique_ptr<GeoCoordinates>(::GeoIndex_ReadCursor(_cursor,batchSize));
|
||||
size_t length = coords ? coords->length : 0;
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "length " << length;
|
||||
if (!length){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for(std::size_t index = 0; index < length; ++index){
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "near " << _near << " max allowed range: " << _withinRange
|
||||
// << " actual range: " << GeoIndex_distance(&_coor, &coords->coordinates[index]) ;
|
||||
if (_near || GeoIndex_distance(&_coor, &coords->coordinates[index]) <= _withinRange ){
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "add above to result" ;
|
||||
result.emplace_back(IndexLookupResult(::GeoIndex::toRevision(coords->coordinates[index].data)));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_TOPIC(DEBUG, Logger::DEVEL) << "EXIT nextBabies";
|
||||
//LOG_TOPIC(DEBUG, Logger::DEVEL) << "EXIT nextBabies " << result.size();
|
||||
}
|
||||
|
||||
::GeoCursor* GeoIndexIterator::replaceCursor(::GeoCursor* c){
|
||||
|
|
|
@ -76,7 +76,7 @@ class GeoIndexIterator final : public IndexIterator {
|
|||
double _lon;
|
||||
bool _near;
|
||||
double _withinRange;
|
||||
double _withinInverse;
|
||||
double _withinLessEq;
|
||||
};
|
||||
|
||||
class GeoIndex final : public Index {
|
||||
|
|
|
@ -148,7 +148,7 @@ function optimizerRuleTestSuite() {
|
|||
//query clust sort filter
|
||||
[ "FOR d IN " + colName + " SORT distance(d.lat,d.lon, 0 ,0 ) ASC LIMIT 1 RETURN d", false, false, false ],
|
||||
[ "FOR d IN " + colName + " SORT distance(0, 0, d.lat,d.lon ) ASC LIMIT 1 RETURN d", false, false, false ],
|
||||
//[ "FOR d IN " + colName + " FILTER distance(0, 0, d.lat,d.lon ) < 1 LIMIT 1 RETURN d", false, false, false ],
|
||||
[ "FOR d IN " + colName + " FILTER distance(0, 0, d.lat,d.lon ) < 1 LIMIT 1 RETURN d", false, false, true ],
|
||||
];
|
||||
|
||||
queries.forEach(function(query) {
|
||||
|
@ -185,7 +185,8 @@ function optimizerRuleTestSuite() {
|
|||
var queries = [
|
||||
[ "FOR d IN " + colName + " SORT distance(d.lat,d.lon, 0 ,0 ) ASC LIMIT 5 RETURN d", false, false, false ],
|
||||
[ "FOR d IN " + colName + " SORT distance(0, 0, d.lat,d.lon ) ASC LIMIT 5 RETURN d", false, false, false ],
|
||||
[ "FOR d IN " + colName + " FILTER distance(0, 0, d.lat,d.lon ) < 2 RETURN d", false, false, false ],
|
||||
[ "FOR d IN " + colName + " FILTER distance(0, 0, d.lat,d.lon ) < 111200 RETURN d", false, false, false ],
|
||||
// [ "FOR i IN 1..2 FOR d IN geocol SORT distance(i,2,d.lat,d.lon) ASC LIMIT 5 RETURN d", false, false, false ],
|
||||
];
|
||||
|
||||
var expected = [
|
||||
|
|
Loading…
Reference in New Issue