Skip to content

Commit ec6cec9

Browse files
committed
DATADOC-87 - Created GeoSpatialIndexed annotation and modified index creation listener to create geospatial indexes. Also added test case for same.
1 parent 4d79cdc commit ec6cec9

File tree

4 files changed

+241
-0
lines changed

4 files changed

+241
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) 2011 by the original author(s).
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.data.document.mongodb.index;
18+
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* Mark a class property to be indexed using MongoDB's geospatial indexing feature.
26+
*
27+
* @author Jon Brisbin <jbrisbin@vmware.com>
28+
*/
29+
@Target(ElementType.FIELD)
30+
@Retention(RetentionPolicy.RUNTIME)
31+
public @interface GeoSpatialIndexed {
32+
33+
/**
34+
* Name of the property in the document that contains the [x, y] or radial coordinates to index.
35+
*
36+
* @return
37+
*/
38+
String name() default "";
39+
40+
/**
41+
* Name of the collection in which to create the index.
42+
*
43+
* @return
44+
*/
45+
String collection() default "";
46+
47+
/**
48+
* Minimum value for indexed values.
49+
*
50+
* @return
51+
*/
52+
int min() default 0;
53+
54+
/**
55+
* Maximum value for indexed values.
56+
*
57+
* @return
58+
*/
59+
int max() default 0;
60+
61+
/**
62+
* Bits of precision for boundary calculations.
63+
*
64+
* @return
65+
*/
66+
int bits() default 26;
67+
68+
}

spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentEntityIndexCreator.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.data.document.mongodb.MongoTemplate;
3535
import org.springframework.data.document.mongodb.index.CompoundIndex;
3636
import org.springframework.data.document.mongodb.index.CompoundIndexes;
37+
import org.springframework.data.document.mongodb.index.GeoSpatialIndexed;
3738
import org.springframework.data.document.mongodb.index.IndexDirection;
3839
import org.springframework.data.document.mongodb.index.Indexed;
3940
import org.springframework.data.mapping.PropertyHandler;
@@ -130,6 +131,20 @@ public void doWithPersistentProperty(PersistentProperty persistentProperty) {
130131
if (log.isDebugEnabled()) {
131132
log.debug("Created property index " + index);
132133
}
134+
} else if (field.isAnnotationPresent(GeoSpatialIndexed.class)) {
135+
GeoSpatialIndexed index = field.getAnnotation(GeoSpatialIndexed.class);
136+
String name = index.name();
137+
if ("".equals(name)) {
138+
name = field.getName();
139+
}
140+
String collection = index.collection();
141+
if ("".equals(collection)) {
142+
collection = entity.getCollection();
143+
}
144+
ensureGeoIndex(collection, name, index.min(), index.max(), index.bits());
145+
if (log.isDebugEnabled()) {
146+
log.debug("Created geo index " + index);
147+
}
133148
}
134149
}
135150
});
@@ -167,4 +182,31 @@ public Object doInCollection(DBCollection collection) throws MongoException, Dat
167182
});
168183
}
169184

185+
protected void ensureGeoIndex(String collection,
186+
final String name,
187+
final int min,
188+
final int max,
189+
final int bits) {
190+
mongoTemplate.execute(collection, new CollectionCallback<Object>() {
191+
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
192+
DBObject defObj = new BasicDBObject();
193+
defObj.put(name, "2d");
194+
195+
DBObject opts = new BasicDBObject();
196+
// Min
197+
if (min != 0) {
198+
opts.put("min", min);
199+
}
200+
// Max
201+
if (max != 0) {
202+
opts.put("max", max);
203+
}
204+
// Bits
205+
opts.put("bits", bits);
206+
collection.ensureIndex(defObj, opts);
207+
return null;
208+
}
209+
});
210+
}
211+
170212
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright (c) 2011 by the original author(s).
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.data.document.mongodb.mapping;
18+
19+
import static org.junit.Assert.*;
20+
21+
import java.util.List;
22+
23+
import com.mongodb.DB;
24+
import com.mongodb.DBCollection;
25+
import com.mongodb.DBObject;
26+
import com.mongodb.Mongo;
27+
import com.mongodb.MongoException;
28+
import org.junit.Before;
29+
import org.junit.Test;
30+
import org.springframework.context.ApplicationContext;
31+
import org.springframework.context.support.ClassPathXmlApplicationContext;
32+
import org.springframework.dao.DataAccessException;
33+
import org.springframework.data.document.mongodb.CollectionCallback;
34+
import org.springframework.data.document.mongodb.MongoTemplate;
35+
36+
/**
37+
* @author Jon Brisbin <jbrisbin@vmware.com>
38+
*/
39+
public class GeoIndexedTests {
40+
41+
private final String[] collectionsToDrop = new String[]{
42+
"geolocation"
43+
};
44+
45+
ApplicationContext applicationContext;
46+
MongoTemplate template;
47+
MongoMappingContext mappingContext;
48+
49+
@Before
50+
public void setUp() throws Exception {
51+
Mongo mongo = new Mongo();
52+
DB db = mongo.getDB("database");
53+
for (String coll : collectionsToDrop) {
54+
db.getCollection(coll).drop();
55+
}
56+
applicationContext = new ClassPathXmlApplicationContext("/mapping.xml");
57+
template = applicationContext.getBean(MongoTemplate.class);
58+
mappingContext = applicationContext.getBean(MongoMappingContext.class);
59+
}
60+
61+
@Test
62+
public void testGeoLocation() {
63+
GeoLocation geo = new GeoLocation(new double[]{40.714346, -74.005966});
64+
template.insert(geo);
65+
66+
boolean hasIndex = template.execute("geolocation", new CollectionCallback<Boolean>() {
67+
public Boolean doInCollection(DBCollection collection) throws MongoException, DataAccessException {
68+
List<DBObject> indexes = collection.getIndexInfo();
69+
for (DBObject dbo : indexes) {
70+
if ("location_2d".equals(dbo.get("name"))) {
71+
return true;
72+
}
73+
}
74+
return false;
75+
}
76+
});
77+
78+
assertTrue(hasIndex);
79+
}
80+
81+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright (c) 2011 by the original author(s).
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.data.document.mongodb.mapping;
18+
19+
import org.bson.types.ObjectId;
20+
import org.springframework.data.annotation.Id;
21+
import org.springframework.data.document.mongodb.index.GeoSpatialIndexed;
22+
23+
/**
24+
* @author Jon Brisbin <jbrisbin@vmware.com>
25+
*/
26+
@Document
27+
public class GeoLocation {
28+
29+
@Id
30+
private ObjectId id;
31+
@GeoSpatialIndexed
32+
private double[] location;
33+
34+
public GeoLocation(double[] location) {
35+
this.location = location;
36+
}
37+
38+
public ObjectId getId() {
39+
return id;
40+
}
41+
42+
public double[] getLocation() {
43+
return location;
44+
}
45+
46+
public void setLocation(double[] location) {
47+
this.location = location;
48+
}
49+
50+
}

0 commit comments

Comments
 (0)