package ca.ualberta.cs.cmput301f14t14.questionapp.data;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import android.content.Context;
import android.location.Location;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
* Class to handle searching from ElasticSearch
*/
public class ESSearch {
protected static String ES_BASE_URL = "http://cmput301.softwareprocess.es:8080/cmput301f14t14/";
private Context context;
private Gson gson;
public ESSearch(Context context) {
this.context = context;
gson = new Gson();
}
public List<GenericSearchItem> search(String query) throws IOException {
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(ES_BASE_URL + "_search");
httpPost.setEntity(new StringEntity(
"{\"query\": {\"filtered\": {\"query\": {\"match\": {\"_all\": \"" + query + "\"}}," +
"\"filter\": {\"or\": [" +
"{\"type\": {\"value\": \"question\"}}," +
"{\"type\": {\"value\": \"answer\"}}" +
"]}}}}"));
HttpResponse response;
try {
response = httpClient.execute(httpPost);
return getResultList(response, new TypeToken<SearchResponse<GenericSearchItem>>() {}.getType());
} catch (IOException e) {
throw new IOException("Search failed.", e);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public List<GenericSearchItem> searchNearby(String query, Location location) throws IOException {
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(ES_BASE_URL + "_search");
httpPost.setEntity(new StringEntity(
"{\"query\":" +
"{\"filtered\":" +
"{\"query\":" +
"{\"match\": {\"_all\": \"" + query + "\"}}," +
"\"filter\": {" +
"\"and\": [" +
"{\"or\": [" +
"{\"type\": {\"value\": \"question\"}}," +
"{\"type\": {\"value\": \"answer\"}}" +
"]}, " +
"{\"geo_distance\": {" +
"\"distance\": \"30km\"," +
"\"location.location\": {" +
"\"lat\": "+ location.getLatitude() +"," +
"\"lon\": " + location.getLongitude() + "}" +
"}" +
"}" +
"]" +
"}" +
"}" +
"}"));
HttpResponse response;
try {
response = httpClient.execute(httpPost);
return getResultList(response, new TypeToken<SearchResponse<GenericSearchItem>>() {}.getType());
} catch (IOException e) {
throw new IOException("Search failed.", e);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Parse response from ElasticSearch, which is contained in a SearchHit
* object
*
* @param response
* @param type Type of deserialized object
* @return SearchHit object from ElasticSearch
*/
private <T> T parseESResponse(HttpResponse response, Type type) {
try {
String json = getEntityContent(response);
T sr = gson.fromJson(json, type);
return sr;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* Extract a result list from an http response, set type
* @param response
* @param type Expected type of deserialized http response body
* @return
*/
private List<GenericSearchItem> getResultList(HttpResponse response, Type type) {
SearchResponse<GenericSearchItem> sr = parseESResponse(response, type);
List<SearchHit<GenericSearchItem>> hits = sr.getHits().getHits();
List<GenericSearchItem> result = new ArrayList<GenericSearchItem>();
for (SearchHit<GenericSearchItem> hit: hits) {
GenericSearchItem item = hit.getSource();
item.setType(hit.get_type());
result.add(hit.getSource());
}
return result;
}
/**
* Gets content from an HTTP response
*/
private String getEntityContent(HttpResponse response) throws IOException {
BufferedReader rd = new BufferedReader(new InputStreamReader(response
.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
return result.toString();
}
}