diff options
author | Hari Khalsa <hkhalsa@10gen.com> | 2014-01-03 14:33:07 -0500 |
---|---|---|
committer | Hari Khalsa <hkhalsa@10gen.com> | 2014-01-06 12:11:34 -0500 |
commit | e89dccbef9b83ac8101dcceab64f5c6e09b6de50 (patch) | |
tree | 3ce9939609d46db43ee3e2f447f079dbdca0e3f6 | |
parent | 81d8d29c4e2a7a706b6fb0f4d4f821ca2ed38161 (diff) | |
download | mongo-e89dccbef9b83ac8101dcceab64f5c6e09b6de50.tar.gz |
SERVER-10363 SERVER-11387 pay attention to special geo idx params
-rw-r--r-- | src/mongo/db/exec/2dnear.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/exec/s2near.cpp | 69 | ||||
-rw-r--r-- | src/mongo/db/exec/s2near.h | 8 | ||||
-rw-r--r-- | src/mongo/db/exec/sort.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/geo/core.h | 12 | ||||
-rw-r--r-- | src/mongo/db/index/expression_index.h | 17 | ||||
-rw-r--r-- | src/mongo/db/index/s2_access_method.h | 3 | ||||
-rw-r--r-- | src/mongo/db/query/get_runner.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/query/index_bounds_builder.cpp | 37 | ||||
-rw-r--r-- | src/mongo/db/query/index_bounds_builder.h | 58 | ||||
-rw-r--r-- | src/mongo/db/query/index_bounds_builder_test.cpp | 60 | ||||
-rw-r--r-- | src/mongo/db/query/index_entry.h | 31 | ||||
-rw-r--r-- | src/mongo/db/query/planner_access.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/query/planner_ixselect.cpp | 37 |
14 files changed, 224 insertions, 124 deletions
diff --git a/src/mongo/db/exec/2dnear.cpp b/src/mongo/db/exec/2dnear.cpp index 33093a8572d..ba80cea73fb 100644 --- a/src/mongo/db/exec/2dnear.cpp +++ b/src/mongo/db/exec/2dnear.cpp @@ -511,8 +511,7 @@ namespace twod_exec { // If we're not, and we're done with points, break if(! inWindow && expandedPoints >= _max) break; - bool expandApprox = !currPt.isExact() && - (!_uniqueDocs || (finish && _needDistance) || inWindow); + bool expandApprox = !currPt.isExact() && (!_uniqueDocs || finish || inWindow); if (expandApprox) { // Add new point(s). These will only be added in a radius of 2 * _distError diff --git a/src/mongo/db/exec/s2near.cpp b/src/mongo/db/exec/s2near.cpp index a30f89ed338..eabb4c3d550 100644 --- a/src/mongo/db/exec/s2near.cpp +++ b/src/mongo/db/exec/s2near.cpp @@ -41,10 +41,15 @@ namespace mongo { S2NearStage::S2NearStage(const S2NearParams& params, WorkingSet* ws) { + _initted = false; _params = params; _ws = ws; _worked = false; _failed = false; + } + + void S2NearStage::init() { + _initted = true; // The field we're near-ing from is the n-th field. Figure out what that 'n' is. We // put the cover for the search annulus in this spot in the bounds. @@ -74,8 +79,36 @@ namespace mongo { _innerRadius = _outerRadius = _minDistance; _outerRadiusInclusive = false; - // XXX: where do we grab finestIndexedLevel from really? idx descriptor? - int finestIndexedLevel = S2::kAvgEdge.GetClosestLevel(500.0 / kRadiusOfEarthInMeters); + // Grab the IndexDescriptor. + Database* db = cc().database(); + if (!db) { + _failed = true; + return; + } + + Collection* collection = db->getCollection(_params.ns); + if (!collection) { + _failed = true; + return; + } + + _descriptor = collection->getIndexCatalog()->findIndexByKeyPattern(_params.indexKeyPattern); + if (NULL == _descriptor) { + _failed = true; + return; + } + + // The user can override this so we honor it. We could ignore it though -- it's just used + // to set _radiusIncrement, not to do any covering. + int finestIndexedLevel; + BSONElement fl = _descriptor->infoObj()["finestIndexedLevel"]; + if (fl.isNumber()) { + finestIndexedLevel = fl.numberInt(); + } + else { + finestIndexedLevel = S2::kAvgEdge.GetClosestLevel(500.0 / kRadiusOfEarthInMeters); + } + // Start with a conservative _radiusIncrement. When we're done searching a shell we // increment the two radii by this. _radiusIncrement = 5 * S2::kAvgEdge.GetValue(finestIndexedLevel) * kRadiusOfEarthInMeters; @@ -88,6 +121,8 @@ namespace mongo { } PlanStage::StageState S2NearStage::work(WorkingSetID* out) { + if (!_initted) { init(); } + if (_failed) { return PlanStage::FAILURE; } if (isEOF()) { return PlanStage::IS_EOF; } ++_commonStats.works; @@ -113,7 +148,8 @@ namespace mongo { // Remove from invalidation map. WorkingSetMember* member = _ws->get(*out); if (member->hasLoc()) { - unordered_map<DiskLoc, WorkingSetID, DiskLoc::Hasher>::iterator it = _invalidationMap.find(member->loc); + unordered_map<DiskLoc, WorkingSetID, DiskLoc::Hasher>::iterator it + = _invalidationMap.find(member->loc); verify(_invalidationMap.end() != it); _invalidationMap.erase(it); } @@ -161,32 +197,15 @@ namespace mongo { _annulus.Release(NULL); _annulus.Init(®ions); - _params.baseBounds.fields[_nearFieldIndex].intervals.clear(); - ExpressionMapping::cover2dsphere(_annulus, &_params.baseBounds.fields[_nearFieldIndex]); - // Step 3: Actually create the ixscan. - // TODO: Cache params. - - Database* db = cc().database(); - if ( !db ) { - _failed = true; - return; - } - - Collection* collection = db->getCollection( _params.ns ); - if ( !collection ) { - _failed = true; - return; - } IndexScanParams params; - params.descriptor = - collection->getIndexCatalog()->findIndexByKeyPattern(_params.indexKeyPattern ); + params.descriptor = _descriptor; + _params.baseBounds.fields[_nearFieldIndex].intervals.clear(); + ExpressionMapping::cover2dsphere(_annulus, + params.descriptor->infoObj(), + &_params.baseBounds.fields[_nearFieldIndex]); - if ( !params.descriptor ) { - _failed = true; - return; - } params.bounds = _params.baseBounds; params.direction = 1; IndexScan* scan = new IndexScan(params, _ws, NULL); diff --git a/src/mongo/db/exec/s2near.h b/src/mongo/db/exec/s2near.h index 9f1513d3235..87613908f6f 100644 --- a/src/mongo/db/exec/s2near.h +++ b/src/mongo/db/exec/s2near.h @@ -33,6 +33,7 @@ #include "mongo/db/exec/plan_stage.h" #include "mongo/db/geo/geoquery.h" #include "mongo/db/geo/s2common.h" +#include "mongo/db/index/index_descriptor.h" #include "mongo/db/jsobj.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/query/index_bounds.h" @@ -75,6 +76,7 @@ namespace mongo { PlanStageStats* getStats(); private: + void init(); StageState addResultToQueue(WorkingSetID* out); void nextAnnulus(); @@ -137,6 +139,12 @@ namespace mongo { // Did we encounter an unrecoverable error? bool _failed; + // Have we init()'d yet? + bool _initted; + + // What index are we searching over? + IndexDescriptor* _descriptor; + CommonStats _commonStats; }; diff --git a/src/mongo/db/exec/sort.cpp b/src/mongo/db/exec/sort.cpp index de55f0b7a67..33fb68aadb0 100644 --- a/src/mongo/db/exec/sort.cpp +++ b/src/mongo/db/exec/sort.cpp @@ -217,7 +217,7 @@ namespace mongo { params.options = QueryPlannerParams::NO_TABLE_SCAN; // We're creating a "virtual index" with key pattern equal to the sort order. - IndexEntry sortOrder(sortObj, true, false, "doesnt_matter"); + IndexEntry sortOrder(sortObj, true, false, "doesnt_matter", BSONObj()); params.indices.push_back(sortOrder); CanonicalQuery* rawQueryForSort; diff --git a/src/mongo/db/geo/core.h b/src/mongo/db/geo/core.h index 29688a2a411..ca4b7138be7 100644 --- a/src/mongo/db/geo/core.h +++ b/src/mongo/db/geo/core.h @@ -46,16 +46,4 @@ namespace mongo { cos(deg2rad(max(-89.0, y - maxDistDegrees)))); } - inline bool twoDWontWrap(double x, double y, double radius) { - // XXX XXX XXX SERVER-11387 - // The 0.001 for error is totally bogus and must depend on the bits used. - double yscandist = rad2deg(radius) + 0.001; - double xscandist = computeXScanDistance(y, yscandist); - bool ret = x + xscandist < 180 - && x - xscandist > -180 - && y + yscandist < 90 - && y - yscandist > -90; - return ret; - } - } diff --git a/src/mongo/db/index/expression_index.h b/src/mongo/db/index/expression_index.h index d172af5836b..3806b1e1c4b 100644 --- a/src/mongo/db/index/expression_index.h +++ b/src/mongo/db/index/expression_index.h @@ -47,11 +47,20 @@ namespace mongo { return bob.obj(); } - static void cover2dsphere(const S2Region& region, OrderedIntervalList* oilOut) { - // XXX: should grab coarsest level from the index since the user can possibly change it. - int coarsestIndexedLevel = - S2::kAvgEdge.GetClosestLevel(100 * 1000.0 / kRadiusOfEarthInMeters); + // TODO: what should we really pass in for indexInfoObj? + static void cover2dsphere(const S2Region& region, + const BSONObj& indexInfoObj, + OrderedIntervalList* oilOut) { + int coarsestIndexedLevel; + BSONElement ce = indexInfoObj["coarsestIndexedLevel"]; + if (ce.isNumber()) { + coarsestIndexedLevel = ce.numberInt(); + } + else { + coarsestIndexedLevel = + S2::kAvgEdge.GetClosestLevel(100 * 1000.0 / kRadiusOfEarthInMeters); + } // The min level of our covering is the level whose cells are the closest match to the // *area* of the region (or the max indexed level, whichever is smaller) The max level diff --git a/src/mongo/db/index/s2_access_method.h b/src/mongo/db/index/s2_access_method.h index 5736d4cb8ce..b3a34b4e679 100644 --- a/src/mongo/db/index/s2_access_method.h +++ b/src/mongo/db/index/s2_access_method.h @@ -49,9 +49,6 @@ namespace mongo { virtual Status newCursor(IndexCursor** out) const; private: - friend class Geo2dFindNearCmd; - const S2IndexingParams& getParams() const { return _params; } - virtual void getKeys(const BSONObj& obj, BSONObjSet* keys); // getKeys calls the helper methods below. diff --git a/src/mongo/db/query/get_runner.cpp b/src/mongo/db/query/get_runner.cpp index d3c020ba557..e33785a777d 100644 --- a/src/mongo/db/query/get_runner.cpp +++ b/src/mongo/db/query/get_runner.cpp @@ -130,7 +130,8 @@ namespace mongo { plannerParams.indices.push_back(IndexEntry(desc->keyPattern(), desc->isMultikey(), desc->isSparse(), - desc->indexName())); + desc->indexName(), + desc->infoObj())); } // Tailable: If the query requests tailable the collection must be capped. diff --git a/src/mongo/db/query/index_bounds_builder.cpp b/src/mongo/db/query/index_bounds_builder.cpp index 23c5e524743..44cd185b9fe 100644 --- a/src/mongo/db/query/index_bounds_builder.cpp +++ b/src/mongo/db/query/index_bounds_builder.cpp @@ -178,18 +178,26 @@ namespace mongo { } // static - void IndexBoundsBuilder::translateAndIntersect(const MatchExpression* expr, const BSONElement& elt, - OrderedIntervalList* oilOut, BoundsTightness* tightnessOut) { + void IndexBoundsBuilder::translateAndIntersect(const MatchExpression* expr, + const BSONElement& elt, + const IndexEntry& index, + OrderedIntervalList* oilOut, + BoundsTightness* tightnessOut) { OrderedIntervalList arg; - translate(expr, elt, &arg, tightnessOut); - // translate outputs arg in sorted order. intersectize assumes that its arguments are sorted. + translate(expr, elt, index, &arg, tightnessOut); + + // translate outputs arg in sorted order. intersectize assumes that its arguments are + // sorted. intersectize(arg, oilOut); } // static - void IndexBoundsBuilder::translateAndUnion(const MatchExpression* expr, const BSONElement& elt, - OrderedIntervalList* oilOut, BoundsTightness* tightnessOut) { - translate(expr, elt, oilOut, tightnessOut); + void IndexBoundsBuilder::translateAndUnion(const MatchExpression* expr, + const BSONElement& elt, + const IndexEntry& index, + OrderedIntervalList* oilOut, + BoundsTightness* tightnessOut) { + translate(expr, elt, index, oilOut, tightnessOut); unionize(oilOut); } @@ -203,8 +211,11 @@ namespace mongo { } // static - void IndexBoundsBuilder::translate(const MatchExpression* expr, const BSONElement& elt, - OrderedIntervalList* oilOut, BoundsTightness* tightnessOut) { + void IndexBoundsBuilder::translate(const MatchExpression* expr, + const BSONElement& elt, + const IndexEntry& index, + OrderedIntervalList* oilOut, + BoundsTightness* tightnessOut) { oilOut->name = elt.fieldName(); bool isHashed = false; @@ -219,12 +230,12 @@ namespace mongo { if (MatchExpression::ELEM_MATCH_VALUE == expr->matchType()) { OrderedIntervalList acc; - translate(expr->getChild(0), elt, &acc, tightnessOut); + translate(expr->getChild(0), elt, index, &acc, tightnessOut); for (size_t i = 1; i < expr->numChildren(); ++i) { OrderedIntervalList next; BoundsTightness tightness; - translate(expr->getChild(i), elt, &next, &tightness); + translate(expr->getChild(i), elt, index, &next, &tightness); intersectize(next, &acc); } @@ -235,6 +246,7 @@ namespace mongo { if (!oilOut->intervals.empty()) { std::sort(oilOut->intervals.begin(), oilOut->intervals.end(), IntervalComparison); } + // $elemMatch value requires an array. // Scalars and directly nested objects are not matched with $elemMatch. // We can't tell if a multi-key index key is derived from an array field. @@ -293,7 +305,6 @@ namespace mongo { bob.appendAs(dataElt, ""); BSONObj dataObj = bob.obj(); verify(dataObj.isOwned()); - QLOG() << "data obj is " << dataObj.toString() << endl; Interval interval = makeRangeInterval(dataObj, typeMatch(dataObj), false); // If the operand to LT is equal to the lower bound X, the interval [X, X) is invalid @@ -427,7 +438,7 @@ namespace mongo { } const S2Region& region = gme->getGeoQuery().getRegion(); - ExpressionMapping::cover2dsphere(region, oilOut); + ExpressionMapping::cover2dsphere(region, index.infoObj, oilOut); *tightnessOut = IndexBoundsBuilder::INEXACT_FETCH; } else { diff --git a/src/mongo/db/query/index_bounds_builder.h b/src/mongo/db/query/index_bounds_builder.h index 9a4bfe8e75e..bf9413bda0e 100644 --- a/src/mongo/db/query/index_bounds_builder.h +++ b/src/mongo/db/query/index_bounds_builder.h @@ -32,6 +32,7 @@ #include "mongo/db/hasher.h" #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/query/index_bounds.h" +#include "mongo/db/query/index_entry.h" namespace mongo { @@ -40,12 +41,13 @@ namespace mongo { */ class IndexBoundsBuilder { public: - enum BoundsTightness { // Index bounds are exact. EXACT, + // Index bounds are inexact, and a fetch is required. INEXACT_FETCH, + // Index bounds are inexact, but no fetch is required INEXACT_COVERED }; @@ -57,30 +59,39 @@ namespace mongo { static void allValuesForField(const BSONElement& elt, OrderedIntervalList* out); /** - * Turn the MatchExpression in 'expr' into a set of index bounds. The field that 'expr' - * is concerned with is indexed according to the keypattern element 'elt'. + * Turn the MatchExpression in 'expr' into a set of index bounds. The field that 'expr' is + * concerned with is indexed according to the keypattern element 'elt' from index 'index'. * * If 'expr' is elemMatch, the index tag is affixed to a child. * * The expression must be a predicate over one field. That is, expr->isLeaf() or * expr->isArray() must be true, and expr->isLogical() must be false. */ - static void translate(const MatchExpression* expr, const BSONElement& elt, - OrderedIntervalList* oilOut, BoundsTightness* tightnessOut); + static void translate(const MatchExpression* expr, + const BSONElement& elt, + const IndexEntry& index, + OrderedIntervalList* oilOut, + BoundsTightness* tightnessOut); /** * Creates bounds for 'expr' (indexed according to 'elt'). Intersects those bounds * with the bounds in oilOut, which is an in/out parameter. */ - static void translateAndIntersect(const MatchExpression* expr, const BSONElement& elt, - OrderedIntervalList* oilOut, BoundsTightness* tightnessOut); + static void translateAndIntersect(const MatchExpression* expr, + const BSONElement& elt, + const IndexEntry& index, + OrderedIntervalList* oilOut, + BoundsTightness* tightnessOut); /** * Creates bounds for 'expr' (indexed according to 'elt'). Unions those bounds * with the bounds in oilOut, which is an in/out parameter. */ - static void translateAndUnion(const MatchExpression* expr, const BSONElement& elt, - OrderedIntervalList* oilOut, BoundsTightness* tightnessOut); + static void translateAndUnion(const MatchExpression* expr, + const BSONElement& elt, + const IndexEntry& index, + OrderedIntervalList* oilOut, + BoundsTightness* tightnessOut); /** * Make a range interval from the provided object. @@ -89,10 +100,14 @@ namespace mongo { * The two inclusive flags indicate whether or not the start/end fields are included in the * interval (closed interval if included, open if not). */ - static Interval makeRangeInterval(const BSONObj& obj, bool startInclusive, + static Interval makeRangeInterval(const BSONObj& obj, + bool startInclusive, + bool endInclusive); + + static Interval makeRangeInterval(const string& start, + const string& end, + bool startInclusive, bool endInclusive); - static Interval makeRangeInterval(const string& start, const string& end, - bool startInclusive, bool endInclusive); /** * Make a point interval from the provided object. @@ -121,18 +136,27 @@ namespace mongo { * * used to optimize queries in some simple regex cases that start with '^' */ - static string simpleRegex(const char* regex, const char* flags, BoundsTightness* tightnessOut); + static string simpleRegex(const char* regex, + const char* flags, + BoundsTightness* tightnessOut); + /** + * Returns an Interval from minKey to maxKey + */ static Interval allValues(); - static void translateRegex(const RegexMatchExpression* rme, OrderedIntervalList* oil, + static void translateRegex(const RegexMatchExpression* rme, + OrderedIntervalList* oil, BoundsTightness* tightnessOut); - static void translateEquality(const BSONElement& data, bool isHashed, - OrderedIntervalList* oil, BoundsTightness* tightnessOut); + static void translateEquality(const BSONElement& data, + bool isHashed, + OrderedIntervalList* oil, + BoundsTightness* tightnessOut); static void unionize(OrderedIntervalList* oilOut); - static void intersectize(const OrderedIntervalList& arg, OrderedIntervalList* oilOut); + static void intersectize(const OrderedIntervalList& arg, + OrderedIntervalList* oilOut); }; } // namespace mongo diff --git a/src/mongo/db/query/index_bounds_builder_test.cpp b/src/mongo/db/query/index_bounds_builder_test.cpp index 9bb8387d891..b236c8d7847 100644 --- a/src/mongo/db/query/index_bounds_builder_test.cpp +++ b/src/mongo/db/query/index_bounds_builder_test.cpp @@ -49,6 +49,8 @@ namespace { double negativeInfinity = -numeric_limits<double>::infinity(); double positiveInfinity = numeric_limits<double>::infinity(); + IndexEntry testIndex = IndexEntry(BSONObj()); + /** * Utility function to create MatchExpression */ @@ -71,10 +73,10 @@ namespace { auto_ptr<MatchExpression> expr(parseMatchExpression(*it)); BSONElement elt = it->firstElement(); if (toUnion.begin() == it) { - IndexBoundsBuilder::translate(expr.get(), elt, oilOut, tightnessOut); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, oilOut, tightnessOut); } else { - IndexBoundsBuilder::translateAndUnion(expr.get(), elt, oilOut, tightnessOut); + IndexBoundsBuilder::translateAndUnion(expr.get(), elt, testIndex, oilOut, tightnessOut); } } } @@ -91,10 +93,10 @@ namespace { auto_ptr<MatchExpression> expr(parseMatchExpression(*it)); BSONElement elt = it->firstElement(); if (toIntersect.begin() == it) { - IndexBoundsBuilder::translate(expr.get(), elt, oilOut, tightnessOut); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, oilOut, tightnessOut); } else { - IndexBoundsBuilder::translateAndIntersect(expr.get(), elt, oilOut, tightnessOut); + IndexBoundsBuilder::translateAndIntersect(expr.get(), elt, testIndex, oilOut, tightnessOut); } } } @@ -117,13 +119,13 @@ namespace { auto_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); if (constraints.begin() == it) { - IndexBoundsBuilder::translate(expr.get(), elt, oilOut, tightnessOut); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, oilOut, tightnessOut); } else if (isIntersect) { - IndexBoundsBuilder::translateAndIntersect(expr.get(), elt, oilOut, tightnessOut); + IndexBoundsBuilder::translateAndIntersect(expr.get(), elt, testIndex, oilOut, tightnessOut); } else { - IndexBoundsBuilder::translateAndUnion(expr.get(), elt, oilOut, tightnessOut); + IndexBoundsBuilder::translateAndUnion(expr.get(), elt, testIndex, oilOut, tightnessOut); } } } @@ -141,7 +143,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -159,7 +161,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -173,7 +175,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -187,7 +189,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -201,7 +203,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -215,7 +217,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -229,7 +231,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 0U); ASSERT_EQUALS(tightness, IndexBoundsBuilder::EXACT); @@ -241,7 +243,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -255,7 +257,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -269,7 +271,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -283,7 +285,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 0U); ASSERT_EQUALS(tightness, IndexBoundsBuilder::EXACT); @@ -295,7 +297,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -309,7 +311,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -323,7 +325,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -337,7 +339,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -351,7 +353,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -365,7 +367,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 2U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -381,7 +383,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 4U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -401,7 +403,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 3U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -587,7 +589,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.name, "a"); ASSERT_EQUALS(oil.intervals.size(), 1U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( @@ -722,7 +724,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.intervals.size(), 2U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( Interval(fromjson("{'': '', '': {}}"), true, false))); @@ -737,7 +739,7 @@ namespace { BSONElement elt = obj.firstElement(); OrderedIntervalList oil; IndexBoundsBuilder::BoundsTightness tightness; - IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness); + IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness); ASSERT_EQUALS(oil.intervals.size(), 2U); ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare( Interval(fromjson("{'': 'foo', '': 'fop'}"), true, false))); diff --git a/src/mongo/db/query/index_entry.h b/src/mongo/db/query/index_entry.h index f5a7f0288c9..0b772438347 100644 --- a/src/mongo/db/query/index_entry.h +++ b/src/mongo/db/query/index_entry.h @@ -39,15 +39,16 @@ namespace mongo { * This name sucks, but every name involving 'index' is used somewhere. */ struct IndexEntry { - IndexEntry(const BSONObj& kp, bool mk, bool sp, const string& n) - : keyPattern(kp), multikey(mk), sparse(sp), name(n) { } - - IndexEntry(const IndexEntry& other) { - keyPattern = other.keyPattern; - multikey = other.multikey; - sparse = other.sparse; - name = other.name; - } + IndexEntry(const BSONObj& kp, + bool mk = false, + bool sp = false, + const string& n = "default_name", + const BSONObj& io = BSONObj()) + : keyPattern(kp), + multikey(mk), + sparse(sp), + name(n), + infoObj(io) { } BSONObj keyPattern; @@ -57,15 +58,25 @@ namespace mongo { string name; + // Geo indices have extra parameters. We need those available to plan correctly. + BSONObj infoObj; + std::string toString() const { stringstream ss; - ss << keyPattern.toString(); + ss << "kp: " << keyPattern.toString(); + if (multikey) { ss << " multikey"; } + if (sparse) { ss << " sparse"; } + + if (!infoObj.isEmpty()) { + ss << " io: " << infoObj.toString(); + } + return ss.str(); } }; diff --git a/src/mongo/db/query/planner_access.cpp b/src/mongo/db/query/planner_access.cpp index 16245186bae..a30406da5d3 100644 --- a/src/mongo/db/query/planner_access.cpp +++ b/src/mongo/db/query/planner_access.cpp @@ -156,7 +156,7 @@ namespace mongo { isn->maxScan = query.getParsed().getMaxScan(); isn->addKeyMetadata = query.getParsed().returnKey(); - IndexBoundsBuilder::translate(expr, index.keyPattern.firstElement(), + IndexBoundsBuilder::translate(expr, index.keyPattern.firstElement(), index, &isn->bounds.fields[0], tightnessOut); // QLOG() << "bounds are " << isn->bounds.toString() << " exact " << *exact << endl; @@ -212,15 +212,15 @@ namespace mongo { OrderedIntervalList* oil = &boundsToFillOut->fields[pos]; if (boundsToFillOut->fields[pos].name.empty()) { - IndexBoundsBuilder::translate(expr, keyElt, oil, tightnessOut); + IndexBoundsBuilder::translate(expr, keyElt, index, oil, tightnessOut); } else { if (MatchExpression::AND == mergeType) { - IndexBoundsBuilder::translateAndIntersect(expr, keyElt, oil, tightnessOut); + IndexBoundsBuilder::translateAndIntersect(expr, keyElt, index, oil, tightnessOut); } else { verify(MatchExpression::OR == mergeType); - IndexBoundsBuilder::translateAndUnion(expr, keyElt, oil, tightnessOut); + IndexBoundsBuilder::translateAndUnion(expr, keyElt, index, oil, tightnessOut); } } } diff --git a/src/mongo/db/query/planner_ixselect.cpp b/src/mongo/db/query/planner_ixselect.cpp index b176b2c4d7c..5f126eacb29 100644 --- a/src/mongo/db/query/planner_ixselect.cpp +++ b/src/mongo/db/query/planner_ixselect.cpp @@ -31,6 +31,7 @@ #include <vector> #include "mongo/db/geo/core.h" +#include "mongo/db/geo/hash.h" #include "mongo/db/matcher/expression_array.h" #include "mongo/db/matcher/expression_geo.h" #include "mongo/db/matcher/expression_text.h" @@ -41,6 +42,36 @@ namespace mongo { + static double fieldWithDefault(const BSONObj& infoObj, const string& name, double def) { + BSONElement e = infoObj[name]; + if (e.isNumber()) { return e.numberDouble(); } + return def; + } + + /** + * 2d indices don't handle wrapping so we can't use them for queries that wrap. + */ + static bool twoDWontWrap(const Circle& circle, const IndexEntry& index) { + // XXX: where does this really belong + GeoHashConverter::Parameters params; + params.bits = static_cast<unsigned>(fieldWithDefault(index.infoObj, "bits", 26)); + params.max = fieldWithDefault(index.infoObj, "max", 180.0); + params.min = fieldWithDefault(index.infoObj, "min", -180.0); + double numBuckets = (1024 * 1024 * 1024 * 4.0); + params.scaling = numBuckets / (params.max - params.min); + + GeoHashConverter conv(params); + + // FYI: old code used flat not spherical error. + double yscandist = rad2deg(circle.radius) + conv.getErrorSphere(); + double xscandist = computeXScanDistance(circle.center.y, yscandist); + bool ret = circle.center.x + xscandist < 180 + && circle.center.x - xscandist > -180 + && circle.center.y + yscandist < 90 + && circle.center.y - yscandist > -90; + return ret; + } + // static void QueryPlannerIXSelect::getFields(MatchExpression* node, string prefix, @@ -163,10 +194,10 @@ namespace mongo { } verify(SPHERE == gc._cap->crs); - // No wrapping in 2d centerSphere, don't use 2d index for that. const Circle& circle = gc._cap->circle; - // An overestimate. - return twoDWontWrap(circle.center.x, circle.center.y, circle.radius); + + // No wrapping around the edge of the world is allowed in 2d centerSphere. + return twoDWontWrap(circle, index); } return false; } |