NIHVIVO-2458, NIHVIVO-2459 Add commented-out servlet definitions of new solr-based servlets for autocomplete and json data services.

This commit is contained in:
ryounes 2011-05-12 21:30:43 +00:00
parent 2d8873f41e
commit 97cfec876b
3 changed files with 904 additions and 0 deletions

View file

@ -0,0 +1,564 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.Literal;
import edu.cornell.mannlib.vitro.webapp.beans.DataProperty;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController.PageRecord;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.dao.jena.VClassGroupCache;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.EditConfiguration;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.SelectListGenerator;
import edu.cornell.mannlib.vitro.webapp.search.beans.ProhibitedFromSearch;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModel;
/**
* This servlet is for servicing requests for JSON objects/data.
* It could be generalized to get other types of data ex. XML, HTML etc
* @author bdc34
*
*/
public class SolrJsonServlet extends VitroHttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
VitroRequest vreq = new VitroRequest(req);
try{
if(vreq.getParameter("getEntitiesByVClass") != null ){
if( vreq.getParameter("resultKey") == null) {
getEntitiesByVClass(req, resp);
return;
} else {
getEntitiesByVClassContinuation( req, resp);
return;
}
}else if( vreq.getParameter("getN3EditOptionList") != null ){
doN3EditOptionList(req,resp);
return;
}else if( vreq.getParameter("getLuceneIndividualsByVClass") != null ){
getLuceneIndividualsByVClass(req,resp);
return;
}else if( vreq.getParameter("getVClassesForVClassGroup") != null ){
getVClassesForVClassGroup(req,resp);
return;
}
}catch(Exception ex){
log.warn(ex,ex);
}
}
private void getVClassesForVClassGroup(HttpServletRequest req, HttpServletResponse resp) throws IOException, JSONException {
JSONObject map = new JSONObject();
VitroRequest vreq = new VitroRequest(req);
String vcgUri = vreq.getParameter("classgroupUri");
if( vcgUri == null ){
log.debug("no URI passed for classgroupUri");
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
VClassGroupCache vcgc = VClassGroupCache.getVClassGroupCache(getServletContext());
VClassGroup vcg = vcgc.getGroup(vcgUri);
if( vcg == null ){
log.debug("Could not find vclassgroup: " + vcgUri);
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
ArrayList<JSONObject> classes = new ArrayList<JSONObject>(vcg.size());
for( VClass vc : vcg){
JSONObject vcObj = new JSONObject();
vcObj.put("name", vc.getName());
vcObj.put("URI", vc.getURI());
vcObj.put("entityCount", vc.getEntityCount());
classes.add(vcObj);
}
map.put("classes", classes);
map.put("classGroupName", vcg.getPublicName());
map.put("classGroupUri", vcg.getURI());
resp.setCharacterEncoding("UTF-8");
resp.setContentType("application/json;charset=UTF-8");
Writer writer = resp.getWriter();
writer.write(map.toString());
}
private void getLuceneIndividualsByVClass( HttpServletRequest req, HttpServletResponse resp ){
String errorMessage = null;
JSONObject rObj = null;
try{
VitroRequest vreq = new VitroRequest(req);
VClass vclass=null;
String vitroClassIdStr = vreq.getParameter("vclassId");
if ( vitroClassIdStr != null && !vitroClassIdStr.isEmpty()){
vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vitroClassIdStr);
if (vclass == null) {
log.debug("Couldn't retrieve vclass ");
throw new Exception (errorMessage = "Class " + vitroClassIdStr + " not found");
}
}else{
log.debug("parameter vclassId URI parameter expected ");
throw new Exception("parameter vclassId URI parameter expected ");
}
rObj = getLuceneIndividualsByVClass(vclass.getURI(),req, getServletContext());
}catch(Exception ex){
errorMessage = ex.toString();
log.error(ex,ex);
}
if( rObj == null )
rObj = new JSONObject();
try{
resp.setCharacterEncoding("UTF-8");
resp.setContentType("application/json;charset=UTF-8");
if( errorMessage != null ){
rObj.put("errorMessage", errorMessage);
resp.setStatus(500 /*HttpURLConnection.HTTP_SERVER_ERROR*/);
}else{
rObj.put("errorMessage", "");
}
Writer writer = resp.getWriter();
writer.write(rObj.toString());
}catch(JSONException jse){
log.error(jse,jse);
} catch (IOException e) {
log.error(e,e);
}
}
public static JSONObject getLuceneIndividualsByVClass(String vclassURI, HttpServletRequest req, ServletContext context) throws Exception {
VitroRequest vreq = new VitroRequest(req);
VClass vclass=null;
JSONObject rObj = new JSONObject();
DataProperty fNameDp = (new DataProperty());
fNameDp.setURI("http://xmlns.com/foaf/0.1/firstName");
DataProperty lNameDp = (new DataProperty());
lNameDp.setURI("http://xmlns.com/foaf/0.1/lastName");
DataProperty monikerDp = (new DataProperty());
monikerDp.setURI( VitroVocabulary.MONIKER);
//this property is vivo specific
DataProperty preferredTitleDp = (new DataProperty());
preferredTitleDp.setURI("http://vivoweb.org/ontology/core#preferredTitle");
if( log.isDebugEnabled() ){
Enumeration<String> e = vreq.getParameterNames();
while(e.hasMoreElements()){
String name = (String)e.nextElement();
log.debug("parameter: " + name);
for( String value : vreq.getParameterValues(name) ){
log.debug("value for " + name + ": '" + value + "'");
}
}
}
//need an unfiltered dao to get firstnames and lastnames
WebappDaoFactory fullWdf = vreq.getFullWebappDaoFactory();
String vitroClassIdStr = vreq.getParameter("vclassId");
if ( vitroClassIdStr != null && !vitroClassIdStr.isEmpty()){
vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vitroClassIdStr);
if (vclass == null) {
log.debug("Couldn't retrieve vclass ");
throw new Exception ("Class " + vitroClassIdStr + " not found");
}
}else{
log.debug("parameter vclassId URI parameter expected ");
throw new Exception("parameter vclassId URI parameter expected ");
}
rObj.put("vclass",
new JSONObject().put("URI",vclass.getURI())
.put("name",vclass.getName()));
if (vclass != null) {
String alpha = IndividualListController.getAlphaParameter(vreq);
int page = IndividualListController.getPageParameter(vreq);
Map<String,Object> map = IndividualListController.getResultsForVClass(
vclass.getURI(),
page,
alpha,
vreq.getWebappDaoFactory().getIndividualDao(),
context);
rObj.put("totalCount", map.get("totalCount"));
rObj.put("alpha", map.get("alpha"));
List<Individual> inds = (List<Individual>)map.get("entities");
List<IndividualTemplateModel> indsTm = new ArrayList<IndividualTemplateModel>();
JSONArray jInds = new JSONArray();
for(Individual ind : inds ){
JSONObject jo = new JSONObject();
jo.put("URI", ind.getURI());
jo.put("label",ind.getRdfsLabel());
jo.put("name",ind.getName());
jo.put("thumbUrl", ind.getThumbUrl());
jo.put("imageUrl", ind.getImageUrl());
jo.put("profileUrl", UrlBuilder.getIndividualProfileUrl(ind, vreq.getWebappDaoFactory()));
String moniker = getDataPropertyValue(ind, monikerDp, fullWdf);
jo.put("moniker", moniker);
jo.put("vclassName", getVClassName(ind,moniker,fullWdf));
jo.put("preferredTitle", getDataPropertyValue(ind, preferredTitleDp, fullWdf));
jo.put("firstName", getDataPropertyValue(ind, fNameDp, fullWdf));
jo.put("lastName", getDataPropertyValue(ind, lNameDp, fullWdf));
jInds.put(jo);
}
rObj.put("individuals", jInds);
JSONArray wpages = new JSONArray();
List<PageRecord> pages = (List<PageRecord>)map.get("pages");
for( PageRecord pr: pages ){
JSONObject p = new JSONObject();
p.put("text", pr.text);
p.put("param", pr.param);
p.put("index", pr.index);
wpages.put( p );
}
rObj.put("pages",wpages);
JSONArray jletters = new JSONArray();
List<String> letters = Controllers.getLetters();
for( String s : letters){
JSONObject jo = new JSONObject();
jo.put("text", s);
jo.put("param", "alpha=" + URLEncoder.encode(s, "UTF-8"));
jletters.put( jo );
}
rObj.put("letters", jletters);
}
return rObj;
}
private static String getVClassName(Individual ind, String moniker,
WebappDaoFactory fullWdf) {
/* so the moniker frequently has a vclass name in it. Try to return
* the vclass name that is the same as the moniker so that the templates
* can detect this. */
if( (moniker == null || moniker.isEmpty()) ){
if( ind.getVClass() != null && ind.getVClass().getName() != null )
return ind.getVClass().getName();
else
return "";
}
List<VClass> vcList = ind.getVClasses();
for( VClass vc : vcList){
if( vc != null && moniker.equals( vc.getName() ))
return moniker;
}
// if we get here, then we didn't find a moniker that matched a vclass,
// so just return any vclass.name
if( ind.getVClass() != null && ind.getVClass().getName() != null )
return ind.getVClass().getName();
else
return "";
}
static String getDataPropertyValue(Individual ind, DataProperty dp, WebappDaoFactory wdf){
List<Literal> values = wdf.getDataPropertyStatementDao()
.getDataPropertyValuesForIndividualByProperty(ind, dp);
if( values == null || values.isEmpty() )
return "";
else{
if( values.get(0) != null )
return values.get(0).getLexicalForm();
else
return "";
}
}
/**
* Gets an option list for a given EditConfiguration and Field.
* Requires following HTTP query parameters:
* editKey
* field
*/
private void doN3EditOptionList(HttpServletRequest req, HttpServletResponse resp) throws IOException {
log.debug("in doN3EditOptionList()");
String field = req.getParameter("field");
if( field == null ){
log.debug("could not find query parameter 'field' for doN3EditOptionList");
throw new IllegalArgumentException(" getN3EditOptionList requires parameter 'field'");
}
HttpSession sess = req.getSession(false);
EditConfiguration editConfig = EditConfiguration.getConfigFromSession(sess, req);
if( editConfig == null ) {
log.debug("could not find query parameter 'editKey' for doN3EditOptionList");
throw new IllegalArgumentException(" getN3EditOptionList requires parameter 'editKey'");
}
if( log.isDebugEnabled() )
log.debug(" attempting to get option list for field '" + field + "'");
// set ProhibitedFromSearch object so picklist doesn't show
// individuals from classes that should be hidden from list views
OntModel displayOntModel =
(OntModel) getServletConfig().getServletContext()
.getAttribute("displayOntModel");
if (displayOntModel != null) {
ProhibitedFromSearch pfs = new ProhibitedFromSearch(
DisplayVocabulary.PRIMARY_LUCENE_INDEX_URI, displayOntModel);
editConfig.setProhibitedFromSearch(pfs);
}
Map<String,String> options = SelectListGenerator.getOptions(editConfig, field, (new VitroRequest(req)).getFullWebappDaoFactory());
resp.setContentType("application/json");
ServletOutputStream out = resp.getOutputStream();
out.println("[");
for(String key : options.keySet()){
JSONArray jsonObj = new JSONArray();
jsonObj.put( options.get(key));
jsonObj.put( key);
out.println(" " + jsonObj.toString() + ",");
}
out.println("]");
}
private void getEntitiesByVClassContinuation(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
log.debug("in getEntitiesByVClassContinuation()");
VitroRequest vreq = new VitroRequest(req);
String resKey = vreq.getParameter("resultKey");
if( resKey == null )
throw new ServletException("Could not get resultKey");
HttpSession session = vreq.getSession();
if( session == null )
throw new ServletException("there is no session to get the pervious results from");
List<Individual> entsInVClass = (List<Individual>) session.getAttribute(resKey);
if( entsInVClass == null )
throw new ServletException("Could not find List<Individual> for resultKey " + resKey);
List<Individual> entsToReturn = new ArrayList<Individual>(REPLY_SIZE);
boolean more = false;
int count = 0;
int size = REPLY_SIZE;
/* we have a large number of items to send back so we need to stash the list in the session scope */
if( entsInVClass.size() > REPLY_SIZE){
more = true;
ListIterator<Individual> entsFromVclass = entsInVClass.listIterator();
while ( entsFromVclass.hasNext() && count <= REPLY_SIZE ){
entsToReturn.add( entsFromVclass.next());
entsFromVclass.remove();
count++;
}
if( log.isDebugEnabled() ) log.debug("getEntitiesByVClassContinuation(): Creating reply with continue token," +
" sending in this reply: " + count +", remaing to send: " + entsInVClass.size() );
} else {
//send out reply with no continuation
entsToReturn = entsInVClass;
count = entsToReturn.size();
session.removeAttribute(resKey);
if( log.isDebugEnabled()) log.debug("getEntitiesByVClassContinuation(): sending " + count + " Ind without continue token");
}
//put all the entities on the JSON array
JSONArray ja = individualsToJson( entsToReturn );
//put the responseGroup number on the end of the JSON array
if( more ){
try{
JSONObject obj = new JSONObject();
obj.put("resultGroup", "true");
obj.put("size", count);
StringBuffer nextUrlStr = req.getRequestURL();
nextUrlStr.append("?")
.append("getEntitiesByVClass").append( "=1&" )
.append("resultKey=").append( resKey );
obj.put("nextUrl", nextUrlStr.toString());
ja.put(obj);
}catch(JSONException je ){
throw new ServletException(je.getMessage());
}
}
resp.setContentType("application/json");
ServletOutputStream out = resp.getOutputStream();
out.print( ja.toString() );
log.debug("done with getEntitiesByVClassContinuation()");
}
/**
* Gets a list of entities that are members of the indicated vClass.
*
* If the list is large then we will pass some token indicating that there is more
* to come. The results are sent back in 250 entity blocks. To get all of the
* entities for a VClass just keep requesting lists until there are not more
* continue tokens.
*
* If there are more entities the last item on the returned array will be an object
* with no id property. It will look like this:
*
* {"resultGroup":0,
* "resultKey":"2WEK2306",
* "nextUrl":"http://caruso.mannlib.cornell.edu:8080/vitro/dataservice?getEntitiesByVClass=1&resultKey=2WEK2306&resultGroup=1&vclassId=null",
* "entsInVClass":1752,
* "nextResultGroup":1,
* "standardReplySize":256}
*
*/
private void getEntitiesByVClass(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException{
log.debug("in getEntitiesByVClass()");
VitroRequest vreq = new VitroRequest(req);
String vclassURI = vreq.getParameter("vclassURI");
WebappDaoFactory daos = (new VitroRequest(req)).getFullWebappDaoFactory();
resp.setCharacterEncoding("UTF-8");
// ServletOutputStream doesn't support UTF-8
PrintWriter out = resp.getWriter();
resp.getWriter();
if( vclassURI == null ){
log.debug("getEntitiesByVClass(): no value for 'vclassURI' found in the HTTP request");
out.print( (new JSONArray()).toString() ); return;
}
VClass vclass = daos.getVClassDao().getVClassByURI( vclassURI );
if( vclass == null ){
log.debug("getEntitiesByVClass(): could not find vclass for uri '"+ vclassURI + "'");
out.print( (new JSONArray()).toString() ); return;
}
List<Individual> entsInVClass = daos.getIndividualDao().getIndividualsByVClass( vclass );
if( entsInVClass == null ){
log.debug("getEntitiesByVClass(): null List<Individual> retruned by getIndividualsByVClass() for "+vclassURI);
out.print( (new JSONArray().toString() )); return ;
}
int numberOfEntsInVClass = entsInVClass.size();
List<Individual> entsToReturn = new ArrayList<Individual>( REPLY_SIZE );
String requestHash = null;
int count = 0;
boolean more = false;
/* we have a large number of items to send back so we need to stash the list in the session scope */
if( entsInVClass.size() > REPLY_SIZE){
more = true;
HttpSession session = vreq.getSession(true);
requestHash = Integer.toString((vclassURI + System.currentTimeMillis()).hashCode());
session.setAttribute(requestHash, entsInVClass );
ListIterator<Individual> entsFromVclass = entsInVClass.listIterator();
while ( entsFromVclass.hasNext() && count < REPLY_SIZE ){
entsToReturn.add( entsFromVclass.next());
entsFromVclass.remove();
count++;
}
if( log.isDebugEnabled() ){ log.debug("getEntitiesByVClass(): Creating reply with continue token, found " + numberOfEntsInVClass + " Individuals"); }
}else{
if( log.isDebugEnabled() ) log.debug("getEntitiesByVClass(): sending " + numberOfEntsInVClass +" Individuals without continue token");
entsToReturn = entsInVClass;
count = entsToReturn.size();
}
//put all the entities on the JSON array
JSONArray ja = individualsToJson( entsToReturn );
//put the responseGroup number on the end of the JSON array
if( more ){
try{
JSONObject obj = new JSONObject();
obj.put("resultGroup", "true");
obj.put("size", count);
obj.put("total", numberOfEntsInVClass);
StringBuffer nextUrlStr = req.getRequestURL();
nextUrlStr.append("?")
.append("getEntitiesByVClass").append( "=1&" )
.append("resultKey=").append( requestHash );
obj.put("nextUrl", nextUrlStr.toString());
ja.put(obj);
}catch(JSONException je ){
throw new ServletException("unable to create continuation as JSON: " + je.getMessage());
}
}
resp.setContentType("application/json");
out.print( ja.toString() );
log.debug("done with getEntitiesByVClass()");
}
private JSONArray individualsToJson(List<Individual> individuals) throws ServletException {
JSONArray ja = new JSONArray();
Iterator it = individuals.iterator();
try{
while(it.hasNext()){
Individual ent = (Individual) it.next();
JSONObject entJ = new JSONObject();
entJ.put("name", ent.getName());
entJ.put("URI", ent.getURI());
ja.put( entJ );
}
}catch(JSONException ex){
throw new ServletException("could not convert list of Individuals into JSON: " + ex);
}
return ja;
}
private static final int REPLY_SIZE = 256;
private static final Log log = LogFactory.getLog(JSONServlet.class.getName());
}

