2
* Copyright (C) 2012 10gen Inc.
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU Affero General Public License, version 3,
6
* as published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU Affero General Public License for more details.
13
* You should have received a copy of the GNU Affero General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18
#include "mongo/db/jsobj.h"
19
#include "mongo/db/commands.h"
20
#include "mongo/db/btreecursor.h"
21
#include "mongo/db/cursor.h"
22
#include "mongo/db/diskloc.h"
23
#include "mongo/db/matcher.h"
24
#include "mongo/db/queryutil.h"
25
#include "mongo/db/geo/s2common.h"
26
#include "mongo/db/geo/geoquery.h"
27
#include "mongo/platform/unordered_set.h"
28
#include "third_party/s2/s2cap.h"
29
#include "third_party/s2/s2regionintersection.h"
32
class S2NearCursor : public Cursor {
34
S2NearCursor(const BSONObj &keyPattern, const IndexDetails* details, const BSONObj &query,
35
const NearQuery &nearQuery, const vector<GeoQuery> &indexedGeoRegions,
36
const S2IndexingParams ¶ms);
37
virtual ~S2NearCursor();
38
virtual CoveredIndexMatcher *matcher() const;
40
virtual bool supportYields() { return true; }
41
virtual bool supportGetMore() { return true; }
42
virtual bool isMultiKey() const { return true; }
43
virtual bool autoDedup() const { return false; }
44
virtual bool modifiedKeys() const { return true; }
45
virtual bool getsetdup(DiskLoc loc) { return false; }
46
virtual string toString() { return "S2NearCursor"; }
47
BSONObj indexKeyPattern() { return _keyPattern; }
49
virtual Record* _current();
50
virtual BSONObj current();
51
virtual DiskLoc currLoc();
52
virtual bool advance();
53
virtual BSONObj currKey() const;
54
virtual DiskLoc refLoc();
55
virtual void noteLocation();
56
virtual void checkLocation();
57
virtual long long nscanned();
58
virtual void explainDetails(BSONObjBuilder& b);
60
double currentDistance() const;
62
// We use this to cache results of the search. Results are sorted to have decreasing
63
// distance, and callers are interested in loc and key.
65
Result(const DiskLoc &dl, const BSONObj &ck, double dist) : loc(dl), key(ck),
67
bool operator<(const Result& other) const {
68
// We want increasing distance, not decreasing, so we reverse the <.
69
return distance > other.distance;
76
// Make the object that describes all keys that are within our current search annulus.
77
BSONObj makeFRSObject();
78
// Fill _results with all of the results in the annulus defined by _innerRadius and
79
// _outerRadius. If no results are found, grow the annulus and repeat until success (or
80
// until the edge of the world).
82
// Grow _innerRadius and _outerRadius by _radiusIncrement, capping _outerRadius at halfway
83
// around the world (pi * _params.radius).
85
double distanceTo(const BSONObj &obj);
87
// Need this to make a FieldRangeSet.
88
const IndexDetails *_details;
90
// How we need/use the query:
91
// Matcher: Can have geo fields in it, but only with $within.
92
// This only really happens (right now) from geoNear command.
93
// We assume the caller takes care of this in the right way.
94
// FRS: No geo fields allowed!
95
// So, on that note: the query with the geo stuff taken out, used by makeFRSObject().
96
BSONObj _filteredQuery;
97
// The GeoQuery for the point we're doing near searching from.
99
// What geo regions are we looking for?
100
vector<GeoQuery> _indexedGeoFields;
101
// We use this for matching non-GEO stuff.
102
shared_ptr<CoveredIndexMatcher> _matcher;
103
// How were the keys created? We need this to search for the right stuff.
104
S2IndexingParams _params;
105
// We have to pass this to the FieldRangeVector ctor (in modified form).
107
// We also pass this to the FieldRangeVector ctor.
108
IndexSpec _specForFRV;
110
// Geo-related variables.
111
// What's the max distance (arc length) we're willing to look for results?
113
// We compute an annulus of results and cache it here.
114
priority_queue<Result> _results;
115
// These radii define the annulus we're currently looking at.
118
// When we search the next annulus, what to adjust our radius by? Grows when we search an
119
// annulus and find no results.
120
double _radiusIncrement;
121
// What have we returned already?
122
unordered_set<DiskLoc, DiskLoc::Hasher> _returned;
125
Stats() : _nscanned(0), _matchTested(0), _geoMatchTested(0), _numShells(0),
126
_keyGeoSkip(0), _returnSkip(0), _btreeDups(0), _inAnnulusTested(0),
128
// Stat counters/debug information goes below.
129
// How many items did we look at in the btree?
131
// How many did we try to match?
132
long long _matchTested;
133
// How many did we geo-test?
134
long long _geoMatchTested;
135
// How many search shells did we use?
136
long long _numShells;
137
// How many did we skip due to key-geo check?
138
long long _keyGeoSkip;
139
long long _returnSkip;
140
long long _btreeDups;
141
long long _inAnnulusTested;
142
long long _numReturned;
147
// The S2 machinery that represents the search annulus
150
S2RegionIntersection _annulus;
151
// This is the "array index" of the key field that is the near field. We use this to do
152
// cheap is-this-doc-in-the-annulus testing.
154
// The max distance we've returned so far.
155
double _returnedDistance;