package org.genedb.crawl.elasticsearch.mappers;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
import org.codehaus.jackson.JsonParseException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.action.search.SearchRequestBuilder;
import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.FieldQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.genedb.crawl.elasticsearch.Connection;
import org.genedb.crawl.json.JsonIzer;
import org.genedb.crawl.model.Feature;
import org.genedb.crawl.model.LocatedFeature;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class ElasticSearchBaseMapper {
private Logger logger = Logger.getLogger(ElasticSearchBaseMapper.class);
protected JsonIzer jsonIzer = new JsonIzer();
private static final Field[] featureFields = Feature.class.getDeclaredFields();
//String index = "features";
//String type = "Feature";
// public static String getIndex() {
// return "index";
// }
// public static String getType() {
// return "type";
// }
@Autowired
Connection connection;
public void setConnection(Connection connection) {
this.connection = connection;
}
protected LocatedFeature getFeatureFromJson(String json) {
if (json == null) {
return null;
}
try {
LocatedFeature feature = (LocatedFeature) jsonIzer.fromJson(json, LocatedFeature.class);
return feature;
} catch (JsonParseException e) {
logger.error("Could not parse the JSON!");
e.printStackTrace();
} catch (IOException e) {
logger.error("Could not read the JSON!");
e.printStackTrace();
}
return null;
}
protected Feature copy(Feature feature, String[] fields) {
Feature copy = new Feature();
if (feature == null) {
return null;
}
for (String field : fields) {
for (Field featureField : featureFields) {
if (featureField.getName().equals(field)) {
try {
featureField.set(copy, featureField.get(feature));
} catch (Exception e) {
logger.error(String.format("could not copy field", field));
e.printStackTrace();
}
}
}
}
return copy;
}
protected List<Feature> fetchAndCopy(String index, String type, List<String> features, String[] fields) {
List<Feature> featureResults = new ArrayList<Feature>();
for (String uniqueName : features) {
String json = getFromElastic(index, type, uniqueName, fields);
Feature feature = getFeatureFromJson(json);
Feature featureToAdd = copy(feature, fields);
if (featureToAdd != null) {
featureResults.add(featureToAdd);
}
}
return featureResults;
}
protected String getFromElastic(String index, String type, String uniqueName) {
return connection.getClient().prepareGet(index,type, uniqueName).execute().actionGet().sourceAsString();
}
protected String getFromElastic(String index, String type, String uniqueName, String[] fields) {
return connection.getClient().prepareGet(index,type, uniqueName).execute().actionGet().sourceAsString();
// logger.debug("Searching for uniqueName " + uniqueName);
//
// SearchRequestBuilder srb = connection.getClient().prepareSearch(index)
// .setQuery( QueryBuilders.fieldQuery("uniqueName", uniqueName));
// // .setQuery( QueryBuilders.termQuery("uniqueName", uniqueName));
//// .setFrom(0)
//// .setSize(1);
//
//// for (String field : fields) {
//// String fieldName = "_source." + field;
//// logger.debug("Field " + fieldName);
//// srb.addField(fieldName);
//// }
//
// // srb.addField("_source.coordinates");
//
// SearchResponse response = srb.execute().actionGet();
//
// logger.debug(response.getHits().totalHits());
//
// if (response.getHits().totalHits() == 1) {
// logger.debug("returning ");
//
// SearchHit hit = response.hits().getAt(0);
//
// logger.debug(hit.sourceAsString());
//
// logger.debug(hit.fields());
//
// return response.hits().getAt(0).sourceAsString();
// }
//
// return null;
}
protected <T extends Feature> T copy(Feature feature, String[] fields, Class<T> cls) throws InstantiationException, IllegalAccessException {
Field[] tFields = cls.getFields();
T copy = (T) cls.newInstance();
if (feature == null) {
return null;
}
for (String field : fields) {
for (Field featureField : tFields) {
//logger.debug(String.format("%s == %s", featureField.getName(), field));
if (featureField.getName().equals(field)) {
try {
featureField.set(copy, featureField.get(feature));
} catch (Exception e) {
logger.error(String.format("could not copy field", field));
e.printStackTrace();
}
}
}
}
return copy;
}
protected <T extends Object> T getFirstMatch(String indexName, String typeName, Map<String, String> fieldNamesAndValues, Class<T> cls) {
logger.info(String.format("Fetching index %s, type %s, field %s, casting to %s.", indexName, typeName, fieldNamesAndValues, cls.getName()));
BoolQueryBuilder booleanQuery = QueryBuilders.boolQuery();
for (String key : fieldNamesAndValues.keySet()) {
String value = fieldNamesAndValues.get(key);
FieldQueryBuilder fieldQuery = QueryBuilders.fieldQuery(key, value);
booleanQuery.must(fieldQuery);
}
SearchResponse response = connection.getClient()
.prepareSearch(indexName)
.setTypes(typeName)
.setQuery(booleanQuery)
.execute()
.actionGet();
return getFirstMatch( response, cls);
}
protected <T extends Object> T getFirstMatch(String indexName, String typeName, String fieldName, String value, Class<T> cls) {
logger.info(String.format("Fetching index %s, type %s, field %s, value %s, casting to %s.", indexName, typeName, fieldName, value, cls.getName()));
FieldQueryBuilder fieldQuery = QueryBuilders.fieldQuery(fieldName, value);
SearchResponse response = connection.getClient()
.prepareSearch(indexName)
.setTypes(typeName)
.setQuery(fieldQuery)
.execute()
.actionGet();
return getFirstMatch( response, cls);
}
protected <T extends Object> T getFirstMatch(SearchResponse response, Class<T> cls) {
for (SearchHit hit : response.getHits()) {
String source = hit.sourceAsString();
try {
T object = (T) jsonIzer.fromJson(source, cls);
return object;
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return null;
}
}
return null;
}
protected <T extends Object> List<T> getAllMatches(String indexName, String fieldName, QueryBuilder query, Class<T> cls) {
SearchRequestBuilder srb = connection.getClient().prepareSearch(indexName).setQuery(query);
logger.info(toString(srb.internalBuilder()));
SearchResponse response = srb.execute().actionGet();
return getAllMatches(response, cls);
}
protected <T extends Object> List<T> getAllMatches(String indexName, String fieldName, String value, Class<T> cls) {
FieldQueryBuilder regionQuery =
QueryBuilders.fieldQuery(fieldName, value);
SearchResponse response = connection.getClient().prepareSearch(indexName)
.setQuery(regionQuery)
.setSize(Integer.MAX_VALUE)
.execute()
.actionGet();
return getAllMatches(response, cls);
}
protected <T extends Object> List<T> getAllMatches(SearchResponse response, Class<T> cls) {
List<T> list = new ArrayList<T>();
for (SearchHit hit : response.getHits()) {
String source = hit.sourceAsString();
try {
T object = (T) jsonIzer.fromJson(source, cls);
list.add(object);
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
}
}
return list;
}
private int maxTries = 10;
private int sleepTime = 60000 ; // 1 minute
public void createOrUpdate(String index, String type, String key, Object obj) {
for (int t = 0; t< maxTries;t++) {
try {
cru(index, type, key, obj);
return;
} catch (IOException e) {
e.printStackTrace();
logger.error(e.getMessage());
logger.error("Retrying");
}
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
throw new RuntimeException(String.format("Could not create or update in index %s, type %s, key %s, object %s.", index, type, key, obj));
}
private synchronized void cru(String index, String type, String key, Object obj) throws IOException {
String json = jsonIzer.toJson(obj);
connection
.getClient()
.prepareIndex(index, type, key)
.setSource(json)
.execute()
.actionGet();
}
// public void waitForYellowOrGreenStatus() {
// ClusterHealthRequest clusterHealth = new ClusterHealthRequest();
// ClusterHealthResponse response;
//
// boolean ok = false;
// logger.info("Waiting...");
//
// while (! ok) {
// response = connection.getClient().admin().cluster().health(clusterHealth).actionGet();
// ClusterHealthStatus status = response.getStatus();
//
// if (status.equals(ClusterHealthStatus.GREEN) || status.equals(ClusterHealthStatus.YELLOW)) {
// logger.info(status);
//
// ok = true;
// }
//
// logger.info(status);
//
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }
public static String toString(ToXContent tmp) {
try {
return
tmp.toXContent(JsonXContent.unCachedContentBuilder(),
ToXContent.EMPTY_PARAMS).
prettyPrint().
string();
} catch (Exception ex) {
return "<ERROR:" + ex.getMessage() + ">";
}
}
public void waitForStatus(EnumSet<ClusterHealthStatus> acceptableStatuses) {
ClusterHealthRequest clusterHealth = new ClusterHealthRequest();
ClusterHealthResponse response;
boolean ok = false;
logger.info("Waiting...");
while (! ok) {
response = connection.getClient().admin().cluster().health(clusterHealth).actionGet();
ClusterHealthStatus status = response.getStatus();
for (ClusterHealthStatus acceptableStatus : acceptableStatuses) {
if (acceptableStatus.equals(status)) {
ok = true;
}
}
logger.info(status);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
protected static final String LUCENE_ESCAPE_CHARS = "[\\\\+\\-\\!\\(\\)\\:\\^\\]\\{\\}\\~\\*\\?]";
protected static final Pattern LUCENE_PATTERN = Pattern.compile(LUCENE_ESCAPE_CHARS);
protected static final String REPLACEMENT_STRING = "\\\\$0";
protected String escape(String value) {
String escaped = LUCENE_PATTERN.matcher(value).replaceAll(REPLACEMENT_STRING);
logger.info(String.format("%s ... %s", value, escaped));
return escaped;
}
}