DATADOC-7 - Support for map-reduce operations in MongoTemplate

This commit is contained in:
Mark Pollack
2011-09-01 18:03:22 -04:00
parent 9bb42245bb
commit 756f886cef
5 changed files with 154 additions and 25 deletions

View File

@@ -270,48 +270,52 @@ public interface MongoOperations {
/**
* Execute a map-reduce operation. The map-reduce operation will be formed with an output type of INLINE
* @param inputCollectionName the collection where the map-reduce will read from
* @param mapFunction The JavaScript map function
* @param reduceFunction The JavaScript reduce function
* @param mapReduceOptions Options that specify detailed map-reduce behavior
* @param entityClass The parameterized type of the returned list
* @return The results of the map reduce operation
*/
<T> MapReduceResults<T> mapReduce(String mapFunction, String reduceFunction, Class<T> entityClass );
<T> MapReduceResults<T> mapReduce(String inputCollectionName, String mapFunction, String reduceFunction, Class<T> entityClass );
/**
* Execute a map-reduce operation that takes additional map-reduce options.
* @param inputCollectionName the collection where the map-reduce will read from
* @param mapFunction The JavaScript map function
* @param reduceFunction The JavaScript reduce function
* @param mapReduceOptions Options that specify detailed map-reduce behavior
* @param entityClass The parameterized type of the returned list
* @return The results of the map reduce operation
*/
<T> MapReduceResults<T> mapReduce(String mapFunction, String reduceFunction, MapReduceOptions mapReduceOptions, Class<T> entityClass );
<T> MapReduceResults<T> mapReduce(String inputCollectionName, String mapFunction, String reduceFunction, MapReduceOptions mapReduceOptions, Class<T> entityClass );
/**
* Execute a map-reduce operation that takes a query. The map-reduce operation will be formed with an output type of INLINE
* @param query The query to use to select the data for the map phase
* @param inputCollectionName the collection where the map-reduce will read from
* @param mapFunction The JavaScript map function
* @param reduceFunction The JavaScript reduce function
* @param mapReduceOptions Options that specify detailed map-reduce behavior
* @param entityClass The parameterized type of the returned list
* @return The results of the map reduce operation
*/
<T> MapReduceResults<T> mapReduce(Query query, String mapFunction, String reduceFunction, Class<T> entityClass );
<T> MapReduceResults<T> mapReduce(Query query, String inputCollectionName, String mapFunction, String reduceFunction, Class<T> entityClass );
/**
* Execute a map-reduce operation that takes a query and additional map-reduce options
* @param query The query to use to select the data for the map phase
* @param inputCollectionName the collection where the map-reduce will read from
* @param mapFunction The JavaScript map function
* @param reduceFunction The JavaScript reduce function
* @param mapReduceOptions Options that specify detailed map-reduce behavior
* @param entityClass The parameterized type of the returned list
* @return The results of the map reduce operation
*/
<T> MapReduceResults<T> mapReduce(Query query, String mapFunction, String reduceFunction, MapReduceOptions mapReduceOptions, Class<T> entityClass );
<T> MapReduceResults<T> mapReduce(Query query, String inputCollectionName, String mapFunction, String reduceFunction, MapReduceOptions mapReduceOptions, Class<T> entityClass );
/**
* Returns {@link GeoResult} for all entities matching the given {@link NearQuery}. Will consider entity mapping

View File

@@ -832,24 +832,24 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
entityClass), collectionName);
}
public <T> MapReduceResults<T> mapReduce(String mapFunction, String reduceFunction, Class<T> entityClass) {
return mapReduce(null, mapFunction, reduceFunction, new MapReduceOptions().outputTypeInline(), entityClass);
public <T> MapReduceResults<T> mapReduce(String inputCollectionName, String mapFunction, String reduceFunction, Class<T> entityClass) {
return mapReduce(null, inputCollectionName, mapFunction, reduceFunction, new MapReduceOptions().outputTypeInline(), entityClass);
}
public <T> MapReduceResults<T> mapReduce(String mapFunction, String reduceFunction,
public <T> MapReduceResults<T> mapReduce(String inputCollectionName, String mapFunction, String reduceFunction,
MapReduceOptions mapReduceOptions, Class<T> entityClass) {
return mapReduce(null, mapFunction, reduceFunction, mapReduceOptions, entityClass);
return mapReduce(null, inputCollectionName, mapFunction, reduceFunction, mapReduceOptions, entityClass);
}
public <T> MapReduceResults<T> mapReduce(Query query, String mapFunction, String reduceFunction, Class<T> entityClass) {
return mapReduce(query, mapFunction, reduceFunction, new MapReduceOptions().outputTypeInline(), entityClass);
public <T> MapReduceResults<T> mapReduce(Query query, String inputCollectionName, String mapFunction, String reduceFunction, Class<T> entityClass) {
return mapReduce(query, inputCollectionName, mapFunction, reduceFunction, new MapReduceOptions().outputTypeInline(), entityClass);
}
public <T> MapReduceResults<T> mapReduce(Query query, String mapFunction, String reduceFunction,
public <T> MapReduceResults<T> mapReduce(Query query, String inputCollectionName, String mapFunction, String reduceFunction,
MapReduceOptions mapReduceOptions, Class<T> entityClass) {
String mapFunc = replaceWithResourceIfNecessary(mapFunction);
String reduceFunc = replaceWithResourceIfNecessary(reduceFunction);
DBCollection inputCollection = getCollection(this.determineCollectionName(entityClass));
DBCollection inputCollection = getCollection(inputCollectionName);
MapReduceCommand command = new MapReduceCommand(inputCollection, mapFunc, reduceFunc,
mapReduceOptions.getOutputCollection(), mapReduceOptions.getOutputType(), null);
@@ -866,11 +866,18 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} else {
commandResult = executeCommand(commandObject);
}
commandResult.throwOnError();
commandResult.throwOnError();
} catch (RuntimeException ex) {
this.potentiallyConvertRuntimeException(ex);
}
String error = commandResult.getErrorMessage();
if (error != null) {
throw new InvalidDataAccessApiUsageException("Command execution failed: Error [" + error + "], Command = " + commandObject);
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("MapReduce command result = [" + commandResult + "]");
}
MapReduceOutput mapReduceOutput = new MapReduceOutput(inputCollection, commandObject, commandResult);
List<T> mappedResults = new ArrayList<T>();
DbObjectCallback<T> callback = new ReadDbObjectCallback<T>(mongoConverter, entityClass);

View File

@@ -28,6 +28,7 @@ import java.util.Map;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@@ -87,9 +88,18 @@ public class MapReduceTests {
protected void cleanDb() {
template.dropCollection(template.getCollectionName(ValueObject.class));
template.dropCollection("jmr1_out");
template.dropCollection("jmr1");
}
@Test
@Ignore
public void testForDocs() {
createMapReduceData();
MapReduceResults<ValueObject> results = mongoTemplate.mapReduce("jmr1", mapFunction, reduceFunction, ValueObject.class);
for (ValueObject valueObject : results) {
System.out.println(valueObject);
}
}
@Test
public void testMapReduce() {
performMapReduce(false, false);
@@ -114,7 +124,7 @@ public class MapReduceTests {
String mapWithExcludeFunction = "function(){ for ( var i=0; i<this.x.length; i++ ){ if(this.x[i] != exclude) emit( this.x[i] , 1 ); } }";
MapReduceResults<ValueObject> results = mongoTemplate.mapReduce(mapWithExcludeFunction, reduceFunction,
MapReduceResults<ValueObject> results = mongoTemplate.mapReduce("jmr1", mapWithExcludeFunction, reduceFunction,
new MapReduceOptions().scopeVariables(scopeVariables).outputTypeInline(), ValueObject.class);
Map<String, Float> m = copyToMap(results);
assertEquals(3, m.size());
@@ -128,7 +138,7 @@ public class MapReduceTests {
createMapReduceData();
Query query = new Query(where("x").ne(new String[] { "a", "b" }));
MapReduceResults<ValueObject> results = mongoTemplate.mapReduce(query, mapFunction, reduceFunction, ValueObject.class);
MapReduceResults<ValueObject> results = mongoTemplate.mapReduce(query, "jmr1", mapFunction, reduceFunction, ValueObject.class);
Map<String, Float> m = copyToMap(results);
assertEquals(3, m.size());
@@ -144,15 +154,15 @@ public class MapReduceTests {
MapReduceResults<ValueObject> results;
if (inline) {
if (withQuery) {
results = mongoTemplate.mapReduce(new Query(), "classpath:map.js", "classpath:reduce.js", ValueObject.class);
results = mongoTemplate.mapReduce(new Query(), "jmr1", "classpath:map.js", "classpath:reduce.js", ValueObject.class);
} else {
results = mongoTemplate.mapReduce(mapFunction, reduceFunction, ValueObject.class);
results = mongoTemplate.mapReduce("jmr1", mapFunction, reduceFunction, ValueObject.class);
}
} else {
if (withQuery) {
results = mongoTemplate.mapReduce(new Query(), mapFunction, reduceFunction, options().outputCollection("jmr1_out"), ValueObject.class);
results = mongoTemplate.mapReduce(new Query(), "jmr1", mapFunction, reduceFunction, options().outputCollection("jmr1_out"), ValueObject.class);
} else {
results = mongoTemplate.mapReduce(mapFunction, reduceFunction, new MapReduceOptions().outputCollection("jmr1_out"), ValueObject.class);
results = mongoTemplate.mapReduce("jmr1", mapFunction, reduceFunction, new MapReduceOptions().outputCollection("jmr1_out"), ValueObject.class);
}
}
Map<String, Float> m = copyToMap(results);
@@ -160,7 +170,7 @@ public class MapReduceTests {
}
private void createMapReduceData() {
DBCollection c = mongoTemplate.getDb().getCollection(template.getCollectionName(ValueObject.class));
DBCollection c = mongoTemplate.getDb().getCollection("jmr1");
c.save(new BasicDBObject("x", new String[] { "a", "b" }));
c.save(new BasicDBObject("x", new String[] { "b", "c" }));
c.save(new BasicDBObject("x", new String[] { "c", "d" }));

View File

@@ -22,8 +22,5 @@ public class ValueObject {
public String toString() {
return "ValueObject [id=" + id + ", value=" + value + "]";
}
}