Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes :) #45

Merged
merged 7 commits into from
Jan 28, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions src/play/modules/elasticsearch/Query.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
import play.db.Model;
import play.modules.elasticsearch.search.SearchResults;
import play.modules.elasticsearch.transformer.JPATransformer;
import play.modules.elasticsearch.transformer.Transformer;
import play.modules.elasticsearch.transformer.MapperTransformer;
import play.modules.elasticsearch.transformer.SimpleTransformer;

/**
* An elastic search query
Expand All @@ -35,6 +36,7 @@ public class Query<T extends Model> {
private int size = -1;

private boolean hydrate = false;
private boolean useMapper = false;

Query(Class<T> clazz, QueryBuilder builder) {
Validate.notNull(clazz, "clazz cannot be null");
Expand Down Expand Up @@ -84,6 +86,19 @@ public Query<T> hydrate(boolean hydrate) {
return this;
}

/**
* Controls the usage of mapper
*
* @param useMapper
* use mapper during result processing
* @return self
*/
public Query<T> useMapper(boolean useMapper) {
this.useMapper = useMapper;

return this;
}

/**
* Adds a facet
*
Expand Down Expand Up @@ -168,9 +183,11 @@ public SearchResults<T> fetch() {
SearchResponse searchResponse = request.execute().actionGet();
SearchResults<T> searchResults = null;
if (hydrate) {
searchResults = JPATransformer.toSearchResults(searchResponse, clazz);
searchResults = new JPATransformer<T>().toSearchResults(searchResponse, clazz);
} else if (useMapper) {
searchResults = new MapperTransformer<T>().toSearchResults(searchResponse, clazz);
} else {
searchResults = Transformer.toSearchResults(searchResponse, clazz);
searchResults = new SimpleTransformer<T>().toSearchResults(searchResponse, clazz);
}
return searchResults;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ public static <T extends Model> void indexModel(Client client, ModelMapper<T> ma

contentBuilder = XContentFactory.jsonBuilder().prettyPrint();
mapper.addModel(model, contentBuilder);
Logger.debug("Index json: %s", contentBuilder.string());
IndexResponse response = client.prepareIndex(indexName, typeName, documentId)
.setSource(contentBuilder).execute().actionGet();

Expand Down
17 changes: 13 additions & 4 deletions src/play/modules/elasticsearch/mapping/FieldMapper.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package play.modules.elasticsearch.mapping;

import java.io.IOException;
import java.util.Map;

import org.elasticsearch.common.xcontent.XContentBuilder;

Expand All @@ -16,19 +17,27 @@ public interface FieldMapper<M> {
* Adds to mapping
*
* @param builder
* @param prefix
* @throws IOException
*/
public void addToMapping(XContentBuilder builder, String prefix) throws IOException;
public void addToMapping(XContentBuilder builder) throws IOException;

/**
* Adds to document
*
* @param model
* @param builder
* @param prefix
* @throws IOException
*/
public void addToDocument(M model, XContentBuilder builder, String prefix) throws IOException;
public void addToDocument(M model, XContentBuilder builder) throws IOException;

/**
* Inflates a model
*
* @param model
* @param map
* @return True if a value was inflated, false otherwise, when no value was
* present
*/
public boolean inflate(M model, Map<String, Object> map);

}
24 changes: 21 additions & 3 deletions src/play/modules/elasticsearch/mapping/MapperFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,32 @@ public static <M> ModelMapper<M> getMapper(Class<M> clazz) throws MappingExcepti
*/
public static <M> FieldMapper<M> getMapper(Field field) throws MappingException {

return getMapper(field, null);

}

