1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
// @tags: [requires_fastcount, assumes_balancer_off]
t = db.geo_center_sphere1;
function test(index) {
t.drop();
skip = 8; // lower for more rigor, higher for more speed (tested with .5, .678, 1, 2, 3, and 4)
searches = [
// x , y rad
[[5, 0], 0.05], // ~200 miles
[[135, 0], 0.05],
[[5, 70], 0.05],
[[135, 70], 0.05],
[[5, 85], 0.05],
[[20, 0], 0.25], // ~1000 miles
[[20, -45], 0.25],
[[-20, 60], 0.25],
[[-20, -70], 0.25],
];
correct = searches.map(function(z) {
return [];
});
num = 0;
var bulk = t.initializeUnorderedBulkOp();
for (x = -179; x <= 179; x += skip) {
for (y = -89; y <= 89; y += skip) {
o = {_id: num++, loc: [x, y]};
bulk.insert(o);
for (i = 0; i < searches.length; i++) {
if (Geo.sphereDistance([x, y], searches[i][0]) <= searches[i][1])
correct[i].push(o);
}
}
gc(); // needed with low skip values
}
assert.writeOK(bulk.execute());
if (index) {
t.ensureIndex({loc: index});
}
for (i = 0; i < searches.length; i++) {
print('------------');
print(tojson(searches[i]) + "\t" + correct[i].length);
q = {loc: {$within: {$centerSphere: searches[i]}}};
// correct[i].forEach( printjson )
// printjson( q );
// t.find( q ).forEach( printjson )
// printjson(t.find( q ).explain())
// printjson( Array.sort( correct[i].map( function(z){ return z._id; } ) ) )
// printjson( Array.sort( t.find(q).map( function(z){ return z._id; } ) ) )
var numExpected = correct[i].length;
var x = correct[i].map(function(z) {
return z._id;
});
var y = t.find(q).map(function(z) {
return z._id;
});
missing = [];
epsilon = 0.001; // allow tenth of a percent error due to conversions
for (var j = 0; j < x.length; j++) {
if (!Array.contains(y, x[j])) {
missing.push(x[j]);
var obj = t.findOne({_id: x[j]});
var dist = Geo.sphereDistance(searches[i][0], obj.loc);
print("missing: " + tojson(obj) + " " + dist);
if ((Math.abs(dist - searches[i][1]) / dist) < epsilon)
numExpected -= 1;
}
}
for (var j = 0; j < y.length; j++) {
if (!Array.contains(x, y[j])) {
missing.push(y[j]);
var obj = t.findOne({_id: y[j]});
var dist = Geo.sphereDistance(searches[i][0], obj.loc);
print("extra: " + tojson(obj) + " " + dist);
if ((Math.abs(dist - searches[i][1]) / dist) < epsilon)
numExpected += 1;
}
}
assert.eq(numExpected, t.find(q).itcount(), "itcount : " + tojson(searches[i]));
assert.eq(numExpected, t.find(q).count(), "count : " + tojson(searches[i]));
if (index == "2d") {
var explain = t.find(q).explain("executionStats");
print('explain for ' + tojson(q, '', true) + ' = ' + tojson(explain));
// The index should be at least minimally effective in preventing the full collection
// scan.
assert.gt(t.find().count(),
explain.executionStats.totalKeysExamined,
"nscanned : " + tojson(searches[i]));
}
}
}
test("2d");
test("2dsphere");
test(false);
|