package gov.nih.ncgc.bard.search;
import gov.nih.ncgc.bard.tools.DBUtils;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Node;
import nu.xom.Nodes;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.glassfish.jersey.client.ClientResponse;
/**
* A one line summary.
*
* @author Rajarshi Guha
*/
public abstract class SolrSearch implements ISolrSearch {
protected static DBUtils db;
protected String query = null;
protected int numHit = -1;
protected List<Facet> facets;
protected SearchResult results = null;
protected String CORE_NAME = null;
protected String solrURL = "http://localhost:8090/solr";
public static void setDb(DBUtils db) {
SolrSearch.db = db;
}
protected SolrSearch(String query) {
this.query = query;
}
public List<Facet> getFacets() {
return facets;
}
public int getHitCount() {
return numHit;
}
public String getQuery() {
return query;
}
public SearchResult getSearchResults() {
return results;
}
public void setSolrURL(String url) {
solrURL = url;
}
public String getSolrURL() {
return solrURL;
}
protected List<SolrDocument> copyRange(List<SolrDocument> docs, Integer skip, Integer top, boolean detailed, String... fields) {
List<SolrDocument> ret = new ArrayList<SolrDocument>();
if (top == null) top = 10;
if (skip == null) skip = 0;
for (int i = skip; i < (skip + top); i++) {
if (i >= docs.size()) continue;
docs.get(i).removeFields("text");
if (!detailed) {
SolrDocument newDoc = new SolrDocument();
for (String field : fields) newDoc.addField(field, docs.get(i).getFieldValue(field));
ret.add(newDoc);
} else ret.add(docs.get(i));
}
return ret;
}
public Map<String, List<String>> suggest(SolrField[] fields, String q, Integer n) throws MalformedURLException, SolrServerException {
return SearchUtil.getTerms(getSolrURL() + CORE_NAME, fields, q + ".*", n);
}
/**
* Get field names associated with a Solr document.
* <p/>
* As we store Solr entity documents in different cores, we can identify fields
* based on the name of the core.
*
* @return A list of {@link SolrField} objects.
* @throws Exception
*/
public List<SolrField> getFieldNames() throws Exception {
if (CORE_NAME == null) throw new Exception("Must have a valid CORE_NAME");
String lukeUrl = getSolrURL() + CORE_NAME + "admin/luke?numTerms=0";
List<SolrField> fieldNames = new ArrayList<SolrField>();
//Client client = new Client.create();
// New jersey...
Client client = ClientBuilder.newClient();
WebTarget target = client.target(getSolrURL() + CORE_NAME);
Response response = target.request().get();
//WebResource resource = client.resource(lukeUrl);
//ClientResponse response = resource.get(ClientResponse.class);
int status = response.getStatus();
if (status != 200) {
throw new Exception("There was a problem querying " + lukeUrl);
}
//String xml = response.getEntity(String.class);
String xml = (String)response.getEntity();
Document doc = new Builder(false).build(xml, null);
Nodes nodes = doc.query("/response/lst[@name='fields']");
if (nodes.size() > 0) {
Node node = nodes.get(0);
for (int i = 0; i < node.getChildCount(); i++) {
Node n = node.getChild(i);
String name = ((Element) n).getAttribute("name").getValue();
if (name.endsWith("text")) continue;
Node sn = n.getChild(0);
String type = sn.getValue();
fieldNames.add(new SolrField(name, type));
}
}
//client.destroy();
client.close();
return fieldNames;
}
/**
* Initiale highlighting.
* <p/>
* This initialization is pretty much independent of the entity we're searching on, hence
* it's placement in the superclass.
*
* @param solrQuery The query object
* @param highlightField which field to highlight on
* @return the updated query object
*/
protected SolrQuery setHighlighting(SolrQuery solrQuery, String highlightField) {
solrQuery = solrQuery.setHighlight(true).
setHighlightSnippets(1).
setHighlightFragsize(300).
setHighlightSimplePre("<b>").
setHighlightSimplePost("</b>");
return solrQuery.addHighlightField(highlightField);
}
/**
* Convert user specified field based filters to the Solr form.
*
* @param solrQuery the query object
* @param filter the filter string
* @return the updated query object
*/
protected SolrQuery setFilterQueries(SolrQuery solrQuery, String filter) {
if (filter == null) return solrQuery;
try {
List<SolrField> fields = getFieldNames();
List<String> fnames = new ArrayList<String>();
for (SolrField field : fields) fnames.add(field.getName());
Map<String, List<String>> fq = SearchUtil.extractFilterQueries(filter, getFieldNames());
for (Map.Entry<String, List<String>> entry : fq.entrySet()) {
String fname = entry.getKey();
List<String> fvalues = entry.getValue();
if (!fnames.contains(fname)) continue;
StringBuilder sb = new StringBuilder();
sb.append(fvalues.get(0));
for (int i = 1; i < fvalues.size(); i++) {
if (fvalues.get(i).contains("["))
sb.append(" OR ").append(fvalues.get(i)); // name + ":" + fvalue
else {
sb.append(" OR ").append("\"").append(fvalues.get(i).replace("\"", "")).append("\"");
sb.append(" OR ").append(fvalues.get(i));
}
}
if (fvalues.size() == 1) {
solrQuery.addFilterQuery(fname + ":" + sb.toString()+"");
}
else solrQuery.addFilterQuery(fname + ":(" + sb.toString()+")");
}
} catch (Exception e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
return solrQuery;
}
protected List<SolrDocument> getHighlightedDocuments(QueryResponse response, String primaryKey, String highlightField) {
List<SolrDocument> docs = new ArrayList<SolrDocument>();
SolrDocumentList sdl = response.getResults();
for (SolrDocument doc : sdl) {
String pkey = (String) doc.getFieldValue(primaryKey);
if (response.getHighlighting() != null && highlightField != null) {
List<String> hls = response.getHighlighting().get(pkey).get(highlightField);
if (hls != null) {
doc.addField("highlight", hls.get(0));
}
}
doc.removeFields("anno_val");
doc.removeFields("anno_key");
docs.add(doc);
}
return docs;
}
protected String putEtag(List<Long> ids, Class klass) throws Exception {
try {
String etag = db.newETag(query, klass.getName());
db.putETag(etag, ids.toArray(new Long[0]));
results.setETag(etag);
return etag;
} finally {
try {
db.closeConnection();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}