/**
* Gets a {@link FieldMapper} for the specified field, using a prefix in the
* index
*
* @param <M>
* the model type
* @param field
* the field
* @throws MappingException
* in case of mapping problems
* @return the field mapper
*/
public static <M> FieldMapper<M> getMapper(Field field, String prefix) throws MappingException {

if (Collection.class.isAssignableFrom(field.getType())) {
return new CollectionFieldMapper<M>(field);
return new CollectionFieldMapper<M>(field, prefix);

} else if (field.isAnnotationPresent(ElasticSearchEmbedded.class)) {
return new EmbeddedFieldMapper<M>(field);
return new EmbeddedFieldMapper<M>(field, prefix);

} else {
return new SimpleFieldMapper<M>(field);
return new SimpleFieldMapper<M>(field, prefix);

}

Expand Down
166 changes: 166 additions & 0 deletions src/play/modules/elasticsearch/mapping/MappingUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,19 @@

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.math.BigDecimal;
import java.util.Date;

import org.apache.commons.lang.Validate;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;

import play.Logger;
import play.modules.elasticsearch.annotations.ElasticSearchField;
import play.modules.elasticsearch.annotations.ElasticSearchField.Index;
import play.modules.elasticsearch.annotations.ElasticSearchField.Store;
import play.modules.elasticsearch.util.ExceptionUtil;

public abstract class MappingUtil {

private MappingUtil() {
Expand Down Expand Up @@ -51,4 +60,161 @@ public static XContentBuilder getMapping(ModelMapper<?> mapper) throws IOExcepti

return builder;
}

/**
* Adds a field to the content builder
*
* @param builder
* the content builder
* @param name
* the field name
* @param type
* the field type
* @param meta
* the ElasticSearchField annotation (optional) *
* @throws IOException
*/
public static void addField(XContentBuilder builder, String name, String type,
ElasticSearchField meta) throws IOException {
Validate.notEmpty(name, "name cannot be empty");
Validate.notEmpty(type, "type cannot be empty");

builder.startObject(name);
builder.field("type", type);

// Check for other settings
if (meta != null) {
if (meta.index() != Index.NOT_SET) {
builder.field("index", meta.index().toString());
}
if (meta.store() != Store.NOT_SET) {
builder.field("store", meta.store().toString());
}
}

builder.endObject();
}

/**
* Detect the ElasticSearch field type for a {@code Class}
*
* @param clazz
* @return
*/
public static String detectFieldType(Class<?> clazz) {
// Core types
if (String.class.isAssignableFrom(clazz)) {
return "string";
} else if (Integer.class.isAssignableFrom(clazz) || int.class.isAssignableFrom(clazz)) {
return "integer";
} else if (Short.class.isAssignableFrom(clazz) || short.class.isAssignableFrom(clazz)) {
return "short";
} else if (Long.class.isAssignableFrom(clazz) || long.class.isAssignableFrom(clazz)) {
return "long";
} else if (Float.class.isAssignableFrom(clazz) || float.class.isAssignableFrom(clazz)) {
return "float";
} else if (Double.class.isAssignableFrom(clazz) || double.class.isAssignableFrom(clazz)) {
return "double";
} else if (Byte.class.isAssignableFrom(clazz) || byte.class.isAssignableFrom(clazz)) {
return "byte";
} else if (Date.class.isAssignableFrom(clazz)) {
return "date";
} else if (Boolean.class.isAssignableFrom(clazz) || boolean.class.isAssignableFrom(clazz)) {
return "boolean";
}

// Fall back to string mapping
return "string";
}

public static Object convertValue(final Object value, final Class<?> targetType) {
if (targetType.equals(value.getClass())) {
// Types match
return value;
}

// Types do not match, perform conversion where needed
if (targetType.equals(String.class)) {
return value.toString();
} else if (targetType.equals(BigDecimal.class)) {
return new BigDecimal(value.toString());
} else if (targetType.equals(Date.class)) {
return convertToDate(value);

// Use Number intermediary where possible
} else if (targetType.equals(Integer.class)) {
if (value instanceof Number) {
return Integer.valueOf(((Number) value).intValue());
} else {
return Integer.valueOf(value.toString());
}
} else if (targetType.equals(Long.class)) {
if (value instanceof Number) {
return Long.valueOf(((Number) value).longValue());
} else {
return Long.valueOf(value.toString());
}
} else if (targetType.equals(Double.class)) {
if (value instanceof Number) {
return Double.valueOf(((Number) value).doubleValue());
} else {
return Double.valueOf(value.toString());
}
} else if (targetType.equals(Float.class)) {
if (value instanceof Number) {
return Float.valueOf(((Number) value).floatValue());
} else {
return Float.valueOf(value.toString());
}

// Fallback to simply returning the value
} else {
return value;
}
}

/**
* Convert to date.
*
* @param value
* the value
* @return the date
*/
private static Date convertToDate(Object value) {
Date date = null;
if (value != null && !"".equals(value)) {
if (value instanceof Long) {
date = new Date(((Long) value).longValue());

} else if (value instanceof String) {
String val = (String) value;
int dateLength = String.valueOf(Long.MAX_VALUE).length();
if (dateLength == val.length()) {
date = new Date(Long.valueOf(val).longValue());
} else {
date = getDate(val);
}
} else {
date = (Date) value;
}
}
return date;
}

/**
* Gets the date.
*
* @param val
* the val
* @return the date
*/
private static Date getDate(String val) {
try {
// Use ES internal converter
return XContentBuilder.defaultDatePrinter.parseDateTime(val).toDate();
} catch (Throwable t) {
Logger.error(ExceptionUtil.getStackTrace(t), val);
}
return null;
}
}
9 changes: 9 additions & 0 deletions src/play/modules/elasticsearch/mapping/ModelMapper.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package play.modules.elasticsearch.mapping;

import java.io.IOException;
import java.util.Map;

import org.elasticsearch.common.xcontent.XContentBuilder;

Expand Down Expand Up @@ -61,4 +62,12 @@ public interface ModelMapper<M> {
* @throws IOException
*/
public void addModel(M model, XContentBuilder builder) throws IOException;

/**
* Inflates a new model from a map of values
*
* @param map
* @return
*/
public M createModel(Map<String, Object> map);
}
Loading