Permalink
Browse files

double bounds for geo query scaling and addn'l error msgs SERVER-2386…

… SERVER-2388
  • Loading branch information...
1 parent f14bb06 commit 729f9caf51e2c82aa9a1b2493829b827610748ab gregs committed Mar 15, 2011
Showing with 127 additions and 31 deletions.
  1. +15 −13 db/geo/2d.cpp
  2. +3 −6 jstests/geo10.js
  3. +1 −1 jstests/geo4.js
  4. +1 −4 jstests/geo_borders.js
  5. +88 −0 jstests/geo_small_large.js
  6. +19 −7 jstests/libs/geo_near_random.js
View
@@ -98,14 +98,18 @@ namespace mongo {
uassert( 13024 , "no geo field specified" , _geo.size() );
- _bits = _configval( spec , "bits" , 26 ); // for lat/long, ~ 1ft
+ double bits = _configval( spec , "bits" , 26 ); // for lat/long, ~ 1ft
- uassert( 13028 , "can't have more than 32 bits in geo index" , _bits <= 32 );
+ uassert( 13028 , "bits in geo index must be between 1 and 32" , bits > 0 && bits <= 32 );
- _max = _configval( spec , "max" , 180 );
- _min = _configval( spec , "min" , -180 );
+ _bits = (unsigned) bits;
- _scaling = (1024*1024*1024*4.0)/(_max-_min);
+ _max = _configval( spec , "max" , 180.0 );
+ _min = _configval( spec , "min" , -180.0 );
+
+ double numBuckets = (1024 * 1024 * 1024 * 4.0);
+
+ _scaling = numBuckets / ( _max - _min );
_order = orderBuilder.obj();
@@ -115,12 +119,10 @@ namespace mongo {
_error = distance(a, b);
}
- int _configval( const IndexSpec* spec , const string& name , int def ) {
+ double _configval( const IndexSpec* spec , const string& name , double def ) {
BSONElement e = spec->info[name];
if ( e.isNumber() ){
- // Check that our values are not too big or small
- uassert_msg(15073, "Value " << e.numberLong() << " exceeds integer bounds.", e.numberLong() == e.numberInt() )
- return e.numberInt();
+ return e.numberDouble();
}
return def;
}
@@ -234,9 +236,9 @@ namespace mongo {
}
unsigned _convert( double in ) const {
- uassert( 13027 , "point not in range" , in <= (_max + _error) && in >= (_min - _error) );
+ uassert_msg( 13027 , "point not in range between " << _min << " and " << _max, in <= (_max + _error) && in >= (_min - _error) );
in -= _min;
- uassert( 14021 , "point not in range" , in > 0 );
+ uassert_msg( 14021 , "point not in range > " << _min , in > 0 );
return (unsigned)(in * _scaling);
}
@@ -317,8 +319,8 @@ namespace mongo {
vector<string> _other;
unsigned _bits;
- int _max;
- int _min;
+ double _max;
+ double _min;
double _scaling;
BSONObj _order;
View
@@ -3,22 +3,19 @@
coll = db.geo10
coll.drop();
-db.geo10.ensureIndex( { c : '2d', t : 1 }, { min : 0, max : Math.pow( 2, 31 ) } )
-assert( db.getLastError(), "A0" )
-assert( db.system.indexes.count({ ns : "test.geo10" }) == 1, "A1" )
-
-db.geo10.ensureIndex( { c : '2d', t : 1 }, { min : 0, max : Math.pow( 2, 30 ) } )
+db.geo10.ensureIndex( { c : '2d', t : 1 }, { min : 0, max : Math.pow( 2, 40 ) } )
assert( db.getLastError() == null, "B" )
assert( db.system.indexes.count({ ns : "test.geo10" }) == 2, "A3" )
printjson( db.system.indexes.find().toArray() )
db.geo10.insert( { c : [ 1, 1 ], t : 1 } )
-assert( db.getLastError() == null, "C" )
+assert.eq( db.getLastError(), null, "C" )
db.geo10.insert( { c : [ 3600, 3600 ], t : 1 } )
assert( db.getLastError() == null, "D" )
db.geo10.insert( { c : [ 0.001, 0.001 ], t : 1 } )
assert( db.getLastError() == null, "E" )
+printjson( db.geo10.find({ c : { $within : { $box : [[0.001, 0.001], [Math.pow(2, 40) - 0.001, Math.pow(2, 40) - 0.001]] } }, t : 1 }).toArray() )
View
@@ -4,7 +4,7 @@ t.drop();
t.insert( { zip : "06525" , loc : [ 41.352964 , 73.01212 ] } );
t.ensureIndex( { loc : "2d" }, { bits : 33 } );
-assert.eq( db.getLastError() , "can't have more than 32 bits in geo index" , "a" );
+assert.eq( db.getLastError() , "bits in geo index must be between 1 and 32" , "a" );
t.ensureIndex( { loc : "2d" }, { bits : 32 } );
assert( !db.getLastError(), "b" );
@@ -2,9 +2,7 @@
t = db.borders
t.drop()
-// FIXME: FAILS for all epsilon < 1
-epsilon = 1
-//epsilon = 0.99
+epsilon = 0.0001;
// For these tests, *required* that step ends exactly on max
min = -1
@@ -26,7 +24,6 @@ overallMax = 1
t.ensureIndex({ loc : "2d" }, { max : overallMax - epsilon / 2, min : overallMin + epsilon / 2})
assert(db.getLastError(), "A1")
-// FIXME: FAILS for all epsilon < 1
// Create a point index only slightly bigger than the points we have
t.ensureIndex({ loc : "2d" }, { max : overallMax + epsilon, min : overallMin - epsilon })
assert.isnull(db.getLastError(), "A2")
@@ -0,0 +1,88 @@
+// SERVER-2386, general geo-indexing using very large and very small bounds
+
+load( "jstests/libs/geo_near_random.js" );
+
+// Do some random tests (for near queries) with very large and small ranges
+
+var test = new GeoNearRandomTest( "geo_small_large" );
+
+bounds = { min : -Math.pow( 2, 34 ), max : Math.pow( 2, 34 ) };
+
+test.insertPts( 50, bounds );
+
+printjson( db["geo_small_large"].find().limit( 10 ).toArray() )
+
+test.testPt( [ 0, 0 ] );
+test.testPt( test.mkPt( undefined, bounds ) );
+test.testPt( test.mkPt( undefined, bounds ) );
+test.testPt( test.mkPt( undefined, bounds ) );
+test.testPt( test.mkPt( undefined, bounds ) );
+
+test = new GeoNearRandomTest( "geo_small_large" );
+
+bounds = { min : -Math.pow( 2, -34 ), max : Math.pow( 2, -34 ) };
+
+test.insertPts( 50, bounds );
+
+printjson( db["geo_small_large"].find().limit( 10 ).toArray() )
+
+test.testPt( [ 0, 0 ] );
+test.testPt( test.mkPt( undefined, bounds ) );
+test.testPt( test.mkPt( undefined, bounds ) );
+test.testPt( test.mkPt( undefined, bounds ) );
+test.testPt( test.mkPt( undefined, bounds ) );
+
+
+// Check that our box and circle queries also work
+var scales = [ Math.pow( 2, 40 ), Math.pow( 2, -40 ), Math.pow(2, 2), Math.pow(3, -15), Math.pow(3, 15) ]
+
+for ( var i = 0; i < scales.length; i++ ) {
+
+ scale = scales[i];
+
+ var eps = Math.pow( 2, -7 ) * scale;
+ var radius = 5 * scale;
+ var max = 10 * scale;
+ var min = -max;
+ var range = max - min;
+
+ var t = db["geo_small_large"]
+ t.drop();
+ t.ensureIndex( { p : "2d" }, { min : min, max : max, bits : 20 + Math.random() * 10 })
+
+ var outPoints = 0;
+ var inPoints = 0;
+
+ // Put a point slightly inside and outside our range
+ for ( var j = 0; j < 2; j++ ) {
+ var currRad = ( j % 2 == 0 ? radius + eps : radius - eps );
+ t.insert( { p : { x : currRad, y : 0 } } );
+ print( db.getLastError() )
+ }
+
+ printjson( t.find().toArray() );
+
+ assert.eq( t.count( { p : { $within : { $center : [[0, 0], radius ] } } } ), 1, "Incorrect center points found!" )
+ assert.eq( t.count( { p : { $within : { $box : [ [ -radius, -radius ], [ radius, radius ] ] } } } ), 1,
+ "Incorrect box points found!" )
+
+ for ( var j = 0; j < 30; j++ ) {
+
+ var x = Math.random() * ( range - eps ) + eps + min;
+ var y = Math.random() * ( range - eps ) + eps + min;
+
+ t.insert( { p : [ x, y ] } );
+
+ if ( x * x + y * y > radius * radius )
+ outPoints++
+ else
+ inPoints++
+ }
+
+ assert.eq( t.count( { p : { $within : { $center : [[0, 0], radius ] } } } ), 1 + inPoints,
+ "Incorrect random center points found!" )
+
+ print("Found " + inPoints + " points in and " + outPoints + " points out.");
+
+}
+
@@ -11,20 +11,32 @@ GeoNearRandomTest = function(name) {
}
-GeoNearRandomTest.prototype.mkPt = function mkPt(scale){
- scale = scale || 1; // scale is good for staying away from edges
- return [((Random.rand() * 359.8) - 179.9) * scale, ((Random.rand() * 180) - 90) * scale];
+GeoNearRandomTest.prototype.mkPt = function mkPt(scale, indexBounds){
+ if(!indexBounds){
+ scale = scale || 1; // scale is good for staying away from edges
+ return [((Random.rand() * 359.8) - 179.9) * scale, ((Random.rand() * 180) - 90) * scale];
+ }
+ else{
+ var range = indexBounds.max - indexBounds.min;
+ var eps = Math.pow(2, -40);
+ // Go very close to the borders but not quite there.
+ return [( Random.rand() * (range - eps) + eps) + indexBounds.min, ( Random.rand() * (range - eps) + eps ) + indexBounds.min];
+ }
+
}
-GeoNearRandomTest.prototype.insertPts = function(nPts) {
+GeoNearRandomTest.prototype.insertPts = function(nPts, indexBounds) {
assert.eq(this.nPts, 0, "insertPoints already called");
this.nPts = nPts;
for (var i=0; i<nPts; i++){
- this.t.insert({_id: i, loc: this.mkPt()});
+ this.t.insert({_id: i, loc: this.mkPt(undefined, indexBounds)});
}
-
- this.t.ensureIndex({loc: '2d'});
+
+ if(!indexBounds)
+ this.t.ensureIndex({loc: '2d'});
+ else
+ this.t.ensureIndex({loc: '2d'}, indexBounds)
}
GeoNearRandomTest.prototype.assertIsPrefix = function(short, long) {

0 comments on commit 729f9ca

Please sign in to comment.