View file

@ -0,0 +1,328 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.search.controller;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.util.Version;
import org.json.JSONArray;
import com.hp.hpl.jena.sparql.lib.org.json.JSONObject;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.UseBasicAjaxControllers;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.ajax.VitroAjaxController;
import edu.cornell.mannlib.vitro.webapp.search.SearchException;
import edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc.VitroLuceneTermNames;
import edu.cornell.mannlib.vitro.webapp.search.lucene.LuceneIndexFactory;
import edu.cornell.mannlib.vitro.webapp.search.lucene.LuceneSetup;
/**
* AutocompleteController generates autocomplete content
* through a Lucene search.
*/
public class SolrAutocompleteController extends VitroAjaxController {
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(SolrAutocompleteController.class);
//private static final String TEMPLATE_DEFAULT = "autocompleteResults.ftl";
private static String QUERY_PARAMETER_NAME = "term";
String NORESULT_MSG = "";
private int defaultMaxSearchSize= 1000;
@Override
protected Actions requiredActions(VitroRequest vreq) {
return new Actions(new UseBasicAjaxControllers());
}
@Override
protected void doRequest(VitroRequest vreq, HttpServletResponse response)
throws IOException, ServletException {
try {
int maxHitSize = defaultMaxSearchSize;
String qtxt = vreq.getParameter(QUERY_PARAMETER_NAME);
Analyzer analyzer = getAnalyzer(getServletContext());
Query query = getQuery(vreq, analyzer, qtxt);
if (query == null ) {
log.debug("query for '" + qtxt +"' is null.");
doNoQuery(response);
return;
}
log.debug("query for '" + qtxt +"' is " + query.toString());
IndexSearcher searcherForRequest = LuceneIndexFactory.getIndexSearcher(getServletContext());
TopDocs topDocs = null;
try{
topDocs = searcherForRequest.search(query,null,maxHitSize);
}catch(Throwable t){
log.error("in first pass at search: " + t);
// this is a hack to deal with odd cases where search and index threads interact
try{
wait(150);
topDocs = searcherForRequest.search(query,null,maxHitSize);
}catch (Exception e){
log.error(e, e);
doNoSearchResults(response);
return;
}
}
if( topDocs == null || topDocs.scoreDocs == null){
log.error("topDocs for a search was null");
doNoSearchResults(response);
return;
}
int hitsLength = topDocs.scoreDocs.length;
if ( hitsLength < 1 ){
doNoSearchResults(response);
return;
}
log.debug("found "+hitsLength+" hits");
List<SearchResult> results = new ArrayList<SearchResult>();
for(int i=0; i<topDocs.scoreDocs.length ;i++){
try{
Document doc = searcherForRequest.doc(topDocs.scoreDocs[i].doc);
String uri = doc.get(VitroLuceneTermNames.URI);
String name = doc.get(VitroLuceneTermNames.NAMERAW);
SearchResult result = new SearchResult(name, uri);
results.add(result);
} catch(Exception e){
log.error("problem getting usable Individuals from search " +
"hits" + e.getMessage());
}
}
Collections.sort(results);
// map.put("results", results);
// writeTemplate(TEMPLATE_DEFAULT, map, config, vreq, response);
JSONArray jsonArray = new JSONArray();
for (SearchResult result : results) {
jsonArray.put(result.toMap());
}
response.getWriter().write(jsonArray.toString());
} catch (Throwable e) {
log.error(e, e);
doSearchError(response);
}
}
private Analyzer getAnalyzer(ServletContext servletContext) throws SearchException {
Object obj = servletContext.getAttribute(LuceneSetup.ANALYZER);
if( obj == null || !(obj instanceof Analyzer) )
throw new SearchException("Could not get analyzer");
else
return (Analyzer)obj;
}
private Query getQuery(VitroRequest vreq, Analyzer analyzer,
String querystr) throws SearchException{
Query query = null;
try {
if( querystr == null){
log.error("There was no Parameter '"+ QUERY_PARAMETER_NAME
+"' in the request.");
return null;
}else if( querystr.length() > MAX_QUERY_LENGTH ){
log.debug("The search was too long. The maximum " +
"query length is " + MAX_QUERY_LENGTH );
return null;
}
query = makeNameQuery(querystr, analyzer, vreq);
// Filter by type
{
BooleanQuery boolQuery = new BooleanQuery();
String typeParam = (String) vreq.getParameter("type");
boolQuery.add( new TermQuery(
new Term(VitroLuceneTermNames.RDFTYPE,
typeParam)),
BooleanClause.Occur.MUST);
boolQuery.add(query, BooleanClause.Occur.MUST);
query = boolQuery;
}
} catch (Exception ex){
throw new SearchException(ex.getMessage());
}
return query;
}
private Query makeNameQuery(String querystr, Analyzer analyzer, HttpServletRequest request) {
String tokenizeParam = (String) request.getParameter("tokenize");
boolean tokenize = "true".equals(tokenizeParam);
// Note: Stemming is only relevant if we are tokenizing: an untokenized name
// query will not be stemmed. So we don't look at the stem parameter until we get to
// makeTokenizedNameQuery().
if (tokenize) {
return makeTokenizedNameQuery(querystr, analyzer, request);
} else {
return makeUntokenizedNameQuery(querystr);
}
}
private Query makeTokenizedNameQuery(String querystr, Analyzer analyzer, HttpServletRequest request) {
String stemParam = (String) request.getParameter("stem");
boolean stem = "true".equals(stemParam);
String termName = stem ? VitroLuceneTermNames.NAME : VitroLuceneTermNames.NAMEUNSTEMMED;
BooleanQuery boolQuery = new BooleanQuery();
// Use the query parser to analyze the search term the same way the indexed text was analyzed.
// For example, text is lowercased, and function words are stripped out.
QueryParser parser = getQueryParser(termName, analyzer);
// The wildcard query doesn't play well with stemming. Query term name:tales* doesn't match
// "tales", which is indexed as "tale", while query term name:tales does. Obviously we need
// the wildcard for name:tal*, so the only way to get them all to match is use a disjunction
// of wildcard and non-wildcard queries. The query will look have only an implicit disjunction
// operator: e.g., +(name:tales name:tales*)
try {
log.debug("Adding non-wildcard query for " + querystr);
Query query = parser.parse(querystr);
boolQuery.add(query, BooleanClause.Occur.SHOULD);
// Prevent ParseException here when adding * after a space.
// If there's a space at the end, we don't need the wildcard query.
if (! querystr.endsWith(" ")) {
log.debug("Adding wildcard query for " + querystr);
Query wildcardQuery = parser.parse(querystr + "*");
boolQuery.add(wildcardQuery, BooleanClause.Occur.SHOULD);
}
log.debug("Name query is: " + boolQuery.toString());
} catch (ParseException e) {
log.warn(e, e);
}
return boolQuery;
}
private Query makeUntokenizedNameQuery(String querystr) {
querystr = querystr.toLowerCase();
String termName = VitroLuceneTermNames.NAMELOWERCASE;
BooleanQuery query = new BooleanQuery();
log.debug("Adding wildcard query on unanalyzed name");
query.add(
new WildcardQuery(new Term(termName, querystr + "*")),
BooleanClause.Occur.MUST);
return query;
}
private QueryParser getQueryParser(String searchField, Analyzer analyzer){
// searchField indicates which field to search against when there is no term
// indicated in the query string.
// The analyzer is needed so that we use the same analyzer on the search queries as
// was used on the text that was indexed.
QueryParser qp = new QueryParser(Version.LUCENE_29, searchField,analyzer);
//this sets the query parser to AND all of the query terms it finds.
qp.setDefaultOperator(QueryParser.AND_OPERATOR);
return qp;
}
private void doNoQuery(HttpServletResponse response) throws IOException {
// For now, we are not sending an error message back to the client because with the default autocomplete configuration it
// chokes.
doNoSearchResults(response);
}
private void doSearchError(HttpServletResponse response) throws IOException {
// For now, we are not sending an error message back to the client because with the default autocomplete configuration it
// chokes.
doNoSearchResults(response);
}
private void doNoSearchResults(HttpServletResponse response) throws IOException {
response.getWriter().write("[]");
}
public static final int MAX_QUERY_LENGTH = 500;
public class SearchResult implements Comparable<Object> {
private String label;
private String uri;
SearchResult(String label, String uri) {
this.label = label;
this.uri = uri;
}
public String getLabel() {
return label;
}
public String getJsonLabel() {
return JSONObject.quote(label);
}
public String getUri() {
return uri;
}
public String getJsonUri() {
return JSONObject.quote(uri);
}
Map<String, String> toMap() {
Map<String, String> map = new HashMap<String, String>();
map.put("label", label);
map.put("uri", uri);
return map;
}
public int compareTo(Object o) throws ClassCastException {
if ( !(o instanceof SearchResult) ) {
throw new ClassCastException("Error in SearchResult.compareTo(): expected SearchResult object.");
}
SearchResult sr = (SearchResult) o;
return label.compareToIgnoreCase(sr.getLabel());
}
}
}