Removing several lucene search controllers and classes.
Adding QueryExecution close() to PageDaoJena Adding AdditionalURIsToIndex interface and tests.
This commit is contained in:
parent
e6f4c2a861
commit
9caf053898
19 changed files with 237 additions and 3991 deletions
|
@ -1,160 +0,0 @@
|
|||
/* $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.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
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.document.Document;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.ScoreDoc;
|
||||
import org.apache.lucene.search.Sort;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.lucene.search.TopDocs;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.rdf.model.ResourceFactory;
|
||||
import com.hp.hpl.jena.vocabulary.RDF;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc;
|
||||
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.web.ContentType;
|
||||
|
||||
|
||||
|
||||
public class EntityURLController extends VitroHttpServlet {
|
||||
private static final Log log = LogFactory.getLog(EntityURLController.class.getName());
|
||||
public static final int ENTITY_LIST_CONTROLLER_MAX_RESULTS = 30000;
|
||||
|
||||
public void doGet (HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException{
|
||||
|
||||
String url = req.getRequestURI().substring(req.getContextPath().length());
|
||||
ContentType contentType = checkForRequestType(req.getHeader("accept"));
|
||||
|
||||
if(Pattern.compile("^/listrdf/$").matcher(url).matches()){
|
||||
String redirectURL = null;
|
||||
if(contentType!=null){
|
||||
if ( RDFXML_MIMETYPE.equals(contentType.getMediaType()))
|
||||
redirectURL = "/listrdf/listrdf.rdf";
|
||||
else if( N3_MIMETYPE.equals(contentType.getMediaType()))
|
||||
redirectURL = "/listrdf/listrdf.n3";
|
||||
else if ( TTL_MIMETYPE.equals(contentType.getMediaType()))
|
||||
redirectURL = "/listrdf/listrdf.ttl";
|
||||
}
|
||||
else{
|
||||
redirectURL = "/listrdf/listrdf.rdf";
|
||||
}
|
||||
|
||||
String hn = req.getHeader("Host");
|
||||
if (req.isSecure()) {
|
||||
res.setHeader("Location", res.encodeURL("https://" + hn
|
||||
+ req.getContextPath() + redirectURL));
|
||||
log.info("doRedirect by using HTTPS");
|
||||
} else {
|
||||
res.setHeader("Location", res.encodeURL("http://" + hn
|
||||
+ req.getContextPath() + redirectURL));
|
||||
log.info("doRedirect by using HTTP");
|
||||
}
|
||||
res.setStatus(res.SC_SEE_OTHER);
|
||||
return;
|
||||
}
|
||||
|
||||
String classUri = (String) getServletContext().getAttribute("classuri");
|
||||
BooleanQuery query = new BooleanQuery();
|
||||
query.add(
|
||||
new TermQuery( new Term(VitroLuceneTermNames.RDFTYPE, classUri)),
|
||||
BooleanClause.Occur.MUST );
|
||||
|
||||
IndexSearcher index = LuceneIndexFactory.getIndexSearcher(getServletContext());
|
||||
TopDocs docs = index.search(query, null,
|
||||
ENTITY_LIST_CONTROLLER_MAX_RESULTS,
|
||||
new Sort(VitroLuceneTermNames.NAME_LOWERCASE));
|
||||
|
||||
if( docs == null ){
|
||||
log.error("Search of lucene index returned null");
|
||||
throw new ServletException("Search of lucene index returned null");
|
||||
}
|
||||
|
||||
int ii = 0;
|
||||
int size = docs.totalHits;
|
||||
Resource resource = null;
|
||||
RDFNode node = null;
|
||||
Model model = ModelFactory.createDefaultModel();
|
||||
while( ii < size ){
|
||||
ScoreDoc hit = docs.scoreDocs[ii];
|
||||
if (hit != null) {
|
||||
Document doc = index.doc(hit.doc);
|
||||
if (doc != null) {
|
||||
String uri = doc.getField(VitroLuceneTermNames.URI).stringValue();
|
||||
resource = ResourceFactory.createResource(uri);
|
||||
node = (RDFNode) ResourceFactory.createResource(classUri);
|
||||
model.add(resource, RDF.type, node);
|
||||
} else {
|
||||
log.warn("no document found for lucene doc id " + hit.doc);
|
||||
}
|
||||
} else {
|
||||
log.debug("hit was null");
|
||||
}
|
||||
ii++;
|
||||
}
|
||||
|
||||
String format = "";
|
||||
if(contentType != null){
|
||||
if ( RDFXML_MIMETYPE.equals(contentType.getMediaType()))
|
||||
format = "RDF/XML";
|
||||
else if( N3_MIMETYPE.equals(contentType.getMediaType()))
|
||||
format = "N3";
|
||||
else if ( TTL_MIMETYPE.equals(contentType.getMediaType()))
|
||||
format ="TTL";
|
||||
res.setContentType(contentType.getMediaType());
|
||||
}
|
||||
else{
|
||||
res.setContentType(RDFXML_MIMETYPE);
|
||||
format = "RDF/XML";
|
||||
}
|
||||
model.write(res.getOutputStream(), format);
|
||||
}
|
||||
public void doPost (HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException{
|
||||
doGet(req,res);
|
||||
}
|
||||
|
||||
protected ContentType checkForRequestType(String acceptHeader) {
|
||||
try {
|
||||
//check the accept header
|
||||
if (acceptHeader != null) {
|
||||
List<ContentType> actualContentTypes = new ArrayList<ContentType>();
|
||||
actualContentTypes.add(new ContentType( XHTML_MIMETYPE ));
|
||||
actualContentTypes.add(new ContentType( HTML_MIMETYPE ));
|
||||
|
||||
actualContentTypes.add(new ContentType( RDFXML_MIMETYPE ));
|
||||
actualContentTypes.add(new ContentType( N3_MIMETYPE ));
|
||||
actualContentTypes.add(new ContentType( TTL_MIMETYPE ));
|
||||
|
||||
|
||||
ContentType best = ContentType.getBestContentType(acceptHeader,actualContentTypes);
|
||||
if (best!=null && (
|
||||
RDFXML_MIMETYPE.equals(best.getMediaType()) ||
|
||||
N3_MIMETYPE.equals(best.getMediaType()) ||
|
||||
TTL_MIMETYPE.equals(best.getMediaType()) ))
|
||||
return best;
|
||||
}
|
||||
}
|
||||
catch (Throwable th) {
|
||||
log.error("problem while checking accept header " , th);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,621 +0,0 @@
|
|||
/* $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.Arrays;
|
||||
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.configuration.EditConfiguration;
|
||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.SelectListGenerator;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.ProhibitedFromSearch;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.pageDataGetter.IndividualsForClassesDataGetter;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.pageDataGetter.DataGetterUtils;
|
||||
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 JSONServlet 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;
|
||||
} else if( vreq.getParameter("getSolrIndividualsByVClasses") != null ){
|
||||
getSolrIndividualsByVClasses(req,resp);
|
||||
return;
|
||||
} else if( vreq.getParameter("getDataForPage") != null ){
|
||||
getDataForPage(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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Accepts multiple vclasses and returns individuals which correspond to the intersection of those classes (i.e. have all those types)
|
||||
private void getSolrIndividualsByVClasses( HttpServletRequest req, HttpServletResponse resp ){
|
||||
String errorMessage = null;
|
||||
JSONObject rObj = null;
|
||||
try{
|
||||
VitroRequest vreq = new VitroRequest(req);
|
||||
VClass vclass=null;
|
||||
|
||||
//Could have multiple vclass Ids sent in
|
||||
List<String> vclassIds = new ArrayList<String>();
|
||||
String[] vitroClassIdStr = vreq.getParameterValues("vclassId");
|
||||
if ( vitroClassIdStr != null && vitroClassIdStr.length > 0){
|
||||
for(String vclassId: vitroClassIdStr) {
|
||||
vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vclassId);
|
||||
if (vclass == null) {
|
||||
log.debug("Couldn't retrieve vclass ");
|
||||
throw new Exception (errorMessage = "Class " + vclassId + " not found");
|
||||
}
|
||||
}
|
||||
}else{
|
||||
log.debug("parameter vclassId URI parameter expected ");
|
||||
throw new Exception("parameter vclassId URI parameter expected ");
|
||||
}
|
||||
vclassIds = Arrays.asList(vitroClassIdStr);
|
||||
//rObj = getLuceneIndividualsByVClass(vclass.getURI(),req, getServletContext());
|
||||
rObj = getSolrIndividualsByVClasses(vclassIds,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);
|
||||
Map<String, Object> map = getLuceneVclassResults(vclassURI, vreq, context);
|
||||
//Last parameter defines whether single or multiple vclasses expected
|
||||
JSONObject rObj = processVclassResults(map, vreq, context, false);
|
||||
return rObj;
|
||||
}
|
||||
|
||||
public static JSONObject getSolrIndividualsByVClasses(List<String> vclassURIs, HttpServletRequest req, ServletContext context) throws Exception {
|
||||
VitroRequest vreq = new VitroRequest(req);
|
||||
Map<String, Object> map = getSolrVclassIntersectionResults(vclassURIs, vreq, context);
|
||||
JSONObject rObj = processVclassResults(map, vreq, context, true);
|
||||
return rObj;
|
||||
}
|
||||
|
||||
//Factoring out to allow for results to be processed from query for both lucene and solr
|
||||
//Map given to process method includes the actual individuals returned from the search
|
||||
public static JSONObject processVclassResults(Map<String, Object> map, VitroRequest vreq, ServletContext context, boolean multipleVclasses) throws Exception{
|
||||
JSONObject rObj = DataGetterUtils.processVclassResultsJSON(map, vreq, multipleVclasses);
|
||||
return rObj;
|
||||
}
|
||||
private static Map<String,Object> getLuceneVclassResults(String vclassURI, VitroRequest vreq, ServletContext context){
|
||||
String alpha = IndividualListController.getAlphaParameter(vreq);
|
||||
int page = IndividualListController.getPageParameter(vreq);
|
||||
Map<String,Object> map = null;
|
||||
try {
|
||||
map = IndividualListController.getResultsForVClass(
|
||||
vclassURI,
|
||||
page,
|
||||
alpha,
|
||||
vreq.getWebappDaoFactory().getIndividualDao(),
|
||||
context);
|
||||
} catch(Exception ex) {
|
||||
log.error("Error in retrieval of Lucene results for VClass " + vclassURI, ex);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
//Including version for Solr query for Vclass Intersections
|
||||
private static Map<String,Object> getSolrVclassIntersectionResults(List<String> vclassURIs, VitroRequest vreq, ServletContext context){
|
||||
String alpha = IndividualListController.getAlphaParameter(vreq);
|
||||
int page = IndividualListController.getPageParameter(vreq);
|
||||
Map<String,Object> map = null;
|
||||
try {
|
||||
map = IndividualListController.getResultsForVClassIntersections(
|
||||
vclassURIs,
|
||||
page,
|
||||
alpha,
|
||||
vreq.getWebappDaoFactory().getIndividualDao(),
|
||||
context);
|
||||
} catch(Exception ex) {
|
||||
log.error("Error in retrieval of Lucene results for VClass " + vclassURIs.toString(), ex);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public 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 "";
|
||||
}
|
||||
|
||||
public 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()");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data based on data getter for page uri and returns in the form of Json objects
|
||||
* @param req
|
||||
* @param resp
|
||||
*/
|
||||
private void getDataForPage(HttpServletRequest req, HttpServletResponse resp) {
|
||||
VitroRequest vreq = new VitroRequest(req);
|
||||
String errorMessage = null;
|
||||
JSONObject rObj = null;
|
||||
String pageUri = vreq.getParameter("pageUri");
|
||||
if(pageUri != null && !pageUri.isEmpty()) {
|
||||
ServletContext context = getServletContext();
|
||||
Map<String,Object> data = DataGetterUtils.getDataForPage(pageUri, vreq, context);
|
||||
//Convert to json version based on type of page
|
||||
if(data != null) {
|
||||
//Convert to json version based on type of page
|
||||
rObj = DataGetterUtils.covertDataToJSONForPage(pageUri, data, vreq, context);
|
||||
}
|
||||
}
|
||||
|
||||
if( rObj == null )
|
||||
rObj = new JSONObject();
|
||||
//Send object
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
|
@ -1,511 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
|
||||
|
||||
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 org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.index.CorruptIndexException;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.PrefixQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.ScoreDoc;
|
||||
import org.apache.lucene.search.Sort;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.lucene.search.TopDocs;
|
||||
import org.apache.solr.client.solrj.SolrQuery;
|
||||
import org.apache.solr.client.solrj.SolrServer;
|
||||
import org.apache.solr.client.solrj.response.QueryResponse;
|
||||
import org.apache.solr.common.SolrDocument;
|
||||
import org.apache.solr.common.SolrDocumentList;
|
||||
|
||||
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.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ExceptionResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc;
|
||||
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.solr.SolrSetup;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individuallist.BaseListedIndividual;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individuallist.ListedIndividual;
|
||||
import freemarker.ext.beans.BeansWrapper;
|
||||
import freemarker.template.TemplateModel;
|
||||
|
||||
/**
|
||||
* Generates a list of individuals for display in a template
|
||||
*/
|
||||
public class IndividualListController extends FreemarkerHttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Log log = LogFactory.getLog(IndividualListController.class.getName());
|
||||
|
||||
public static final int ENTITY_LIST_CONTROLLER_MAX_RESULTS = 30000;
|
||||
public static final int INDIVIDUALS_PER_PAGE = 30;
|
||||
public static final int MAX_PAGES = 40; //must be even
|
||||
|
||||
private static final String TEMPLATE_DEFAULT = "individualList.ftl";
|
||||
|
||||
@Override
|
||||
protected ResponseValues processRequest(VitroRequest vreq) {
|
||||
|
||||
String templateName = TEMPLATE_DEFAULT;
|
||||
Map<String, Object> body = new HashMap<String, Object>();
|
||||
String errorMessage = null;
|
||||
|
||||
try {
|
||||
Object obj = vreq.getAttribute("vclass");
|
||||
VClass vclass = null;
|
||||
if ( obj == null ) { // look for vitroclass id parameter
|
||||
String vitroClassIdStr = vreq.getParameter("vclassId");
|
||||
if ( !StringUtils.isEmpty(vitroClassIdStr)) {
|
||||
try {
|
||||
//TODO have to change this so vclass's group and entity count are populated
|
||||
vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vitroClassIdStr);
|
||||
if (vclass == null) {
|
||||
log.error("Couldn't retrieve vclass " + vitroClassIdStr);
|
||||
errorMessage = "Class " + vitroClassIdStr + " not found";
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new HelpException("IndividualListController: request parameter 'vclassId' must be a URI string.");
|
||||
}
|
||||
}
|
||||
} else if (obj instanceof VClass) {
|
||||
vclass = (VClass)obj;
|
||||
} else {
|
||||
throw new HelpException("IndividualListController: attribute 'vclass' must be of type "
|
||||
+ VClass.class.getName() + ".");
|
||||
}
|
||||
|
||||
body.put("vclassId", vclass.getURI());
|
||||
|
||||
if (vclass != null) {
|
||||
String alpha = getAlphaParameter(vreq);
|
||||
int page = getPageParameter(vreq);
|
||||
Map<String,Object> map = getResultsForVClass(
|
||||
vclass.getURI(),
|
||||
page,
|
||||
alpha,
|
||||
vreq.getWebappDaoFactory().getIndividualDao(),
|
||||
getServletContext());
|
||||
body.putAll(map);
|
||||
|
||||
List<Individual> inds = (List<Individual>)map.get("entities");
|
||||
List<ListedIndividual> indsTm = new ArrayList<ListedIndividual>();
|
||||
for(Individual ind : inds ){
|
||||
indsTm.add(new ListedIndividual(ind,vreq));
|
||||
}
|
||||
body.put("individuals", indsTm);
|
||||
|
||||
List<TemplateModel> wpages = new ArrayList<TemplateModel>();
|
||||
List<PageRecord> pages = (List<PageRecord>)body.get("pages");
|
||||
BeansWrapper wrapper = new BeansWrapper();
|
||||
for( PageRecord pr: pages ){
|
||||
wpages.add( wrapper.wrap(pr) );
|
||||
}
|
||||
|
||||
// Set title and subtitle. Title will be retrieved later in getTitle().
|
||||
VClassGroup classGroup = vclass.getGroup();
|
||||
String title;
|
||||
if (classGroup == null) {
|
||||
title = vclass.getName();
|
||||
} else {
|
||||
title = classGroup.getPublicName();
|
||||
body.put("subtitle", vclass.getName());
|
||||
}
|
||||
body.put("title", title);
|
||||
body.put("rdfUrl", UrlBuilder.getUrl("/listrdf", "vclass", vclass.getURI()));
|
||||
|
||||
}
|
||||
|
||||
} catch (HelpException help){
|
||||
errorMessage = "Request attribute 'vclass' or request parameter 'vclassId' must be set before calling. Its value must be a class uri.";
|
||||
} catch (Throwable e) {
|
||||
return new ExceptionResponseValues(e);
|
||||
}
|
||||
|
||||
if (errorMessage != null) {
|
||||
templateName = Template.ERROR_MESSAGE.toString();
|
||||
body.put("errorMessage", errorMessage);
|
||||
}
|
||||
|
||||
return new TemplateResponseValues(templateName, body);
|
||||
}
|
||||
|
||||
private class HelpException extends Throwable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public HelpException(String string) {
|
||||
super(string);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getAlphaParameter(VitroRequest request){
|
||||
return request.getParameter("alpha");
|
||||
}
|
||||
|
||||
public static int getPageParameter(VitroRequest request) {
|
||||
String pageStr = request.getParameter("page");
|
||||
if( pageStr != null ){
|
||||
try{
|
||||
return Integer.parseInt(pageStr);
|
||||
}catch(NumberFormatException nfe){
|
||||
log.debug("could not parse page parameter");
|
||||
return 1;
|
||||
}
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is now called in a couple of places. It should be refactored
|
||||
* into a DAO or similar object.
|
||||
*/
|
||||
public static Map<String,Object> getResultsForVClass(String vclassURI, int page, String alpha, IndividualDao indDao, ServletContext context)
|
||||
throws CorruptIndexException, IOException, ServletException{
|
||||
Map<String,Object> rvMap = new HashMap<String,Object>();
|
||||
try{
|
||||
//make lucene query for this rdf:type
|
||||
List<String> classUris = new ArrayList<String>();
|
||||
classUris.add(vclassURI);
|
||||
Query query = getQuery(classUris, alpha);
|
||||
rvMap = getResultsForVClassQuery(query, page, alpha, indDao, context);
|
||||
List<Individual> individuals = (List<Individual>) rvMap.get("entities");
|
||||
if (individuals == null)
|
||||
log.debug("entities list is null for vclass " + vclassURI );
|
||||
} catch(Throwable th) {
|
||||
log.error("An error occurred retrieving results for vclass query", th);
|
||||
}
|
||||
return rvMap;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method includes what was formerly a part of the method above, allowing for refactoring of code
|
||||
* to use for a different number fo classes
|
||||
*/
|
||||
|
||||
public static Map<String,Object> getResultsForVClassQuery(Query query, int page, String alpha, IndividualDao indDao, ServletContext context)
|
||||
throws CorruptIndexException, IOException, ServletException{
|
||||
Map<String,Object> rvMap = new HashMap<String,Object>();
|
||||
|
||||
//execute lucene query for individuals of the specified type
|
||||
IndexSearcher index = LuceneIndexFactory.getIndexSearcher(context);
|
||||
TopDocs docs = null;
|
||||
try{
|
||||
docs = index.search(query, null,
|
||||
ENTITY_LIST_CONTROLLER_MAX_RESULTS,
|
||||
new Sort(Entity2LuceneDoc.term.NAME_LOWERCASE));
|
||||
}catch(Throwable th){
|
||||
log.error("Could not run search. " + th.getMessage());
|
||||
docs = null;
|
||||
}
|
||||
|
||||
if( docs == null )
|
||||
throw new ServletException("Could not run search in IndividualListController");
|
||||
|
||||
//get list of individuals for the search results
|
||||
int size = docs.totalHits;
|
||||
log.debug("Number of search results: " + size);
|
||||
|
||||
// don't get all the results, only get results for the requestedSize
|
||||
List<Individual> individuals = new ArrayList<Individual>(INDIVIDUALS_PER_PAGE);
|
||||
int individualsAdded = 0;
|
||||
int ii = (page-1)*INDIVIDUALS_PER_PAGE;
|
||||
while( individualsAdded < INDIVIDUALS_PER_PAGE && ii < size ){
|
||||
ScoreDoc hit = docs.scoreDocs[ii];
|
||||
if (hit != null) {
|
||||
Document doc = index.doc(hit.doc);
|
||||
if (doc != null) {
|
||||
String uri = doc.getField(Entity2LuceneDoc.term.URI).stringValue();
|
||||
Individual ind = indDao.getIndividualByURI( uri );
|
||||
if( ind != null ){
|
||||
individuals.add( ind );
|
||||
individualsAdded++;
|
||||
}
|
||||
} else {
|
||||
log.warn("no document found for lucene doc id " + hit.doc);
|
||||
}
|
||||
} else {
|
||||
log.debug("hit was null");
|
||||
}
|
||||
ii++;
|
||||
}
|
||||
|
||||
rvMap.put("count", size);
|
||||
|
||||
if( size > INDIVIDUALS_PER_PAGE ){
|
||||
rvMap.put("showPages", Boolean.TRUE);
|
||||
List<PageRecord> pageRecords = makePagesList(size, INDIVIDUALS_PER_PAGE, page);
|
||||
rvMap.put("pages", pageRecords);
|
||||
}else{
|
||||
rvMap.put("showPages", Boolean.FALSE);
|
||||
rvMap.put("pages", Collections.emptyList());
|
||||
}
|
||||
|
||||
rvMap.put("alpha",alpha);
|
||||
|
||||
rvMap.put("totalCount", size);
|
||||
rvMap.put("entities",individuals);
|
||||
|
||||
return rvMap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Solr based version
|
||||
public static Map<String,Object> getResultsForVClassQuery(SolrQuery query, int page, String alpha, IndividualDao indDao, ServletContext context)
|
||||
throws CorruptIndexException, IOException, ServletException{
|
||||
Map<String,Object> rvMap = new HashMap<String,Object>();
|
||||
//Execute solr query
|
||||
SolrServer solr = SolrSetup.getSolrServer(context);
|
||||
QueryResponse response = null;
|
||||
|
||||
try {
|
||||
response = solr.query(query);
|
||||
|
||||
} 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{
|
||||
//Can't use the method below in a static class?
|
||||
//wait(150);
|
||||
response = solr.query(query);
|
||||
} catch (Exception ex) {
|
||||
log.error(ex);
|
||||
//doFailedSearch()
|
||||
//return doFailedSearch(msg, qtxt, format);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SolrDocumentList docs = response.getResults();
|
||||
if( docs == null )
|
||||
throw new ServletException("Could not run search in IndividualListController");
|
||||
|
||||
//get list of individuals for the search results
|
||||
|
||||
int size = new Long(docs.getNumFound()).intValue();
|
||||
log.debug("Number of search results: " + size);
|
||||
|
||||
// don't get all the results, only get results for the requestedSize
|
||||
List<Individual> individuals = new ArrayList<Individual>(INDIVIDUALS_PER_PAGE);
|
||||
int individualsAdded = 0;
|
||||
int ii = (page-1)*INDIVIDUALS_PER_PAGE;
|
||||
while( individualsAdded < INDIVIDUALS_PER_PAGE && ii < size ){
|
||||
SolrDocument doc = docs.get(ii);
|
||||
if (doc != null) {
|
||||
String uri = doc.get(VitroLuceneTermNames.URI).toString();
|
||||
log.debug("Retrieving individual with uri "+ uri);
|
||||
Individual ind = indDao.getIndividualByURI(uri);
|
||||
if( ind != null ){
|
||||
individuals.add( ind );
|
||||
individualsAdded++;
|
||||
}
|
||||
} else {
|
||||
log.warn("no document found for lucene doc id " + doc);
|
||||
}
|
||||
ii++;
|
||||
}
|
||||
|
||||
rvMap.put("count", size);
|
||||
|
||||
if( size > INDIVIDUALS_PER_PAGE ){
|
||||
rvMap.put("showPages", Boolean.TRUE);
|
||||
List<PageRecord> pageRecords = makePagesList(size, INDIVIDUALS_PER_PAGE, page);
|
||||
rvMap.put("pages", pageRecords);
|
||||
}else{
|
||||
rvMap.put("showPages", Boolean.FALSE);
|
||||
rvMap.put("pages", Collections.emptyList());
|
||||
}
|
||||
|
||||
rvMap.put("alpha",alpha);
|
||||
|
||||
rvMap.put("totalCount", size);
|
||||
rvMap.put("entities",individuals);
|
||||
|
||||
return rvMap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static Map<String,Object> getResultsForVClassIntersections(List<String> vclassURIs, int page, String alpha, IndividualDao indDao, ServletContext context)
|
||||
throws CorruptIndexException, IOException, ServletException{
|
||||
Map<String,Object> rvMap = new HashMap<String,Object>();
|
||||
try{
|
||||
//make lucene query for multiple rdf types
|
||||
//change to solr
|
||||
SolrQuery query = getSolrQuery(vclassURIs, alpha);
|
||||
//get results corresponding to this query
|
||||
rvMap = getResultsForVClassQuery(query, page, alpha, indDao, context);
|
||||
List<Individual> individuals = (List<Individual>) rvMap.get("entities");
|
||||
if (individuals == null)
|
||||
log.debug("entities list is null for vclass " + vclassURIs.toString() );
|
||||
} catch(Throwable th) {
|
||||
log.error("Error retrieving individuals corresponding to intersection multiple classes." + vclassURIs.toString(), th);
|
||||
}
|
||||
return rvMap;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This method creates a query to search for terms with rdf type corresponding to vclass Uri.
|
||||
* The original version allowed only for one class URI but needed to be extended to enable multiple
|
||||
* vclass Uris to be passed
|
||||
*/
|
||||
|
||||
private static BooleanQuery getQuery(List<String>vclassUris, String alpha){
|
||||
BooleanQuery query = new BooleanQuery();
|
||||
try{
|
||||
//query term for rdf:type - multiple types possible
|
||||
for(String vclassUri: vclassUris) {
|
||||
query.add(
|
||||
new TermQuery( new Term(Entity2LuceneDoc.term.RDFTYPE, vclassUri)),
|
||||
BooleanClause.Occur.MUST );
|
||||
}
|
||||
//Add alpha filter if it is needed
|
||||
Query alphaQuery = null;
|
||||
if( alpha != null && !"".equals(alpha) && alpha.length() == 1){
|
||||
alphaQuery =
|
||||
new PrefixQuery(new Term(Entity2LuceneDoc.term.NAME_LOWERCASE, alpha.toLowerCase()));
|
||||
query.add(alphaQuery,BooleanClause.Occur.MUST);
|
||||
}
|
||||
|
||||
log.debug("Query: " + query);
|
||||
return query;
|
||||
} catch (Exception ex){
|
||||
log.error(ex,ex);
|
||||
return new BooleanQuery();
|
||||
}
|
||||
}
|
||||
|
||||
//how to extend for solr query
|
||||
//Alpha handling taken from SolrIndividualListController
|
||||
private static SolrQuery getSolrQuery(List<String>vclassUris, String alpha){
|
||||
//SolrQuery query = getQuery(qtxt, maxHitCount, vreq);
|
||||
//SolrServer solr = SolrSetup.getSolrServer(getServletContext());
|
||||
SolrQuery query = new SolrQuery();
|
||||
|
||||
// Solr requires these values, but we don't want them to be the real values for this page
|
||||
// of results, else the refinement links won't work correctly: each page of results needs to
|
||||
// show refinement links generated for all results, not just for the results on the current page.
|
||||
query.setStart(0)
|
||||
.setRows(1000);
|
||||
String queryText = "";
|
||||
//Query text should be of form:
|
||||
List<String> queryTypes = new ArrayList<String>();
|
||||
try{
|
||||
//query term for rdf:type - multiple types possible
|
||||
for(String vclassUri: vclassUris) {
|
||||
queryTypes.add(VitroLuceneTermNames.RDFTYPE + ":\"" + vclassUri + "\" ");
|
||||
|
||||
}
|
||||
|
||||
if(queryTypes.size() > 1) {
|
||||
queryText = StringUtils.join(queryTypes, " AND ");
|
||||
} else {
|
||||
if(queryTypes.size() > 0) {
|
||||
queryText = queryTypes.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Add alpha filter if it is needed
|
||||
if ( alpha != null && !"".equals(alpha) && alpha.length() == 1) {
|
||||
queryText += VitroLuceneTermNames.NAME_LOWERCASE + ":" + alpha.toLowerCase() + "*";
|
||||
}
|
||||
|
||||
log.debug("Query text is " + queryText);
|
||||
query.setQuery(queryText);
|
||||
log.debug("Query: " + query);
|
||||
return query;
|
||||
} catch (Exception ex){
|
||||
log.error(ex,ex);
|
||||
|
||||
return new SolrQuery();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static List<PageRecord> makePagesList( int count, int pageSize, int selectedPage){
|
||||
|
||||
List<PageRecord> records = new ArrayList<PageRecord>( MAX_PAGES + 1 );
|
||||
int requiredPages = count/pageSize ;
|
||||
int remainder = count % pageSize ;
|
||||
if( remainder > 0 )
|
||||
requiredPages++;
|
||||
|
||||
if( selectedPage < MAX_PAGES && requiredPages > MAX_PAGES ){
|
||||
//the selected pages is within the first maxPages, just show the normal pages up to maxPages.
|
||||
for(int page = 1; page < requiredPages && page <= MAX_PAGES ; page++ ){
|
||||
records.add( new PageRecord( "page=" + page, Integer.toString(page), Integer.toString(page), selectedPage == page ) );
|
||||
}
|
||||
records.add( new PageRecord( "page="+ (MAX_PAGES+1), Integer.toString(MAX_PAGES+1), "more...", false));
|
||||
}else if( requiredPages > MAX_PAGES && selectedPage+1 > MAX_PAGES && selectedPage < requiredPages - MAX_PAGES){
|
||||
//the selected pages is in the middle of the list of page
|
||||
int startPage = selectedPage - MAX_PAGES / 2;
|
||||
int endPage = selectedPage + MAX_PAGES / 2;
|
||||
for(int page = startPage; page <= endPage ; page++ ){
|
||||
records.add( new PageRecord( "page=" + page, Integer.toString(page), Integer.toString(page), selectedPage == page ) );
|
||||
}
|
||||
records.add( new PageRecord( "page="+ endPage+1, Integer.toString(endPage+1), "more...", false));
|
||||
}else if ( requiredPages > MAX_PAGES && selectedPage > requiredPages - MAX_PAGES ){
|
||||
//the selected page is in the end of the list
|
||||
int startPage = requiredPages - MAX_PAGES;
|
||||
double max = Math.ceil(count/pageSize);
|
||||
for(int page = startPage; page <= max; page++ ){
|
||||
records.add( new PageRecord( "page=" + page, Integer.toString(page), Integer.toString(page), selectedPage == page ) );
|
||||
}
|
||||
}else{
|
||||
//there are fewer than maxPages pages.
|
||||
for(int i = 1; i <= requiredPages; i++ ){
|
||||
records.add( new PageRecord( "page=" + i, Integer.toString(i), Integer.toString(i), selectedPage == i ) );
|
||||
}
|
||||
}
|
||||
return records;
|
||||
}
|
||||
|
||||
public static class PageRecord {
|
||||
public PageRecord(String param, String index, String text, boolean selected) {
|
||||
this.param = param;
|
||||
this.index = index;
|
||||
this.text = text;
|
||||
this.selected = selected;
|
||||
}
|
||||
public String param;
|
||||
public String index;
|
||||
public String text;
|
||||
public boolean selected=false;
|
||||
|
||||
public String getParam() {
|
||||
return param;
|
||||
}
|
||||
public String getIndex() {
|
||||
return index;
|
||||
}
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
public boolean getSelected(){
|
||||
return selected;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -186,13 +186,21 @@ public class PageDaoJena extends JenaBaseDao implements PageDao {
|
|||
@Override
|
||||
public Map<String, String> getPageMappings() {
|
||||
Model displayModel = getOntModelSelector().getDisplayModel();
|
||||
QueryExecution qexec = QueryExecutionFactory.create( pageQuery, displayModel );
|
||||
|
||||
Map<String,String> rv = new HashMap<String,String>();
|
||||
ResultSet resultSet = qexec.execSelect();
|
||||
while(resultSet.hasNext()){
|
||||
QuerySolution soln = resultSet.next();
|
||||
rv.put(nodeToString(soln.get("urlMapping")) , nodeToString( soln.get("pageUri") ));
|
||||
displayModel.enterCriticalSection(false);
|
||||
try{
|
||||
QueryExecution qexec = QueryExecutionFactory.create( pageQuery, displayModel );
|
||||
try{
|
||||
ResultSet resultSet = qexec.execSelect();
|
||||
while(resultSet.hasNext()){
|
||||
QuerySolution soln = resultSet.next();
|
||||
rv.put(nodeToString(soln.get("urlMapping")) , nodeToString( soln.get("pageUri") ));
|
||||
}
|
||||
}finally{
|
||||
qexec.close();
|
||||
}
|
||||
}finally{
|
||||
displayModel.leaveCriticalSection();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
@ -211,8 +219,11 @@ public class PageDaoJena extends JenaBaseDao implements PageDao {
|
|||
displayModel.enterCriticalSection(false);
|
||||
try{
|
||||
QueryExecution qexec = QueryExecutionFactory.create(pageQuery,displayModel,initialBindings );
|
||||
list = executeQueryToCollection( qexec );
|
||||
qexec.close();
|
||||
try{
|
||||
list = executeQueryToCollection( qexec );
|
||||
}finally{
|
||||
qexec.close();
|
||||
}
|
||||
}finally{
|
||||
displayModel.leaveCriticalSection();
|
||||
}
|
||||
|
@ -236,12 +247,15 @@ public class PageDaoJena extends JenaBaseDao implements PageDao {
|
|||
displayModel.enterCriticalSection(false);
|
||||
try{
|
||||
QueryExecution qexec = QueryExecutionFactory.create(pageDataGettersQuery, displayModel, initialBindings);
|
||||
ResultSet rs = qexec.execSelect();
|
||||
while(rs.hasNext()){
|
||||
QuerySolution soln = rs.next();
|
||||
dataGetters.add( nodeToString( soln.get("dataGetter" ) ));
|
||||
try{
|
||||
ResultSet rs = qexec.execSelect();
|
||||
while(rs.hasNext()){
|
||||
QuerySolution soln = rs.next();
|
||||
dataGetters.add( nodeToString( soln.get("dataGetter" ) ));
|
||||
}
|
||||
}finally{
|
||||
qexec.close();
|
||||
}
|
||||
qexec.close();
|
||||
}finally{
|
||||
displayModel.leaveCriticalSection();
|
||||
}
|
||||
|
@ -257,23 +271,31 @@ public class PageDaoJena extends JenaBaseDao implements PageDao {
|
|||
@Override
|
||||
public String getHomePageUri(){
|
||||
Model displayModel = getOntModelSelector().getDisplayModel();
|
||||
QueryExecution qexec = QueryExecutionFactory.create( homePageUriQuery, displayModel );
|
||||
|
||||
List<String> rv = new ArrayList<String>();
|
||||
ResultSet resultSet = qexec.execSelect();
|
||||
while(resultSet.hasNext()){
|
||||
QuerySolution soln = resultSet.next();
|
||||
rv.add( nodeToString(soln.get("pageUri")) );
|
||||
}
|
||||
if( rv.size() == 0 ){
|
||||
log.error("No display:HomePage defined in display model.");
|
||||
return null;
|
||||
}
|
||||
if( rv.size() > 1 ){
|
||||
log.error("More than one display:HomePage defined in display model.");
|
||||
for( String hp : rv ){
|
||||
log.error("home page: " + hp);
|
||||
displayModel.enterCriticalSection(false);
|
||||
try{
|
||||
QueryExecution qexec = QueryExecutionFactory.create( homePageUriQuery, displayModel );
|
||||
try{
|
||||
ResultSet resultSet = qexec.execSelect();
|
||||
while(resultSet.hasNext()){
|
||||
QuerySolution soln = resultSet.next();
|
||||
rv.add( nodeToString(soln.get("pageUri")) );
|
||||
}
|
||||
if( rv.size() == 0 ){
|
||||
log.error("No display:HomePage defined in display model.");
|
||||
return null;
|
||||
}
|
||||
if( rv.size() > 1 ){
|
||||
log.error("More than one display:HomePage defined in display model.");
|
||||
for( String hp : rv ){
|
||||
log.error("home page: " + hp);
|
||||
}
|
||||
}
|
||||
}finally{
|
||||
qexec.close();
|
||||
}
|
||||
}finally{
|
||||
displayModel.leaveCriticalSection();
|
||||
}
|
||||
return rv.get(0);
|
||||
}
|
||||
|
@ -291,22 +313,29 @@ public class PageDaoJena extends JenaBaseDao implements PageDao {
|
|||
initialBindings.add("pageUri", ResourceFactory.createResource(pageUri));
|
||||
|
||||
Model displayModel = getOntModelSelector().getDisplayModel();
|
||||
QueryExecution qexec = QueryExecutionFactory.create( classGroupPageQuery, displayModel , initialBindings);
|
||||
|
||||
List<String> classGroupsForPage = new ArrayList<String>();
|
||||
ResultSet resultSet = qexec.execSelect();
|
||||
while(resultSet.hasNext()){
|
||||
QuerySolution soln = resultSet.next();
|
||||
classGroupsForPage.add( nodeToString(soln.get("classGroup")) );
|
||||
try{
|
||||
QueryExecution qexec = QueryExecutionFactory.create( classGroupPageQuery, displayModel , initialBindings);
|
||||
try{
|
||||
List<String> classGroupsForPage = new ArrayList<String>();
|
||||
ResultSet resultSet = qexec.execSelect();
|
||||
while(resultSet.hasNext()){
|
||||
QuerySolution soln = resultSet.next();
|
||||
classGroupsForPage.add( nodeToString(soln.get("classGroup")) );
|
||||
}
|
||||
if( classGroupsForPage.size() == 0 ){
|
||||
log.debug("No classgroup info defined in display model for "+ pageUri);
|
||||
return null;
|
||||
}
|
||||
if( classGroupsForPage.size() > 1 ){
|
||||
log.error("More than one display:forClassGroup defined in display model for page " + pageUri);
|
||||
}
|
||||
return classGroupsForPage.get(0);
|
||||
}finally{
|
||||
qexec.close();
|
||||
}
|
||||
}finally{
|
||||
displayModel.leaveCriticalSection();
|
||||
}
|
||||
if( classGroupsForPage.size() == 0 ){
|
||||
log.debug("No classgroup info defined in display model for "+ pageUri);
|
||||
return null;
|
||||
}
|
||||
if( classGroupsForPage.size() > 1 ){
|
||||
log.error("More than one display:forClassGroup defined in display model for page " + pageUri);
|
||||
}
|
||||
return classGroupsForPage.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -318,32 +347,40 @@ public class PageDaoJena extends JenaBaseDao implements PageDao {
|
|||
initialBindings.add("pageUri", ResourceFactory.createResource(pageUri));
|
||||
|
||||
Model displayModel = getOntModelSelector().getDisplayModel();
|
||||
QueryExecution qexec = QueryExecutionFactory.create( classIntersectionPageQuery, displayModel , initialBindings);
|
||||
//Assuming unique labels or could use URI itself?
|
||||
//TODO: Review whether to use labels or URIs
|
||||
|
||||
|
||||
ResultSet resultSet = qexec.execSelect();
|
||||
while(resultSet.hasNext()){
|
||||
QuerySolution soln = resultSet.next();
|
||||
//Results format should be ?page hasClassIntersection <a>. <a> intersectsWithClass ?c; <a> intersects With Class ?e.
|
||||
String intersectionLabel = nodeToString(soln.get("label"));
|
||||
|
||||
//first time encountering label, set up
|
||||
if(!classIntersectionsMap.containsKey(intersectionLabel)) {
|
||||
classIntersectionsMap.put(intersectionLabel, new ArrayList<String>());
|
||||
}
|
||||
|
||||
List<String> classes = classIntersectionsMap.get(intersectionLabel);
|
||||
classes.add(nodeToString(soln.get("class")));
|
||||
//classIntersections.add( nodeToString(soln.get("classIntersection")) );
|
||||
try{
|
||||
QueryExecution qexec = QueryExecutionFactory.create( classIntersectionPageQuery, displayModel , initialBindings);
|
||||
try{
|
||||
//Assuming unique labels or could use URI itself?
|
||||
//TODO: Review whether to use labels or URIs
|
||||
|
||||
|
||||
ResultSet resultSet = qexec.execSelect();
|
||||
while(resultSet.hasNext()){
|
||||
QuerySolution soln = resultSet.next();
|
||||
//Results format should be ?page hasClassIntersection <a>. <a> intersectsWithClass ?c; <a> intersects With Class ?e.
|
||||
String intersectionLabel = nodeToString(soln.get("label"));
|
||||
|
||||
//first time encountering label, set up
|
||||
if(!classIntersectionsMap.containsKey(intersectionLabel)) {
|
||||
classIntersectionsMap.put(intersectionLabel, new ArrayList<String>());
|
||||
}
|
||||
|
||||
List<String> classes = classIntersectionsMap.get(intersectionLabel);
|
||||
classes.add(nodeToString(soln.get("class")));
|
||||
//classIntersections.add( nodeToString(soln.get("classIntersection")) );
|
||||
}
|
||||
if( classIntersectionsMap.size() == 0 ){
|
||||
log.debug("No class intersections info defined in display model for "+ pageUri);
|
||||
return null;
|
||||
}
|
||||
|
||||
return classIntersectionsMap;
|
||||
}finally{
|
||||
qexec.close();
|
||||
}
|
||||
}finally{
|
||||
displayModel.leaveCriticalSection();
|
||||
}
|
||||
if( classIntersectionsMap.size() == 0 ){
|
||||
log.debug("No class intersections info defined in display model for "+ pageUri);
|
||||
return null;
|
||||
}
|
||||
|
||||
return classIntersectionsMap;
|
||||
}
|
||||
|
||||
|
||||
|
@ -362,40 +399,50 @@ public class PageDaoJena extends JenaBaseDao implements PageDao {
|
|||
QuerySolutionMap initialBindings = new QuerySolutionMap();
|
||||
initialBindings.add("pageUri", ResourceFactory.createResource(pageUri));
|
||||
List<String> classes = new ArrayList<String>();
|
||||
Model displayModel = getOntModelSelector().getDisplayModel();
|
||||
QueryExecution qexec = QueryExecutionFactory.create( individualsForClassesQuery, displayModel , initialBindings);
|
||||
HashMap<String, String> restrictClassesPresentMap = new HashMap<String, String>();
|
||||
List<String> restrictClasses = new ArrayList<String>();
|
||||
|
||||
ResultSet resultSet = qexec.execSelect();
|
||||
while(resultSet.hasNext()){
|
||||
QuerySolution soln = resultSet.next();
|
||||
String dg = nodeToString(soln.get("dg"));
|
||||
classes.add(nodeToString(soln.get("class")));
|
||||
String restrictClass = nodeToString(soln.get("restrictClass"));
|
||||
if(!restrictClassesPresentMap.containsKey(restrictClass)) {
|
||||
restrictClasses.add(restrictClass);
|
||||
restrictClassesPresentMap.put(restrictClass, "true");
|
||||
}
|
||||
}
|
||||
|
||||
if( classes.size() == 0 ){
|
||||
log.debug("No classes defined in display model for "+ pageUri);
|
||||
return null;
|
||||
Model displayModel = getOntModelSelector().getDisplayModel();
|
||||
try{
|
||||
QueryExecution qexec = QueryExecutionFactory.create( individualsForClassesQuery, displayModel , initialBindings);
|
||||
try{
|
||||
HashMap<String, String> restrictClassesPresentMap = new HashMap<String, String>();
|
||||
List<String> restrictClasses = new ArrayList<String>();
|
||||
|
||||
ResultSet resultSet = qexec.execSelect();
|
||||
while(resultSet.hasNext()){
|
||||
QuerySolution soln = resultSet.next();
|
||||
String dg = nodeToString(soln.get("dg"));
|
||||
classes.add(nodeToString(soln.get("class")));
|
||||
String restrictClass = nodeToString(soln.get("restrictClass"));
|
||||
if(!restrictClassesPresentMap.containsKey(restrictClass)) {
|
||||
restrictClasses.add(restrictClass);
|
||||
restrictClassesPresentMap.put(restrictClass, "true");
|
||||
}
|
||||
}
|
||||
|
||||
if( classes.size() == 0 ){
|
||||
log.debug("No classes defined in display model for "+ pageUri);
|
||||
return null;
|
||||
}
|
||||
classesAndRestrictions.put("classes", classes);
|
||||
classesAndRestrictions.put("restrictClasses", restrictClasses);
|
||||
return classesAndRestrictions;
|
||||
}finally{
|
||||
qexec.close();
|
||||
}
|
||||
}finally{
|
||||
displayModel.leaveCriticalSection();
|
||||
}
|
||||
classesAndRestrictions.put("classes", classes);
|
||||
classesAndRestrictions.put("restrictClasses", restrictClasses);
|
||||
return classesAndRestrictions;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ****************************************************************************** */
|
||||
/* *************************** Utility methods ********************************* */
|
||||
|
||||
/**
|
||||
* Converts a sparql query that returns a multiple rows to a list of maps.
|
||||
* The maps will have column names as keys to the values.
|
||||
* This method will not close qexec.
|
||||
*/
|
||||
protected List<Map<String, Object>> executeQueryToCollection(
|
||||
QueryExecution qexec) {
|
||||
|
|
|
@ -1,326 +0,0 @@
|
|||
/* $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 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;
|
||||
|
||||
/**
|
||||
* AutocompleteController generates autocomplete content
|
||||
* through a Lucene search.
|
||||
*/
|
||||
public class AutocompleteController extends VitroAjaxController {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Log log = LogFactory.getLog(AutocompleteController.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.NAME_RAW);
|
||||
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_STEMMED : VitroLuceneTermNames.NAME_UNSTEMMED;
|
||||
|
||||
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.NAME_LOWERCASE;
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,868 +0,0 @@
|
|||
/* $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.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
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.document.Field;
|
||||
import org.apache.lucene.index.CorruptIndexException;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.queryParser.MultiFieldQueryParser;
|
||||
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.Explanation;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.ScoreDoc;
|
||||
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 edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ExceptionResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VClassDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.SearchException;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.Searcher;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.VitroHighlighter;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQuery;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQueryFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.lucene.CustomSimilarity;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc;
|
||||
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.web.templatemodels.LinkTemplateModel;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individuallist.BaseListedIndividual;
|
||||
import freemarker.template.Configuration;
|
||||
|
||||
/**
|
||||
* PagedSearchController is the new search controller that interacts
|
||||
* directly with the lucene API and returns paged, relevance ranked results.
|
||||
*
|
||||
* @author bdc34
|
||||
*
|
||||
* Rewritten to use Freemarker: rjy7
|
||||
*
|
||||
*/
|
||||
public class PagedSearchController extends FreemarkerHttpServlet implements Searcher {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Log log = LogFactory.getLog(PagedSearchController.class.getName());
|
||||
private static final String XML_REQUEST_PARAM = "xml";
|
||||
|
||||
private IndexSearcher searcher = null;
|
||||
private int defaultHitsPerPage = 25;
|
||||
private int defaultMaxSearchSize= 1000;
|
||||
|
||||
protected static final Map<Format,Map<Result,String>> templateTable;
|
||||
private static final float QUERY_BOOST = 2.0F;
|
||||
|
||||
protected enum Format{
|
||||
HTML, XML;
|
||||
}
|
||||
|
||||
protected enum Result{
|
||||
PAGED, FORM, ERROR, BAD_QUERY
|
||||
}
|
||||
|
||||
static{
|
||||
templateTable = setupTemplateTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding doGet from FreemarkerHttpController to do a page template (as
|
||||
* opposed to body template) style output for XML requests.
|
||||
*
|
||||
* This follows the pattern in AutocompleteController.java.
|
||||
*/
|
||||
@Override
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
boolean wasXmlRequested = isRequestedFormatXml(request);
|
||||
if( ! wasXmlRequested ){
|
||||
super.doGet(request,response);
|
||||
}else{
|
||||
try {
|
||||
VitroRequest vreq = new VitroRequest(request);
|
||||
Configuration config = getConfig(vreq);
|
||||
ResponseValues rvalues = processRequest(vreq);
|
||||
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setContentType("text/xml;charset=UTF-8");
|
||||
writeTemplate(rvalues.getTemplateName(), rvalues.getMap(), config, request, response);
|
||||
} catch (Exception e) {
|
||||
log.error(e, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResponseValues processRequest(VitroRequest vreq) {
|
||||
|
||||
log.debug("All parameters present in the request: "+ vreq.getParameterMap().toString());
|
||||
|
||||
//There may be other non-html formats in the future
|
||||
Format format = getFormat(vreq);
|
||||
boolean wasXmlRequested = Format.XML == format;
|
||||
log.debug("Requested format was " + (wasXmlRequested ? "xml" : "html"));
|
||||
boolean wasHtmlRequested = ! wasXmlRequested;
|
||||
|
||||
try {
|
||||
ApplicationBean appBean = vreq.getAppBean();
|
||||
|
||||
//make sure an IndividualDao is available
|
||||
if( vreq.getWebappDaoFactory() == null
|
||||
|| vreq.getWebappDaoFactory().getIndividualDao() == null ){
|
||||
log.error("Could not get webappDaoFactory or IndividualDao");
|
||||
throw new Exception("Could not access model.");
|
||||
}
|
||||
IndividualDao iDao = vreq.getWebappDaoFactory().getIndividualDao();
|
||||
VClassGroupDao grpDao = vreq.getWebappDaoFactory().getVClassGroupDao();
|
||||
VClassDao vclassDao = vreq.getWebappDaoFactory().getVClassDao();
|
||||
String alphaFilter = vreq.getParameter("alpha");
|
||||
|
||||
|
||||
log.debug("IndividualDao is " + iDao.toString() + " Public classes in the classgroup are " + grpDao.getPublicGroupsWithVClasses().toString());
|
||||
log.debug("VClassDao is "+ vclassDao.toString() );
|
||||
|
||||
int startIndex = 0;
|
||||
try{
|
||||
startIndex = Integer.parseInt(vreq.getParameter("startIndex"));
|
||||
}catch (Throwable e) {
|
||||
startIndex = 0;
|
||||
}
|
||||
log.debug("startIndex is " + startIndex);
|
||||
|
||||
int hitsPerPage = defaultHitsPerPage;
|
||||
try{
|
||||
hitsPerPage = Integer.parseInt(vreq.getParameter("hitsPerPage"));
|
||||
} catch (Throwable e) {
|
||||
hitsPerPage = defaultHitsPerPage;
|
||||
}
|
||||
log.debug("hitsPerPage is " + hitsPerPage);
|
||||
|
||||
int maxHitSize = defaultMaxSearchSize;
|
||||
if( startIndex >= defaultMaxSearchSize - hitsPerPage )
|
||||
maxHitSize = startIndex + defaultMaxSearchSize;
|
||||
if( alphaFilter != null ){
|
||||
maxHitSize = maxHitSize * 2;
|
||||
hitsPerPage = maxHitSize;
|
||||
}
|
||||
log.debug("maxHitSize is " + maxHitSize);
|
||||
|
||||
String qtxt = vreq.getParameter(VitroQuery.QUERY_PARAMETER_NAME);
|
||||
Analyzer analyzer = getAnalyzer(getServletContext());
|
||||
|
||||
log.debug("Query text is "+ qtxt + " Analyzer is "+ analyzer.toString());
|
||||
|
||||
Query query = null;
|
||||
try {
|
||||
query = getQuery(vreq, analyzer, qtxt);
|
||||
log.debug("query for '" + qtxt +"' is " + query.toString());
|
||||
} catch (ParseException e) {
|
||||
return doBadQuery(appBean, qtxt,format);
|
||||
}
|
||||
|
||||
IndexSearcher searcherForRequest = LuceneIndexFactory.getIndexSearcher(getServletContext());
|
||||
|
||||
/* using the CustomSimilarity to override effects such as
|
||||
* 1) rarity of a term doesn't affect the document score.
|
||||
* 2) number of instances of a query term in the matched document doesn't affect the document score
|
||||
* 3) field length doesn't affect the document score
|
||||
*
|
||||
* 3/29/2011 bk392
|
||||
*/
|
||||
CustomSimilarity customSimilarity = new CustomSimilarity();
|
||||
searcherForRequest.setSimilarity(customSimilarity);
|
||||
|
||||
TopDocs topDocs = null;
|
||||
try{
|
||||
log.debug("Searching for query term in the Index with maxHitSize "+ maxHitSize);
|
||||
log.debug("Query is "+ query.toString());
|
||||
|
||||
//sets the query boost for the query. the lucene docs matching this query term
|
||||
//are multiplied by QUERY_BOOST to get their total score
|
||||
//query.setBoost(QUERY_BOOST);
|
||||
|
||||
topDocs = searcherForRequest.search(query,null,maxHitSize);
|
||||
|
||||
log.debug("Total hits for the query are "+ topDocs.totalHits);
|
||||
for(ScoreDoc scoreDoc : topDocs.scoreDocs){
|
||||
|
||||
Document document = searcherForRequest.doc(scoreDoc.doc);
|
||||
Explanation explanation = searcherForRequest.explain(query, scoreDoc.doc);
|
||||
|
||||
log.debug("Document title: "+ document.get(Entity2LuceneDoc.VitroLuceneTermNames.NAME_STEMMED) + " score: " +scoreDoc.score);
|
||||
log.debug("Scoring of the doc explained " + explanation.toString());
|
||||
log.debug("Explanation's description "+ explanation.getDescription());
|
||||
log.debug("ALLTEXT: " + document.get(Entity2LuceneDoc.VitroLuceneTermNames.ALLTEXT));
|
||||
log.debug("ALLTEXTUNSTEMMED: " + document.get(Entity2LuceneDoc.VitroLuceneTermNames.ALLTEXTUNSTEMMED));
|
||||
|
||||
|
||||
}
|
||||
|
||||
}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 ex){
|
||||
log.error(ex);
|
||||
String msg = makeBadSearchMessage(qtxt,ex.getMessage());
|
||||
if (msg == null) {
|
||||
msg = "The search request contained errors.";
|
||||
}
|
||||
return doFailedSearch(msg, qtxt,format);
|
||||
}
|
||||
}
|
||||
|
||||
if( topDocs == null || topDocs.scoreDocs == null){
|
||||
log.error("topDocs for a search was null");
|
||||
String msg = "The search request contained errors.";
|
||||
return doFailedSearch(msg, qtxt,format);
|
||||
}
|
||||
|
||||
|
||||
int hitsLength = topDocs.scoreDocs.length;
|
||||
log.debug("No. of hits "+ hitsLength);
|
||||
if ( hitsLength < 1 ){
|
||||
return doNoHits(qtxt,format);
|
||||
}
|
||||
log.debug("found "+hitsLength+" hits");
|
||||
|
||||
int lastHitToShow = 0;
|
||||
if((startIndex + hitsPerPage) > hitsLength ) {
|
||||
lastHitToShow = hitsLength;
|
||||
} else {
|
||||
lastHitToShow = startIndex + hitsPerPage - 1;
|
||||
}
|
||||
|
||||
List<Individual> beans = new LinkedList<Individual>();
|
||||
for(int i=startIndex; i<topDocs.scoreDocs.length ;i++){
|
||||
try{
|
||||
if( (i >= startIndex) && (i <= lastHitToShow) ){
|
||||
Document doc = searcherForRequest.doc(topDocs.scoreDocs[i].doc);
|
||||
String uri = doc.get(Entity2LuceneDoc.term.URI);
|
||||
log.debug("Retrieving entity with uri "+ uri);
|
||||
Individual ent = new IndividualImpl();
|
||||
ent.setURI(uri);
|
||||
ent = iDao.getIndividualByURI(uri);
|
||||
if(ent!=null)
|
||||
beans.add(ent);
|
||||
}
|
||||
}catch(Exception e){
|
||||
log.error("problem getting usable Individuals from search " +
|
||||
"hits" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
ParamMap pagingLinkParams = new ParamMap();
|
||||
pagingLinkParams.put("querytext", qtxt);
|
||||
pagingLinkParams.put("hitsPerPage", String.valueOf(hitsPerPage));
|
||||
|
||||
if( wasXmlRequested ){
|
||||
pagingLinkParams.put(XML_REQUEST_PARAM,"1");
|
||||
}
|
||||
|
||||
/* Start putting together the data for the templates */
|
||||
|
||||
Map<String, Object> body = new HashMap<String, Object>();
|
||||
|
||||
String classGroupParam = vreq.getParameter("classgroup");
|
||||
boolean classGroupFilterRequested = false;
|
||||
if (!StringUtils.isEmpty(classGroupParam)) {
|
||||
VClassGroup grp = grpDao.getGroupByURI(classGroupParam);
|
||||
classGroupFilterRequested = true;
|
||||
if (grp != null && grp.getPublicName() != null)
|
||||
body.put("classGroupName", grp.getPublicName());
|
||||
}
|
||||
|
||||
String typeParam = vreq.getParameter("type");
|
||||
boolean typeFiltereRequested = false;
|
||||
if (!StringUtils.isEmpty(typeParam)) {
|
||||
VClass type = vclassDao.getVClassByURI(typeParam);
|
||||
typeFiltereRequested = true;
|
||||
if (type != null && type.getName() != null)
|
||||
body.put("typeName", type.getName());
|
||||
}
|
||||
|
||||
/* Add classgroup and type refinement links to body */
|
||||
if( wasHtmlRequested ){
|
||||
// Search request includes no classgroup and no type, so add classgroup search refinement links.
|
||||
if ( !classGroupFilterRequested && !typeFiltereRequested ) {
|
||||
List<VClassGroup> classgroups = getClassGroups(grpDao, topDocs, searcherForRequest);
|
||||
List<VClassGroupSearchLink> classGroupLinks = new ArrayList<VClassGroupSearchLink>(classgroups.size());
|
||||
for (VClassGroup vcg : classgroups) {
|
||||
if (vcg.getPublicName() != null) {
|
||||
classGroupLinks.add(new VClassGroupSearchLink(qtxt, vcg));
|
||||
}
|
||||
}
|
||||
body.put("classGroupLinks", classGroupLinks);
|
||||
|
||||
// Search request is for a classgroup, so add rdf:type search refinement links
|
||||
// but try to filter out classes that are subclasses
|
||||
} else if ( classGroupFilterRequested && !typeFiltereRequested ) {
|
||||
List<VClass> vClasses = getVClasses(vclassDao,topDocs,searcherForRequest);
|
||||
List<VClassSearchLink> vClassLinks = new ArrayList<VClassSearchLink>(vClasses.size());
|
||||
for (VClass vc : vClasses) {
|
||||
vClassLinks.add(new VClassSearchLink(qtxt, vc));
|
||||
}
|
||||
body.put("classLinks", vClassLinks);
|
||||
pagingLinkParams.put("classgroup", classGroupParam);
|
||||
|
||||
// This case is never displayed
|
||||
} else if (!StringUtils.isEmpty(alphaFilter)) {
|
||||
body.put("alphas", getAlphas(topDocs, searcherForRequest));
|
||||
alphaSortIndividuals(beans);
|
||||
} else {
|
||||
pagingLinkParams.put("type", typeParam);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert search result individuals to template model objects
|
||||
body.put("individuals", BaseListedIndividual
|
||||
.getIndividualTemplateModels(beans, vreq));
|
||||
|
||||
body.put("querytext", qtxt);
|
||||
body.put("title", qtxt + " - " + appBean.getApplicationName()
|
||||
+ " Search Results");
|
||||
|
||||
body.put("hitCount",hitsLength);
|
||||
body.put("startIndex", startIndex);
|
||||
|
||||
body.put("pagingLinks", getPagingLinks(startIndex, hitsPerPage,
|
||||
hitsLength, maxHitSize, vreq.getServletPath(),
|
||||
pagingLinkParams));
|
||||
|
||||
if (startIndex != 0) {
|
||||
body.put("prevPage", getPreviousPageLink(startIndex,
|
||||
hitsPerPage, vreq.getServletPath(), pagingLinkParams));
|
||||
}
|
||||
if (startIndex < (hitsLength - hitsPerPage)) {
|
||||
body.put("nextPage", getNextPageLink(startIndex, hitsPerPage,
|
||||
vreq.getServletPath(), pagingLinkParams));
|
||||
}
|
||||
|
||||
String template = templateTable.get(format).get(Result.PAGED);
|
||||
|
||||
return new TemplateResponseValues(template, body);
|
||||
} catch (Throwable e) {
|
||||
return doSearchError(e,format);
|
||||
}
|
||||
}
|
||||
|
||||
private void alphaSortIndividuals(List<Individual> beans) {
|
||||
Collections.sort(beans, new Comparator< Individual >(){
|
||||
public int compare(Individual o1, Individual o2) {
|
||||
if( o1 == null || o1.getName() == null )
|
||||
return 1;
|
||||
else
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}});
|
||||
}
|
||||
|
||||
private List<String> getAlphas(TopDocs topDocs, IndexSearcher searcher) {
|
||||
Set<String> alphas = new HashSet<String>();
|
||||
for(int i=0;i<topDocs.scoreDocs.length; i++){
|
||||
Document doc;
|
||||
try {
|
||||
doc = searcher.doc(topDocs.scoreDocs[i].doc);
|
||||
String name =doc.get(Entity2LuceneDoc.term.NAME_STEMMED);
|
||||
if( name != null && name.length() > 0)
|
||||
alphas.add( name.substring(0, 1));
|
||||
} catch (CorruptIndexException e) {
|
||||
log.debug("Could not get alphas for document",e);
|
||||
} catch (IOException e) {
|
||||
log.debug("Could not get alphas for document",e);
|
||||
}
|
||||
|
||||
}
|
||||
return new ArrayList<String>(alphas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class groups represented for the individuals in the topDocs.
|
||||
*/
|
||||
private List<VClassGroup> getClassGroups(VClassGroupDao grpDao, TopDocs topDocs,
|
||||
IndexSearcher searcherForRequest) {
|
||||
LinkedHashMap<String,VClassGroup> grpMap = grpDao.getClassGroupMap();
|
||||
int n = grpMap.size();
|
||||
|
||||
HashSet<String> classGroupsInHits = new HashSet<String>(n);
|
||||
int grpsFound = 0;
|
||||
|
||||
for(int i=0; i<topDocs.scoreDocs.length && n > grpsFound ;i++){
|
||||
try{
|
||||
Document doc = searcherForRequest.doc(topDocs.scoreDocs[i].doc);
|
||||
Field[] grps = doc.getFields(Entity2LuceneDoc.term.CLASSGROUP_URI);
|
||||
if(grps != null || grps.length > 0){
|
||||
for(int j=0;j<grps.length;j++){
|
||||
String groupUri = grps[j].stringValue();
|
||||
if( groupUri != null && ! classGroupsInHits.contains(groupUri)){
|
||||
classGroupsInHits.add(groupUri);
|
||||
grpsFound++;
|
||||
if( grpsFound >= n )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch(Exception e){
|
||||
log.error("problem getting VClassGroups from search hits "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
List<String> classgroupURIs= Collections.list(Collections.enumeration(classGroupsInHits));
|
||||
List<VClassGroup> classgroups = new ArrayList<VClassGroup>( classgroupURIs.size() );
|
||||
for(String cgUri: classgroupURIs){
|
||||
if( cgUri != null && ! "".equals(cgUri) ){
|
||||
VClassGroup vcg = grpDao.getGroupByURI( cgUri );
|
||||
if( vcg == null ){
|
||||
log.debug("could not get classgroup for URI " + cgUri);
|
||||
}else{
|
||||
classgroups.add(vcg);
|
||||
}
|
||||
}
|
||||
}
|
||||
grpDao.sortGroupList(classgroups);
|
||||
|
||||
return classgroups;
|
||||
}
|
||||
|
||||
private class VClassGroupSearchLink extends LinkTemplateModel {
|
||||
|
||||
VClassGroupSearchLink(String querytext, VClassGroup classgroup) {
|
||||
super(classgroup.getPublicName(), "/search", "querytext", querytext, "classgroup", classgroup.getURI());
|
||||
}
|
||||
}
|
||||
|
||||
private class VClassSearchLink extends LinkTemplateModel {
|
||||
|
||||
VClassSearchLink(String querytext, VClass type) {
|
||||
super(type.getName(), "/search", "querytext", querytext, "type", type.getURI());
|
||||
}
|
||||
}
|
||||
|
||||
private List<PagingLink> getPagingLinks(int startIndex, int hitsPerPage, int hitsLength, int maxHitSize, String baseUrl, ParamMap params) {
|
||||
|
||||
List<PagingLink> pagingLinks = new ArrayList<PagingLink>();
|
||||
|
||||
// No paging links if only one page of results
|
||||
if (hitsLength <= hitsPerPage) {
|
||||
return pagingLinks;
|
||||
}
|
||||
|
||||
for (int i = 0; i < hitsLength; i += hitsPerPage) {
|
||||
params.put("startIndex", String.valueOf(i));
|
||||
if ( i < maxHitSize - hitsPerPage) {
|
||||
int pageNumber = i/hitsPerPage + 1;
|
||||
if (i >= startIndex && i < (startIndex + hitsPerPage)) {
|
||||
pagingLinks.add(new PagingLink(pageNumber));
|
||||
} else {
|
||||
pagingLinks.add(new PagingLink(pageNumber, baseUrl, params));
|
||||
}
|
||||
} else {
|
||||
pagingLinks.add(new PagingLink("more...", baseUrl, params));
|
||||
}
|
||||
}
|
||||
|
||||
return pagingLinks;
|
||||
}
|
||||
|
||||
private String getPreviousPageLink(int startIndex, int hitsPerPage, String baseUrl, ParamMap params) {
|
||||
params.put("startIndex", String.valueOf(startIndex-hitsPerPage));
|
||||
//return new PagingLink("Previous", baseUrl, params);
|
||||
return UrlBuilder.getUrl(baseUrl, params);
|
||||
}
|
||||
|
||||
private String getNextPageLink(int startIndex, int hitsPerPage, String baseUrl, ParamMap params) {
|
||||
params.put("startIndex", String.valueOf(startIndex+hitsPerPage));
|
||||
//return new PagingLink("Next", baseUrl, params);
|
||||
return UrlBuilder.getUrl(baseUrl, params);
|
||||
}
|
||||
|
||||
private class PagingLink extends LinkTemplateModel {
|
||||
|
||||
PagingLink(int pageNumber, String baseUrl, ParamMap params) {
|
||||
super(String.valueOf(pageNumber), baseUrl, params);
|
||||
}
|
||||
|
||||
// Constructor for current page item: not a link, so no url value.
|
||||
PagingLink(int pageNumber) {
|
||||
setText(String.valueOf(pageNumber));
|
||||
}
|
||||
|
||||
// Constructor for "more..." item
|
||||
PagingLink(String text, String baseUrl, ParamMap params) {
|
||||
super(text, baseUrl, params);
|
||||
}
|
||||
}
|
||||
|
||||
private List<VClass> getVClasses(VClassDao vclassDao, TopDocs topDocs,
|
||||
IndexSearcher searherForRequest){
|
||||
HashSet<String> typesInHits = getVClassUrisForHits(topDocs,searherForRequest);
|
||||
List<VClass> classes = new ArrayList<VClass>(typesInHits.size());
|
||||
|
||||
Iterator<String> it = typesInHits.iterator();
|
||||
while(it.hasNext()){
|
||||
String typeUri = it.next();
|
||||
try{
|
||||
if( VitroVocabulary.OWL_THING.equals(typeUri))
|
||||
continue;
|
||||
VClass type = vclassDao.getVClassByURI(typeUri);
|
||||
if( ! type.isAnonymous() &&
|
||||
type.getName() != null && !"".equals(type.getName()) &&
|
||||
type.getGroupURI() != null ) //don't display classes that aren't in classgroups
|
||||
classes.add(type);
|
||||
}catch(Exception ex){
|
||||
if( log.isDebugEnabled() )
|
||||
log.debug("could not add type " + typeUri, ex);
|
||||
}
|
||||
}
|
||||
Collections.sort(classes, new Comparator<VClass>(){
|
||||
public int compare(VClass o1, VClass o2) {
|
||||
return o1.compareTo(o2);
|
||||
}});
|
||||
return classes;
|
||||
}
|
||||
|
||||
private HashSet<String> getVClassUrisForHits(TopDocs topDocs,
|
||||
IndexSearcher searcherForRequest){
|
||||
HashSet<String> typesInHits = new HashSet<String>();
|
||||
for(int i=0; i<topDocs.scoreDocs.length; i++){
|
||||
try{
|
||||
Document doc=searcherForRequest.doc(topDocs.scoreDocs[i].doc);
|
||||
Field[] types = doc.getFields(Entity2LuceneDoc.term.RDFTYPE);
|
||||
if(types != null ){
|
||||
for(int j=0;j<types.length;j++){
|
||||
String typeUri = types[j].stringValue();
|
||||
typesInHits.add(typeUri);
|
||||
}
|
||||
}
|
||||
}catch(Exception e){
|
||||
log.error("problems getting rdf:type for search hits",e);
|
||||
}
|
||||
}
|
||||
return typesInHits;
|
||||
}
|
||||
|
||||
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 request,
|
||||
Analyzer analyzer, String querystr ) throws SearchException, ParseException {
|
||||
Query query = null;
|
||||
try{
|
||||
//String querystr = request.getParameter(VitroQuery.QUERY_PARAMETER_NAME);
|
||||
if( querystr == null){
|
||||
log.error("There was no Parameter '"+VitroQuery.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;
|
||||
}
|
||||
|
||||
log.debug("Parsing query using QueryParser ");
|
||||
|
||||
QueryParser parser = getQueryParser(analyzer);
|
||||
query = parser.parse(querystr);
|
||||
|
||||
String alpha = request.getParameter("alpha");
|
||||
|
||||
if( alpha != null && !"".equals(alpha) && alpha.length() == 1){
|
||||
|
||||
log.debug("Firing alpha query ");
|
||||
log.debug("request.getParameter(alpha) is " + alpha);
|
||||
|
||||
BooleanQuery boolQuery = new BooleanQuery();
|
||||
boolQuery.add( query, BooleanClause.Occur.MUST );
|
||||
boolQuery.add(
|
||||
new WildcardQuery(new Term(Entity2LuceneDoc.term.NAME_STEMMED, alpha+'*')),
|
||||
BooleanClause.Occur.MUST);
|
||||
query = boolQuery;
|
||||
}
|
||||
|
||||
//check if this is classgroup filtered
|
||||
Object param = request.getParameter("classgroup");
|
||||
if( param != null && !"".equals(param)){
|
||||
|
||||
log.debug("Firing classgroup query ");
|
||||
log.debug("request.getParameter(classgroup) is "+ param.toString());
|
||||
|
||||
BooleanQuery boolQuery = new BooleanQuery();
|
||||
boolQuery.add( query, BooleanClause.Occur.MUST);
|
||||
boolQuery.add( new TermQuery(
|
||||
new Term(Entity2LuceneDoc.term.CLASSGROUP_URI,
|
||||
(String)param)),
|
||||
BooleanClause.Occur.MUST);
|
||||
query = boolQuery;
|
||||
}
|
||||
|
||||
//check if this is rdf:type filtered
|
||||
param = request.getParameter("type");
|
||||
if( param != null && !"".equals(param)){
|
||||
log.debug("Firing type query ");
|
||||
log.debug("request.getParameter(type) is "+ param.toString());
|
||||
|
||||
BooleanQuery boolQuery = new BooleanQuery();
|
||||
boolQuery.add( query, BooleanClause.Occur.MUST);
|
||||
boolQuery.add( new TermQuery(
|
||||
new Term(Entity2LuceneDoc.term.RDFTYPE,
|
||||
(String)param)),
|
||||
BooleanClause.Occur.MUST);
|
||||
query = boolQuery;
|
||||
}
|
||||
|
||||
log.debug("Query: " + query);
|
||||
|
||||
} catch (ParseException e) {
|
||||
throw new ParseException(e.getMessage());
|
||||
} catch (Exception ex){
|
||||
throw new SearchException(ex.getMessage());
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@SuppressWarnings("static-access")
|
||||
private QueryParser getQueryParser(Analyzer analyzer){
|
||||
//defaultSearchField indicates which field 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("NAME",analyzer);
|
||||
//this sets the query parser to AND all of the query terms it finds.
|
||||
//set up the map of stemmed field names -> unstemmed field names
|
||||
// HashMap<String,String> map = new HashMap<String, String>();
|
||||
// map.put(Entity2LuceneDoc.term.ALLTEXT,Entity2LuceneDoc.term.ALLTEXTUNSTEMMED);
|
||||
// qp.setStemmedToUnstemmed(map);
|
||||
|
||||
MultiFieldQueryParser qp = new MultiFieldQueryParser(Version.LUCENE_29, new String[]{
|
||||
VitroLuceneTermNames.NAME_STEMMED,
|
||||
VitroLuceneTermNames.NAME_UNSTEMMED,
|
||||
VitroLuceneTermNames.RDFTYPE,
|
||||
VitroLuceneTermNames.ALLTEXT,
|
||||
VitroLuceneTermNames.ALLTEXTUNSTEMMED,
|
||||
VitroLuceneTermNames.NAME_LOWERCASE,
|
||||
VitroLuceneTermNames.CLASSLOCALNAME,
|
||||
VitroLuceneTermNames.CLASSLOCALNAMELOWERCASE }, analyzer);
|
||||
|
||||
// QueryParser qp = new QueryParser(Version.LUCENE_29, "name", analyzer);
|
||||
|
||||
//AND_OPERATOR returns documents even if the terms in the query lie in different fields.
|
||||
//The only requirement is that they exist in a single document.
|
||||
//qp.setDefaultOperator(QueryParser.AND_OPERATOR);
|
||||
|
||||
|
||||
return qp;
|
||||
}
|
||||
|
||||
private ExceptionResponseValues doSearchError(Throwable e, Format f) {
|
||||
Map<String, Object> body = new HashMap<String, Object>();
|
||||
body.put("message", "Search failed: " + e.getMessage());
|
||||
return new ExceptionResponseValues(getTemplate(f,Result.ERROR), body, e);
|
||||
}
|
||||
|
||||
private TemplateResponseValues doBadQuery(ApplicationBean appBean, String query, Format f) {
|
||||
Map<String, Object> body = new HashMap<String, Object>();
|
||||
body.put("title", "Search " + appBean.getApplicationName());
|
||||
body.put("query", query);
|
||||
return new TemplateResponseValues(getTemplate(f,Result.BAD_QUERY), body);
|
||||
}
|
||||
|
||||
private TemplateResponseValues doFailedSearch(String message, String querytext, Format f) {
|
||||
Map<String, Object> body = new HashMap<String, Object>();
|
||||
body.put("title", "Search for '" + querytext + "'");
|
||||
if ( StringUtils.isEmpty(message) ) {
|
||||
message = "Search failed.";
|
||||
}
|
||||
body.put("message", message);
|
||||
return new TemplateResponseValues(getTemplate(f,Result.ERROR), body);
|
||||
}
|
||||
|
||||
private TemplateResponseValues doNoHits(String querytext, Format f) {
|
||||
Map<String, Object> body = new HashMap<String, Object>();
|
||||
body.put("title", "Search for '" + querytext + "'");
|
||||
body.put("message", "No matching results.");
|
||||
return new TemplateResponseValues(getTemplate(f,Result.ERROR), body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a message to display to user for a bad search term.
|
||||
* @param query
|
||||
* @param exceptionMsg
|
||||
*/
|
||||
private String makeBadSearchMessage(String querytext, String exceptionMsg){
|
||||
String rv = "";
|
||||
try{
|
||||
//try to get the column in the search term that is causing the problems
|
||||
int coli = exceptionMsg.indexOf("column");
|
||||
if( coli == -1) return "";
|
||||
int numi = exceptionMsg.indexOf(".", coli+7);
|
||||
if( numi == -1 ) return "";
|
||||
String part = exceptionMsg.substring(coli+7,numi );
|
||||
int i = Integer.parseInt(part) - 1;
|
||||
|
||||
// figure out where to cut preview and post-view
|
||||
int errorWindow = 5;
|
||||
int pre = i - errorWindow;
|
||||
if (pre < 0)
|
||||
pre = 0;
|
||||
int post = i + errorWindow;
|
||||
if (post > querytext.length())
|
||||
post = querytext.length();
|
||||
// log.warn("pre: " + pre + " post: " + post + " term len:
|
||||
// " + term.length());
|
||||
|
||||
// get part of the search term before the error and after
|
||||
String before = querytext.substring(pre, i);
|
||||
String after = "";
|
||||
if (post > i)
|
||||
after = querytext.substring(i + 1, post);
|
||||
|
||||
rv = "The search term had an error near <span class='searchQuote'>"
|
||||
+ before + "<span class='searchError'>" + querytext.charAt(i)
|
||||
+ "</span>" + after + "</span>";
|
||||
} catch (Throwable ex) {
|
||||
return "";
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private HashSet<String> getDataPropertyBlacklist(){
|
||||
// HashSet<String>dpBlacklist = (HashSet<String>)
|
||||
// getServletContext().getAttribute(LuceneSetup.SEARCH_DATAPROPERTY_BLACKLIST);
|
||||
// return dpBlacklist;
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private HashSet<String> getObjectPropertyBlacklist(){
|
||||
// HashSet<String>opBlacklist = (HashSet<String>)
|
||||
// getServletContext().getAttribute(LuceneSetup.SEARCH_OBJECTPROPERTY_BLACKLIST);
|
||||
// return opBlacklist;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private final String defaultSearchField = "ALLTEXT";
|
||||
public static final int MAX_QUERY_LENGTH = 500;
|
||||
|
||||
|
||||
/**
|
||||
* Need to accept notification from indexer that the index has been changed.
|
||||
*/
|
||||
public void close() {
|
||||
searcher = null;
|
||||
}
|
||||
|
||||
public VitroHighlighter getHighlighter(VitroQuery q) {
|
||||
throw new Error("PagedSearchController.getHighlighter() is unimplemented");
|
||||
}
|
||||
|
||||
public VitroQueryFactory getQueryFactory() {
|
||||
throw new Error("PagedSearchController.getQueryFactory() is unimplemented");
|
||||
}
|
||||
|
||||
public List search(VitroQuery query) throws SearchException {
|
||||
throw new Error("PagedSearchController.search() is unimplemented");
|
||||
}
|
||||
|
||||
protected boolean isRequestedFormatXml(HttpServletRequest req){
|
||||
if( req != null ){
|
||||
String param = req.getParameter(XML_REQUEST_PARAM);
|
||||
if( param != null && "1".equals(param)){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected Format getFormat(HttpServletRequest req){
|
||||
if( req != null && req.getParameter("xml") != null && "1".equals(req.getParameter("xml")))
|
||||
return Format.XML;
|
||||
else
|
||||
return Format.HTML;
|
||||
}
|
||||
|
||||
protected static String getTemplate(Format format, Result result){
|
||||
if( format != null && result != null)
|
||||
return templateTable.get(format).get(result);
|
||||
else{
|
||||
log.error("getTemplate() must not have a null format or result.");
|
||||
return templateTable.get(Format.HTML).get(Result.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
protected static Map<Format,Map<Result,String>> setupTemplateTable(){
|
||||
Map<Format,Map<Result,String>> templateTable =
|
||||
new HashMap<Format,Map<Result,String>>();
|
||||
|
||||
HashMap<Result,String> resultsToTemplates = new HashMap<Result,String>();
|
||||
|
||||
//setup HTML format
|
||||
resultsToTemplates.put(Result.PAGED, "search-pagedResults.ftl");
|
||||
resultsToTemplates.put(Result.FORM, "search-form.ftl");
|
||||
resultsToTemplates.put(Result.ERROR, "search-error.ftl");
|
||||
resultsToTemplates.put(Result.BAD_QUERY, "search-badQuery.ftl");
|
||||
templateTable.put(Format.HTML, Collections.unmodifiableMap(resultsToTemplates));
|
||||
|
||||
//setup XML format
|
||||
resultsToTemplates = new HashMap<Result,String>();
|
||||
resultsToTemplates.put(Result.PAGED, "search-xmlResults.ftl");
|
||||
resultsToTemplates.put(Result.FORM, "search-xmlForm.ftl");
|
||||
resultsToTemplates.put(Result.ERROR, "search-xmlError.ftl");
|
||||
resultsToTemplates.put(Result.BAD_QUERY, "search-xmlBadQuery.ftl");
|
||||
templateTable.put(Format.XML, Collections.unmodifiableMap(resultsToTemplates));
|
||||
|
||||
return Collections.unmodifiableMap(templateTable);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package edu.cornell.mannlib.vitro.webapp.search.indexing;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
|
||||
public class AdditionalURIsForContextNodes implements AdditionalURIsToIndex {
|
||||
|
||||
private OntModel model;
|
||||
|
||||
public AdditionalURIsForContextNodes( OntModel jenaOntModel){
|
||||
this.model = jenaOntModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> findAdditionalURIsToIndex(String uri) {
|
||||
// TODO Auto-generated method stub
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package edu.cornell.mannlib.vitro.webapp.search.indexing;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface to use with IndexBuilder to find more URIs to index given a URI.
|
||||
*
|
||||
*/
|
||||
public interface AdditionalURIsToIndex {
|
||||
List<String> findAdditionalURIsToIndex(String uri);
|
||||
}
|
|
@ -47,6 +47,7 @@ public class IndexBuilder extends Thread {
|
|||
protected long reindexInterval = 1000 * 60 /* msec */ ;
|
||||
|
||||
protected int numberOfThreads = 10;
|
||||
protected List<AdditionalURIsToIndex> additionalURIsFinders;
|
||||
|
||||
public static final boolean UPDATE_DOCS = false;
|
||||
public static final boolean NEW_DOCS = true;
|
||||
|
@ -56,19 +57,20 @@ public class IndexBuilder extends Thread {
|
|||
public IndexBuilder(
|
||||
ServletContext context,
|
||||
IndexerIface indexer,
|
||||
WebappDaoFactory wdf){
|
||||
WebappDaoFactory wdf,
|
||||
List<AdditionalURIsToIndex> additionalURIsFinders){
|
||||
super("IndexBuilder");
|
||||
this.indexer = indexer;
|
||||
this.wdf = wdf;
|
||||
this.context = context;
|
||||
|
||||
this.additionalURIsFinders = additionalURIsFinders;
|
||||
this.changedUris = new HashSet<String>();
|
||||
this.start();
|
||||
}
|
||||
|
||||
protected IndexBuilder(){
|
||||
//for testing only
|
||||
this( null, null, null);
|
||||
this( null, null, null, null);
|
||||
}
|
||||
|
||||
public void setWdf(WebappDaoFactory wdf){
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.search.lucene;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.store.FSDirectory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.search.SearchException;
|
||||
|
||||
public class LuceneIndexFactory {
|
||||
|
||||
IndexSearcher searcher = null;
|
||||
String baseIndexDirName = null;
|
||||
|
||||
private static final Log log = LogFactory.getLog(LuceneIndexFactory.class.getName());
|
||||
|
||||
public static final String LUCENE_INDEX_FACTORY= "LuceneIndexFactory";
|
||||
|
||||
public LuceneIndexFactory(String baseIndexDirName){
|
||||
this.baseIndexDirName = baseIndexDirName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a lucene IndexSearch. This may return null.
|
||||
*/
|
||||
public static IndexSearcher getIndexSearcher( ServletContext context){
|
||||
return getLuceneIndexFactoryFromContext(context).innerGetIndexSearcher(context);
|
||||
}
|
||||
|
||||
protected static LuceneIndexFactory getLuceneIndexFactoryFromContext(ServletContext context){
|
||||
Object obj = context.getAttribute(LUCENE_INDEX_FACTORY);
|
||||
if( obj == null ){
|
||||
log.error("cannot get LuceneIndexFactory from context. Search is not setup correctly");
|
||||
return null;
|
||||
}
|
||||
if( ! (obj instanceof LuceneIndexFactory)){
|
||||
log.error("LuceneIndexFactory in context was not of correct type. Expected " + LuceneIndexFactory.class.getName()
|
||||
+ " found " + obj.getClass().getName() + " Search is not setup correctly");
|
||||
return null;
|
||||
}
|
||||
return (LuceneIndexFactory)obj;
|
||||
}
|
||||
|
||||
|
||||
public static LuceneIndexFactory setup(ServletContext context, String baseIndexDirName){
|
||||
LuceneIndexFactory lif = (LuceneIndexFactory)context.getAttribute(LuceneIndexFactory.LUCENE_INDEX_FACTORY);
|
||||
if( lif == null ){
|
||||
lif = new LuceneIndexFactory(baseIndexDirName);
|
||||
context.setAttribute(LuceneIndexFactory.LUCENE_INDEX_FACTORY, lif);
|
||||
}
|
||||
return lif;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be used to force the LuceneIndexFactory to return a new IndexSearcher.
|
||||
* This will force a re-opening of the search index.
|
||||
*
|
||||
* This could be useful if the index was rebult in a different directory on the file system.
|
||||
*/
|
||||
public synchronized void forceNewIndexSearcher(){
|
||||
log.debug("forcing the re-opening of the search index");
|
||||
IndexSearcher oldSearcher = searcher;
|
||||
|
||||
|
||||
searcher = null;
|
||||
}
|
||||
|
||||
protected synchronized void forceClose(){
|
||||
log.debug("forcing the closing of the search index");
|
||||
try {
|
||||
if( searcher != null )
|
||||
searcher.close();
|
||||
} catch (IOException e) {
|
||||
log.error("could not close lucene searcher: " + e.getMessage());
|
||||
}
|
||||
searcher = null;
|
||||
}
|
||||
|
||||
private synchronized IndexSearcher innerGetIndexSearcher(ServletContext context) {
|
||||
if (searcher == null ) {
|
||||
String liveDir = getLiveIndexDir( context );
|
||||
if( liveDir != null ){
|
||||
try {
|
||||
Directory fsDir = FSDirectory.getDirectory(liveDir);
|
||||
searcher = new IndexSearcher(fsDir);
|
||||
} catch (IOException e) {
|
||||
String base = getBaseIndexDir();
|
||||
log.error("could not make IndexSearcher " + e);
|
||||
log.error("It is likely that you have not made a directory for the lucene index. "
|
||||
+ "Create the directory " + base + " and set permissions/ownership so"
|
||||
+ " that the tomcat process can read and write to it.");
|
||||
}
|
||||
}else{
|
||||
log.error("Could not create IndexSearcher because index directory was null. It may be that the LucenSetup.indexDir is " +
|
||||
" not set in your deploy.properties file.");
|
||||
}
|
||||
}
|
||||
return searcher;
|
||||
}
|
||||
|
||||
protected String getBaseIndexDir(){
|
||||
if( this.baseIndexDirName == null )
|
||||
log.error("LucenIndexFactory was not setup correctly, it must have a value for baseIndexDir");
|
||||
return this.baseIndexDirName;
|
||||
}
|
||||
|
||||
protected String getLiveIndexDir(ServletContext servletContext){
|
||||
String base = getBaseIndexDir();
|
||||
if( base == null )
|
||||
return null;
|
||||
else
|
||||
return base + File.separator + "live";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,489 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.search.lucene;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
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.CorruptIndexException;
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.IndexWriter;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.store.FSDirectory;
|
||||
import org.apache.lucene.store.LockObtainFailedException;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.IndexingException;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.Searcher;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.docbuilder.Obj2DocIface;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexerIface;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author bdc34
|
||||
*
|
||||
*/
|
||||
public class LuceneIndexer implements IndexerIface {
|
||||
|
||||
private final static Log log = LogFactory.getLog(LuceneIndexer.class);
|
||||
|
||||
LinkedList<Obj2DocIface> obj2DocList = new LinkedList<Obj2DocIface>();
|
||||
String baseIndexDir = null;
|
||||
String liveIndexDir = null;
|
||||
Analyzer analyzer = null;
|
||||
List<Searcher> searchers = Collections.EMPTY_LIST;
|
||||
IndexWriter writer = null;
|
||||
boolean indexing = false;
|
||||
boolean fullRebuild = false;
|
||||
HashSet<String> urisIndexed;
|
||||
private LuceneIndexFactory luceneIndexFactory;
|
||||
private String currentOffLineDir;
|
||||
|
||||
|
||||
//JODA timedate library can use java date format strings.
|
||||
//http://java.sun.com/j2se/1.3/docs/api/java/text/SimpleDateFormat.html
|
||||
public static String MODTIME_DATE_FORMAT = "YYYYMMDDHHmmss";
|
||||
|
||||
//date format for use with entity sunrise AND sunset
|
||||
//don't let that SUNSET in the name fool you.
|
||||
//controls the time resolution of the search.
|
||||
// "YYYYMMDDHHmm" would have minute resolution
|
||||
// "YYYYMMDD" would have day resolution;
|
||||
public static String DATE_FORMAT = "YYYYMMDD";
|
||||
|
||||
/**
|
||||
* Used for the sunrise to indicate that
|
||||
* the entity has an very early sunrise
|
||||
*/
|
||||
public static String BEGINNING_OF_TIME = "00000000";
|
||||
/**
|
||||
* used for the sunset to indicate that
|
||||
* the entity has a very late sunset
|
||||
*/
|
||||
public static String END_OF_TIME = "ZZZ_END_OF_TIME";
|
||||
|
||||
private static final IndexWriter.MaxFieldLength MAX_FIELD_LENGTH =
|
||||
IndexWriter.MaxFieldLength.UNLIMITED;
|
||||
|
||||
public LuceneIndexer(String baseIndexDir, String liveIndexDir, List<Searcher> searchers, Analyzer analyzer ) throws IOException{
|
||||
this.baseIndexDir = baseIndexDir;
|
||||
this.liveIndexDir = liveIndexDir;
|
||||
this.analyzer = analyzer;
|
||||
if( searchers != null )
|
||||
this.searchers = searchers;
|
||||
|
||||
updateTo1p2();
|
||||
makeEmptyIndexIfNone();
|
||||
}
|
||||
|
||||
public synchronized void addObj2Doc(Obj2DocIface o2d) {
|
||||
if (o2d != null)
|
||||
obj2DocList.add(o2d);
|
||||
}
|
||||
|
||||
public synchronized List<Obj2DocIface> getObj2DocList() {
|
||||
return obj2DocList;
|
||||
}
|
||||
|
||||
public synchronized void addSearcher(Searcher s){
|
||||
if( searchers == null ){
|
||||
searchers = new ArrayList<Searcher>();
|
||||
}
|
||||
searchers.add( s );
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void prepareForRebuild() throws IndexingException {
|
||||
if( this.indexing )
|
||||
log.error("Only an update will be performed, must call prepareForRebuild() before startIndexing()");
|
||||
else
|
||||
this.fullRebuild = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if indexing is currently happening.
|
||||
*/
|
||||
public synchronized boolean isIndexing(){
|
||||
return indexing;
|
||||
}
|
||||
|
||||
public synchronized void startIndexing() throws IndexingException{
|
||||
while( indexing ){ //wait for indexing to end.
|
||||
log.debug("LuceneIndexer.startIndexing() waiting...");
|
||||
try{ wait(); } catch(InterruptedException ex){}
|
||||
}
|
||||
checkStartPreconditions();
|
||||
try {
|
||||
log.debug("Starting to index");
|
||||
if( this.fullRebuild ){
|
||||
String offLineDir = getOffLineBuildDir();
|
||||
this.currentOffLineDir = offLineDir;
|
||||
writer = new IndexWriter(offLineDir, analyzer, true, MAX_FIELD_LENGTH);
|
||||
writer.setSimilarity(new CustomSimilarity());
|
||||
}else{
|
||||
writer = getLiveIndexWriter(false);
|
||||
}
|
||||
indexing = true;
|
||||
urisIndexed = new HashSet<String>();
|
||||
} catch(Throwable th){
|
||||
throw new IndexingException("startIndexing() unable " +
|
||||
"to make IndexWriter:" + th.getMessage());
|
||||
}finally{
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public synchronized void endIndexing() {
|
||||
if( ! indexing ){
|
||||
notifyAll();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
urisIndexed = null;
|
||||
log.debug("ending index");
|
||||
if( writer != null )
|
||||
writer.optimize();
|
||||
|
||||
if( this.fullRebuild )
|
||||
bringRebuildOnLine();
|
||||
|
||||
//close the searcher so it will find the newly indexed documents
|
||||
for( Searcher s : searchers){
|
||||
s.close();
|
||||
}
|
||||
//this is the call that replaces Searcher.close()
|
||||
luceneIndexFactory.forceNewIndexSearcher();
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("LuceneIndexer.endIndexing() - "
|
||||
+ "unable to optimize lucene index: \n" + e);
|
||||
}finally{
|
||||
fullRebuild = false;
|
||||
closeWriter();
|
||||
indexing = false;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void setLuceneIndexFactory(LuceneIndexFactory lif) {
|
||||
luceneIndexFactory = lif;
|
||||
}
|
||||
|
||||
public synchronized Analyzer getAnalyzer(){
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indexes an object. startIndexing() must be called before this method
|
||||
* to setup the modifier.
|
||||
*
|
||||
*/
|
||||
public void index(Individual ind, boolean newDoc) throws IndexingException {
|
||||
if( ! indexing )
|
||||
throw new IndexingException("LuceneIndexer: must call " +
|
||||
"startIndexing() before index().");
|
||||
if( writer == null )
|
||||
throw new IndexingException("LuceneIndexer: cannot build index," +
|
||||
"IndexWriter is null.");
|
||||
if( ind == null )
|
||||
log.debug("Individual to index was null, ignoring.");
|
||||
try {
|
||||
if( urisIndexed.contains(ind.getURI()) ){
|
||||
log.debug("already indexed " + ind.getURI() );
|
||||
return;
|
||||
}else{
|
||||
urisIndexed.add(ind.getURI());
|
||||
log.debug("indexing " + ind.getURI());
|
||||
Iterator<Obj2DocIface> it = getObj2DocList().iterator();
|
||||
while (it.hasNext()) {
|
||||
Obj2DocIface obj2doc = (Obj2DocIface) it.next();
|
||||
if (obj2doc.canTranslate(ind)) {
|
||||
Document d = (Document) obj2doc.translate(ind);
|
||||
if( d != null){
|
||||
if( !newDoc ){
|
||||
writer.updateDocument((Term)obj2doc.getIndexId(ind), d);
|
||||
log.debug("updated " + ind.getName() + " " + ind.getURI());
|
||||
}else{
|
||||
writer.addDocument(d);
|
||||
log.debug("added " + ind.getName() + " " + ind.getURI());
|
||||
}
|
||||
}else{
|
||||
log.debug("removing from index " + ind.getURI());
|
||||
writer.deleteDocuments((Term)obj2doc.getIndexId(ind));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new IndexingException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a single object from index. <code>obj</code> is translated
|
||||
* using the obj2DocList.
|
||||
*/
|
||||
public void removeFromIndex(Individual ind) throws IndexingException {
|
||||
if( writer == null )
|
||||
throw new IndexingException("LuceneIndexer: cannot delete from " +
|
||||
"index, IndexWriter is null.");
|
||||
try {
|
||||
Iterator<Obj2DocIface> it = getObj2DocList().iterator();
|
||||
while (it.hasNext()) {
|
||||
Obj2DocIface obj2doc = (Obj2DocIface) it.next();
|
||||
if (obj2doc.canTranslate(ind)) {
|
||||
writer.deleteDocuments((Term)obj2doc.getIndexId(ind));
|
||||
log.debug("deleted " + ind.getName() + " " + ind.getURI());
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new IndexingException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will make a new directory and create a lucene index in it.
|
||||
*/
|
||||
private synchronized void makeNewIndex() throws IOException{
|
||||
|
||||
}
|
||||
|
||||
private synchronized void closeWriter(){
|
||||
if( writer != null )try{
|
||||
writer.commit();
|
||||
writer.close();
|
||||
}catch(IOException ioe){
|
||||
log.error("LuceneIndexer.endIndexing() unable " +
|
||||
"to close indexModifier " + ioe.getMessage());
|
||||
}catch(java.lang.IllegalStateException ise){
|
||||
//this is thrown when trying to close a closed index.
|
||||
}catch(Throwable t){//must not jump away from here
|
||||
log.error("in LuceneIndexer.closeModifier(): \n"+t);
|
||||
}
|
||||
writer = null;
|
||||
}
|
||||
|
||||
private synchronized void bringRebuildOnLine() {
|
||||
closeWriter();
|
||||
File offLineDir = new File(currentOffLineDir);
|
||||
File liveDir = new File(liveIndexDir);
|
||||
|
||||
log.debug("deleting old live directory " + liveDir.getAbsolutePath());
|
||||
boolean deleted = deleteDir(liveDir);
|
||||
if (! deleted ){
|
||||
log.debug("failed to delete live index directory "
|
||||
+ liveDir.getAbsolutePath());
|
||||
log.debug("Attempting to close searcher and delete live directory");
|
||||
this.luceneIndexFactory.forceClose();
|
||||
boolean secondDeleted = deleteDir(liveDir);
|
||||
if( ! secondDeleted ){
|
||||
log.error("Search index is out of date and cannot be replaced " +
|
||||
"because could not remove lucene index from directory"
|
||||
+ liveDir.getAbsolutePath());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("moving " + offLineDir.getAbsolutePath() + " to "
|
||||
+ liveDir.getAbsolutePath());
|
||||
|
||||
boolean success = offLineDir.renameTo( liveDir );
|
||||
if( ! success ){
|
||||
log.error("could not move off line index at "
|
||||
+ offLineDir.getAbsolutePath() + " to live index directory "
|
||||
+ liveDir.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
|
||||
File oldWorkignDir = new File(currentOffLineDir);
|
||||
if( oldWorkignDir.exists() )
|
||||
log.debug("old working directory should have been removed " +
|
||||
"but still exits at " + oldWorkignDir.getAbsolutePath());
|
||||
|
||||
currentOffLineDir = null;
|
||||
}
|
||||
|
||||
private synchronized String getOffLineBuildDir(){
|
||||
File baseDir = new File(baseIndexDir);
|
||||
baseDir.mkdirs();
|
||||
File tmpDir = new File( baseIndexDir + File.separator + "tmp" );
|
||||
tmpDir.mkdir();
|
||||
File offLineBuildDir = new File( baseIndexDir + File.separator + "tmp" + File.separator + "offLineRebuild" + System.currentTimeMillis());
|
||||
offLineBuildDir.mkdir();
|
||||
String dirName = offLineBuildDir.getAbsolutePath();
|
||||
if( ! dirName.endsWith(File.separator) )
|
||||
dirName = dirName + File.separator;
|
||||
return dirName;
|
||||
}
|
||||
|
||||
public long getModified() {
|
||||
long rv = 0;
|
||||
try{
|
||||
FSDirectory d = FSDirectory.getDirectory(liveIndexDir);
|
||||
rv = IndexReader.lastModified(d);
|
||||
}catch(IOException ex){
|
||||
log.error("LuceneIndexer.getModified() - could not get modified time "+ ex);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** Deletes all files and subdirectories under dir.
|
||||
* Returns true if all deletions were successful.
|
||||
* If a deletion fails, the method stops attempting to delete
|
||||
* and returns false. */
|
||||
private static boolean deleteDir(File dir) {
|
||||
if (dir.isDirectory()) {
|
||||
String[] children = dir.list();
|
||||
for (int i=0; i<children.length; i++) {
|
||||
File child = new File(dir, children[i]);
|
||||
boolean childDeleted = deleteDir(child);
|
||||
if (!childDeleted) {
|
||||
log.debug("failed to delete " + child.getAbsolutePath());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// The directory is now empty so delete it
|
||||
boolean deleted = dir.delete();
|
||||
if (!deleted) {
|
||||
log.debug("failed to delete " + dir.getAbsolutePath());
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
||||
private void checkStartPreconditions() {
|
||||
if( this.writer != null )
|
||||
log.error("it is expected that the writer would " +
|
||||
"be null but it isn't");
|
||||
if( this.currentOffLineDir != null)
|
||||
log.error("it is expected that the current" +
|
||||
"OffLineDir would be null but it is " + currentOffLineDir);
|
||||
if( indexing )
|
||||
log.error("indexing should not be set to true just yet");
|
||||
}
|
||||
|
||||
private IndexWriter getLiveIndexWriter(boolean createNew) throws CorruptIndexException, LockObtainFailedException, IOException{
|
||||
return new IndexWriter(this.liveIndexDir, analyzer, createNew, MAX_FIELD_LENGTH);
|
||||
}
|
||||
|
||||
private synchronized void makeEmptyIndexIfNone() throws IOException {
|
||||
if( !liveIndexExists() ){
|
||||
log.debug("Making new index dir and initially empty lucene index at " + liveIndexDir);
|
||||
closeWriter();
|
||||
makeIndexDirs();
|
||||
writer = getLiveIndexWriter(true);
|
||||
closeWriter();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void makeIndexDirs() throws IOException{
|
||||
File baseDir = new File(baseIndexDir);
|
||||
if( ! baseDir.exists())
|
||||
baseDir.mkdirs();
|
||||
|
||||
File dir = new File(liveIndexDir);
|
||||
if( ! dir.exists() )
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
private boolean liveIndexExists(){
|
||||
return indexExistsAt(liveIndexDir);
|
||||
}
|
||||
|
||||
private boolean indexExistsAt(String dirName){
|
||||
Directory fsDir = null;
|
||||
try{
|
||||
fsDir = FSDirectory.getDirectory(dirName);
|
||||
return IndexReader.indexExists(fsDir);
|
||||
}catch(Exception ex){
|
||||
return false;
|
||||
}finally{
|
||||
try{
|
||||
if( fsDir != null)
|
||||
fsDir.close();
|
||||
}catch(Exception ex){}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* In needed, create new 1.2 style index directories and copy old index to new dirs.
|
||||
*/
|
||||
private synchronized void updateTo1p2() throws IOException {
|
||||
//check if live index directory exists, don't check for a lucene index.
|
||||
File liveDirF = new File(this.liveIndexDir);
|
||||
if( ! liveDirF.exists() && indexExistsAt(baseIndexDir)){
|
||||
log.info("Updating to vitro 1.2 search index directory structure");
|
||||
makeIndexDirs();
|
||||
File live = new File(liveIndexDir);
|
||||
|
||||
//copy existing index to live index directory
|
||||
File baseDir = new File(baseIndexDir);
|
||||
for( File file : baseDir.listFiles()){
|
||||
if( ! file.isDirectory() && ! live.getName().equals(file.getName() ) ){
|
||||
FileUtils.copyFile(file, new File(liveIndexDir+File.separator+file.getName()));
|
||||
boolean success = file.delete();
|
||||
if( ! success )
|
||||
log.error("could not delete "+ baseIndexDir + file.getName());
|
||||
}
|
||||
}
|
||||
log.info("Done updating to vitro 1.2 search index directory structure.");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isIndexEmpty() throws CorruptIndexException, IOException{
|
||||
IndexWriter writer = null;
|
||||
try{
|
||||
writer = getLiveIndexWriter(false);
|
||||
return writer.numDocs() == 0;
|
||||
}finally{
|
||||
if (writer != null) writer.close();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isIndexCorroupt(){
|
||||
//if it is clear it out but don't rebuild.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void abortIndexingAndCleanUp() {
|
||||
if( ! indexing )
|
||||
log.error("abortIndexingAndCleanUp() should only be called if LuceneIndexer is indexing.");
|
||||
else if( ! fullRebuild )
|
||||
log.error("abortIndexingAndCleanUp() should only be called if LuceneIndexer to end an aborted full index rebuild");
|
||||
else{
|
||||
closeWriter();
|
||||
File offLineDir = new File(currentOffLineDir);
|
||||
boolean deleted = deleteDir(offLineDir);
|
||||
//log might be null if system is shutting down.
|
||||
if( ! deleted ){
|
||||
System.out.println("Could not clean up temp indexing dir " + currentOffLineDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void index(Individual ind) throws IndexingException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromIndex(String uri) throws IndexingException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
|
@ -1,285 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.search.lucene;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
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.search.CachingWrapperFilter;
|
||||
import org.apache.lucene.search.HitCollector;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.store.FSDirectory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.search.SearchException;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.Searcher;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.VitroHighlighter;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQuery;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQueryFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.docbuilder.Obj2DocIface;
|
||||
|
||||
//
|
||||
//NOTES ABOUT SEARCHING AND INDEXING AT THE SAME TIME
|
||||
//from the lucene cvs commit logs:
|
||||
// cvs commit: jakarta-lucene/src/test/org/apache/lucene
|
||||
// ThreadSafetyTest.java
|
||||
// Thu, 27 Sep 2001 09:01:08 -0700
|
||||
//
|
||||
// cutting 01/09/27 09:27:02
|
||||
//
|
||||
// Modified: src/java/org/apache/lucene/index IndexReader.java
|
||||
// IndexWriter.java SegmentReader.java
|
||||
// src/java/org/apache/lucene/store Directory.java
|
||||
// FSDirectory.java RAMDirectory.java
|
||||
// src/test/org/apache/lucene ThreadSafetyTest.java
|
||||
// Added: src/java/org/apache/lucene/store Lock.java
|
||||
// Log:
|
||||
// Added index lock files. Indexing and search are now not just
|
||||
// thread
|
||||
// safe, but also "process safe": multiple processes may may now
|
||||
// search
|
||||
// an index while it is being updated from another process.
|
||||
//
|
||||
// Two lock files are used in an index. One is "commit.lock". This
|
||||
// is
|
||||
// used to synchronize commits [IndexWriter.close()] with opens
|
||||
// [IndexReader.open()]. Since these actions are short-lived,
|
||||
// attempts
|
||||
// to obtain this lock will block for up to ten seconds, which
|
||||
// should be
|
||||
// plenty of time, before an exception is thrown.
|
||||
//
|
||||
// The second lock file is "write.lock". This is used to enforce the
|
||||
// restriction that only one process should be adding documents to
|
||||
// an
|
||||
// index at a time. This is created when an IndexWriter is
|
||||
// constructed
|
||||
// and removed when it is closed. If index writing is aborted then
|
||||
// this
|
||||
// file must be manually removed. Attempts to index from another
|
||||
// process
|
||||
// will immediately throw an exception.
|
||||
// so a check if indexing is running, is not needed
|
||||
// try {
|
||||
// IndexBuilder builder =
|
||||
// (IndexBuilder)getServletContext().getAttribute(IndexBuilder.class.getName());
|
||||
// if( builder.isIndexing() ){
|
||||
// //System.out.println("location 1");
|
||||
// doIndexingRunningErrorPage(request, response);
|
||||
// return;
|
||||
// }
|
||||
// } catch (Throwable e) {
|
||||
// System.out.println("here at the first chunk of code");
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
public class LuceneSearcher implements Searcher {
|
||||
private VitroQueryFactory QFactory = null;
|
||||
protected String indexDir = "index directory has not be set";
|
||||
private IndexSearcher indexSearcher = null;
|
||||
private static final Log log = LogFactory.getLog(LuceneSearcher.class.getName());
|
||||
/**
|
||||
* Caching Filter for default time window. It is in this
|
||||
* class so that when the searcher gets closed and reopened
|
||||
* this cache can be thrown out and a new cache started.
|
||||
*/
|
||||
private CachingWrapperFilter timeWindowCachingFilter = null;
|
||||
private long timeWinFilterBorn = 0L;
|
||||
|
||||
//Obj2Docs are used to convert hits to objects
|
||||
LinkedList obj2DocList = new LinkedList();
|
||||
|
||||
public LuceneSearcher(LuceneQueryFactory fact, String indexDir){
|
||||
this.QFactory = fact;
|
||||
this.indexDir = indexDir;
|
||||
this.indexSearcher = getIndexSearcher();
|
||||
}
|
||||
|
||||
public VitroQueryFactory getQueryFactory() {
|
||||
return QFactory;
|
||||
}
|
||||
|
||||
public void addObj2Doc(Obj2DocIface o2d) {
|
||||
if (o2d != null)
|
||||
obj2DocList.add(o2d);
|
||||
}
|
||||
|
||||
public List search(VitroQuery query) throws SearchException {
|
||||
if( ! (query instanceof LuceneQuery ) ){
|
||||
String queryObjMismatchMsg = "The LuceneSearcher needs a LuceneQuery " +
|
||||
"object when performing a search.\n"
|
||||
+"This should have been setup by the LuceneSetup when the servlet " +
|
||||
"context started.\n"
|
||||
+"The code in LuceneSetup can be run using a listener element in the " +
|
||||
"web.xml set the comments for LuceneSetup.";
|
||||
throw new SearchException( queryObjMismatchMsg );
|
||||
}
|
||||
|
||||
Query luceneQuery = (Query)query.getQuery();
|
||||
|
||||
//use the caching default time filter
|
||||
//bdc34 as of 2009-01-30, getting rid of time windows
|
||||
// if( ((LuceneQuery)query).defaultTimeWindow )
|
||||
// luceneQuery = new FilteredQuery(luceneQuery,
|
||||
// getTimeWindowCachingFilter());
|
||||
|
||||
List results = null;
|
||||
//Hits hits = null;
|
||||
//HitsCollector collector = new HitsCollector();
|
||||
|
||||
|
||||
// final BitSet bits = new BitSet(indexSearcher.maxDoc());
|
||||
// searcher.search(query, new HitCollector() {
|
||||
// public void collect(int doc, float score) {
|
||||
// bits.set(doc);
|
||||
// }
|
||||
// });
|
||||
|
||||
/*
|
||||
TopDocCollector collector = new TopDocCollector(hitsPerPage);
|
||||
* searcher.search(query, collector);
|
||||
* ScoreDoc[] hits = collector.topDocs().scoreDocs;
|
||||
* for (int i = 0; i < hits.length; i++) {
|
||||
* int docId = hits[i].doc;
|
||||
* Document d = searcher.doc(docId);
|
||||
*/
|
||||
|
||||
|
||||
IndexSearcher is = getIndexSearcher();
|
||||
if( is == null )
|
||||
throw new SearchException("Unable to find a Search Index");
|
||||
|
||||
try{
|
||||
final BitSet bits = new BitSet(is.maxDoc());
|
||||
is.search(luceneQuery,(HitCollector)new HitCollector() {
|
||||
public void collect(int doc, float score) {
|
||||
bits.set(doc);
|
||||
}
|
||||
});
|
||||
results = hits2objs(is, bits);
|
||||
}catch(Throwable t){
|
||||
String msg = "There was an error executing your search: " + t;
|
||||
log.error(msg);
|
||||
t.printStackTrace();
|
||||
throw new SearchException( msg );
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is going to go through the list of hits and make objects for each hit.
|
||||
* After making the object, it attempts to invoke the methods setId and setName.
|
||||
* @param hits
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws SearchException
|
||||
*/
|
||||
private List hits2objs(IndexSearcher index, BitSet hits)throws IOException, SearchException{
|
||||
if( hits == null ) throw new SearchException("There was no hits object");
|
||||
List objs = new ArrayList(hits.cardinality());
|
||||
for (int i = 0; i < hits.length(); i++) {
|
||||
if( hits.get(i) ){
|
||||
Document doc = index.doc(i);
|
||||
Object obj = null;
|
||||
if( doc != null ){
|
||||
obj = tryObj2Docs( doc );
|
||||
/*log.debug(obj.getClass().getName() + doc.get("ID")
|
||||
+ " with a score of " + hits.score(i));*/
|
||||
if( obj != null )
|
||||
objs.add(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
return objs;
|
||||
}
|
||||
|
||||
/**
|
||||
* go through all the obj2doc translators and attemp to untranslate the doc
|
||||
* into a vitro entity. If there are no translators that work then just return the
|
||||
* hit Document.
|
||||
* @param hit
|
||||
* @return
|
||||
*/
|
||||
private Object tryObj2Docs(Document hit){
|
||||
Object obj = hit;
|
||||
Iterator it = obj2DocList.iterator();
|
||||
while(it.hasNext()){
|
||||
Obj2DocIface trans = (Obj2DocIface) it.next();
|
||||
if( trans.canUnTranslate(hit) )
|
||||
obj = trans.unTranslate(hit);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
protected synchronized IndexSearcher getIndexSearcher() {
|
||||
if( indexSearcher == null ){
|
||||
try {
|
||||
Directory fsDir = FSDirectory.getDirectory(indexDir);
|
||||
indexSearcher = new IndexSearcher(fsDir);
|
||||
timeWindowCachingFilter = null;
|
||||
} catch (IOException e) {
|
||||
log.error("LuceneSearcher: could not make indexSearcher "+e);
|
||||
log.error("It is likely that you have not made a directory for the lucene index. "+
|
||||
"Create the directory indicated in the error and set permissions/ownership so"+
|
||||
" that the tomcat server can read/write to it.");
|
||||
//The index directory is created by LuceneIndexer.makeNewIndex()
|
||||
}
|
||||
}
|
||||
return indexSearcher;
|
||||
}
|
||||
|
||||
|
||||
public synchronized void close() {
|
||||
if( indexSearcher != null ){
|
||||
try{
|
||||
indexSearcher.close();
|
||||
}catch(Throwable t){}
|
||||
indexSearcher = null;
|
||||
}
|
||||
timeWindowCachingFilter = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* We need access to the index to make a highligher because
|
||||
* we need to 'rewrite' the query. That takes any wild cards
|
||||
* and replaces them will all terms that are found in the index.
|
||||
*/
|
||||
/* public VitroHighlighter getHighlighter(VitroQuery queryIn){
|
||||
if( ! (queryIn instanceof LuceneQuery) ){
|
||||
log.error("LuceneSearcher expects to get a LuceneQuery");
|
||||
throw new Error("LuceneSearcher expects to get a LuceneQuery");
|
||||
}
|
||||
|
||||
LuceneHighlighter highlighter = null;
|
||||
try {
|
||||
LuceneQuery lucQuery = (LuceneQuery) queryIn;
|
||||
Analyzer analyzer = lucQuery.getAnalyzer();
|
||||
Query query = (Query)lucQuery.getQuery();
|
||||
if( getIndexSearcher().getIndexReader() != null ){
|
||||
query = query.rewrite( getIndexSearcher().getIndexReader() );
|
||||
}
|
||||
highlighter = new LuceneHighlighter( query, analyzer );
|
||||
} catch (SearchException e) {
|
||||
log.error(e, e);
|
||||
} catch (IOException e) {
|
||||
log.error(e, e);
|
||||
}
|
||||
return (VitroHighlighter)highlighter;
|
||||
}*/
|
||||
|
||||
}
|
|
@ -1,274 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.search.lucene;
|
||||
|
||||
import static edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc.VitroLuceneTermNames.ALLTEXT;
|
||||
import static edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc.VitroLuceneTermNames.ALLTEXTUNSTEMMED;
|
||||
import static edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc.VitroLuceneTermNames.CLASSLOCALNAME;
|
||||
import static edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc.VitroLuceneTermNames.CLASSLOCALNAMELOWERCASE;
|
||||
import static edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc.VitroLuceneTermNames.CONTEXTNODE;
|
||||
import static edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc.VitroLuceneTermNames.NAME_STEMMED;
|
||||
import static edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc.VitroLuceneTermNames.NAME_UNSTEMMED;
|
||||
import static edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc.VitroLuceneTermNames.RDFTYPE;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.lucene.analysis.Analyzer;
|
||||
import org.apache.lucene.analysis.PerFieldAnalyzerWrapper;
|
||||
import org.apache.lucene.analysis.standard.StandardAnalyzer;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.util.Version;
|
||||
|
||||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.filtering.WebappDaoFactoryFiltering;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilterUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelContext;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.SearchReindexingListener;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.IndividualProhibitedFromSearchImpl;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.ObjectSourceIface;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.ProhibitedFromSearch;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup;
|
||||
|
||||
/**
|
||||
* Setup objects for lucene searching and indexing.
|
||||
*
|
||||
* The indexing and search objects, IndexBuilder and Searcher are found by the
|
||||
* controllers IndexController and SearchController through the servletContext.
|
||||
* This object will have the method contextInitialized() called when the tomcat
|
||||
* server starts this webapp.
|
||||
*
|
||||
* The contextInitialized() will try to find the lucene index directory,
|
||||
* make a LueceneIndexer and a LuceneSearcher. The LuceneIndexer will
|
||||
* also get a list of Obj2Doc objects so it can translate object to lucene docs.
|
||||
*
|
||||
* To execute this at context creation put this in web.xml:
|
||||
<listener>
|
||||
<listener-class>
|
||||
edu.cornell.mannlib.vitro.search.setup.LuceneSetup
|
||||
</listener-class>
|
||||
</listener>
|
||||
|
||||
* @author bdc34
|
||||
*
|
||||
*/
|
||||
public class LuceneSetup implements javax.servlet.ServletContextListener {
|
||||
private static final Log log = LogFactory.getLog(LuceneSetup.class.getName());
|
||||
|
||||
private static final String PROPERTY_VITRO_HOME = "vitro.home.directory";
|
||||
private static final String LUCENE_SUBDIRECTORY_NAME = "luceneIndex";
|
||||
|
||||
/**
|
||||
* Gets run to set up DataSource when the webapp servlet context gets
|
||||
* created.
|
||||
*/
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
|
||||
if (AbortStartup.isStartupAborted(sce.getServletContext())) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ServletContext context = sce.getServletContext();
|
||||
|
||||
String baseIndexDir = getBaseIndexDirName(context);
|
||||
log.info("Setting up Lucene index. Base directory of lucene index: " + baseIndexDir);
|
||||
|
||||
setBoolMax();
|
||||
|
||||
// these should really be set as annotation properties.
|
||||
HashSet<String> dataPropertyBlacklist = new HashSet<String>();
|
||||
context.setAttribute(SEARCH_DATAPROPERTY_BLACKLIST, dataPropertyBlacklist);
|
||||
HashSet<String> objectPropertyBlacklist = new HashSet<String>();
|
||||
objectPropertyBlacklist.add("http://www.w3.org/2002/07/owl#differentFrom");
|
||||
context.setAttribute(SEARCH_OBJECTPROPERTY_BLACKLIST, objectPropertyBlacklist);
|
||||
|
||||
//This is where to get a LucenIndex from. The indexer will
|
||||
//need to reference this to notify it of updates to the index
|
||||
context.setAttribute(BASE_INDEX_DIR, baseIndexDir);
|
||||
LuceneIndexFactory lif = LuceneIndexFactory.setup(context, baseIndexDir);
|
||||
String liveIndexDir = lif.getLiveIndexDir(context);
|
||||
|
||||
// Here we want to put the LuceneIndex object into the application scope.
|
||||
// This will attempt to create a new directory and empty index if there is none.
|
||||
LuceneIndexer indexer = new LuceneIndexer(
|
||||
getBaseIndexDirName(context), liveIndexDir, null,
|
||||
getAnalyzer());
|
||||
context.setAttribute(ANALYZER, getAnalyzer());
|
||||
|
||||
//bk392 adding another argument to Entity2LuceneDoc
|
||||
// that takes care of sparql queries for context nodes.
|
||||
|
||||
OntModel displayOntModel = (OntModel) sce.getServletContext().getAttribute("displayOntModel");
|
||||
Entity2LuceneDoc translator = new Entity2LuceneDoc(
|
||||
new ProhibitedFromSearch(DisplayVocabulary.PRIMARY_LUCENE_INDEX_URI, displayOntModel),
|
||||
new IndividualProhibitedFromSearchImpl(context)
|
||||
|
||||
);
|
||||
indexer.addObj2Doc(translator);
|
||||
|
||||
context.setAttribute(LuceneIndexer.class.getName(), indexer);
|
||||
indexer.setLuceneIndexFactory(lif);
|
||||
|
||||
if( indexer.isIndexCorroupt() ){
|
||||
log.info("lucene index is corrupt, requesting rebuild");
|
||||
}
|
||||
if( indexer.isIndexEmpty() ){
|
||||
log.info("lucene index is empty, requesting rebuild");
|
||||
sce.getServletContext().setAttribute(INDEX_REBUILD_REQUESTED_AT_STARTUP, Boolean.TRUE);
|
||||
}
|
||||
|
||||
// This is where the builder gets the list of places to try to
|
||||
// get objects to index. It is filtered so that non-public text
|
||||
// does not get into the search index.
|
||||
WebappDaoFactory wadf = (WebappDaoFactory) context.getAttribute("webappDaoFactory");
|
||||
VitroFilters vf = VitroFilterUtils.getPublicFilter(context);
|
||||
wadf = new WebappDaoFactoryFiltering(wadf, vf);
|
||||
|
||||
List<ObjectSourceIface> sources = new ArrayList<ObjectSourceIface>();
|
||||
sources.add(wadf.getIndividualDao());
|
||||
|
||||
//IndexBuilder builder = new IndexBuilder(context, indexer, sources);
|
||||
IndexBuilder builder = new IndexBuilder(context, indexer, wadf);
|
||||
|
||||
// here we add the IndexBuilder with the LuceneIndexer
|
||||
// to the servlet context so we can access it later in the webapp.
|
||||
context.setAttribute(IndexBuilder.class.getName(), builder);
|
||||
|
||||
// set up listeners so search index builder is notified of changes to model
|
||||
ServletContext ctx = sce.getServletContext();
|
||||
SearchReindexingListener srl = new SearchReindexingListener(builder);
|
||||
ModelContext.registerListenerForChanges(ctx, srl);
|
||||
|
||||
if( sce.getServletContext().getAttribute(INDEX_REBUILD_REQUESTED_AT_STARTUP) instanceof Boolean &&
|
||||
(Boolean)sce.getServletContext().getAttribute(INDEX_REBUILD_REQUESTED_AT_STARTUP) ){
|
||||
log.info("Rebuild of lucene index required before startup.");
|
||||
builder.doIndexRebuild();
|
||||
int n = 0;
|
||||
while( builder.isReindexRequested() || builder.isIndexing() ){
|
||||
n++;
|
||||
if( n % 20 == 0 ) //output message every 10 sec.
|
||||
log.info("Still rebuilding lucene index");
|
||||
Thread.sleep(500);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Setup of Lucene index completed.");
|
||||
} catch (Throwable t) {
|
||||
AbortStartup.abortStartup(sce.getServletContext());
|
||||
log.error("***** Error setting up Lucene index *****", t);
|
||||
throw new RuntimeException("Startup of vitro application was prevented by errors in the lucene configuration");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets run when the webApp Context gets destroyed.
|
||||
*/
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
log.debug("**** Running " + this.getClass().getName() + ".contextDestroyed()");
|
||||
IndexBuilder builder = (IndexBuilder) sce.getServletContext().getAttribute(IndexBuilder.class.getName());
|
||||
if( builder != null){
|
||||
builder.stopIndexingThread();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In wild card searches the query is first broken into many boolean
|
||||
* searches OR'ed together. So if there is a query that would match a lot of
|
||||
* records we need a high max boolean limit for the lucene search.
|
||||
*
|
||||
* This sets some static method in the lucene library to achieve this.
|
||||
*/
|
||||
public static void setBoolMax() {
|
||||
BooleanQuery.setMaxClauseCount(16384);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the directory to store the lucene index in. The
|
||||
* {@link ConfigurationProperties} should have a property named
|
||||
* 'vitro.home.directory' which has the parent directory of the directory to
|
||||
* store the lucene index for this clone in. If the property is not found,
|
||||
* an exception will be thrown.
|
||||
*
|
||||
* @return a string that is the directory to store the lucene index.
|
||||
* @throws IllegalStateException
|
||||
* if the property is not found, or if the home directory does
|
||||
* not exist.
|
||||
* @throws IOException
|
||||
* if the directory doesn't exist and we fail to create it.
|
||||
*/
|
||||
private String getBaseIndexDirName(ServletContext ctx) throws IOException {
|
||||
String homeDirName = ConfigurationProperties.getBean(ctx).getProperty(
|
||||
PROPERTY_VITRO_HOME);
|
||||
if (homeDirName == null) {
|
||||
throw new IllegalStateException(PROPERTY_VITRO_HOME
|
||||
+ " not found in properties file.");
|
||||
}
|
||||
|
||||
File homeDir = new File(homeDirName);
|
||||
if (!homeDir.exists()) {
|
||||
throw new IllegalStateException("Vitro home directory '"
|
||||
+ homeDir.getAbsolutePath() + "' does not exist.");
|
||||
}
|
||||
|
||||
File luceneDir = new File(homeDir, LUCENE_SUBDIRECTORY_NAME);
|
||||
if (!luceneDir.exists()) {
|
||||
boolean created = luceneDir.mkdir();
|
||||
if (!created) {
|
||||
throw new IOException(
|
||||
"Unable to create Lucene index directory at '"
|
||||
+ luceneDir + "'");
|
||||
}
|
||||
}
|
||||
|
||||
return luceneDir.getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the analyzer that will be used when building the indexing
|
||||
* and when analyzing the incoming search terms.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Analyzer getAnalyzer() {
|
||||
|
||||
PerFieldAnalyzerWrapper analyzer = new PerFieldAnalyzerWrapper( new StandardAnalyzer(Version.LUCENE_29));
|
||||
|
||||
analyzer.addAnalyzer(ALLTEXT, new HtmlLowerStopStemAnalyzer());
|
||||
analyzer.addAnalyzer(ALLTEXTUNSTEMMED, new HtmlLowerStopAnalyzer());
|
||||
analyzer.addAnalyzer(NAME_UNSTEMMED, new HtmlLowerStopAnalyzer());
|
||||
analyzer.addAnalyzer(NAME_STEMMED, new HtmlLowerStopStemAnalyzer());
|
||||
analyzer.addAnalyzer(RDFTYPE, new StandardAnalyzer(Version.LUCENE_29));
|
||||
analyzer.addAnalyzer(CONTEXTNODE, new StandardAnalyzer(Version.LUCENE_29));
|
||||
analyzer.addAnalyzer(CLASSLOCALNAME, new HtmlLowerStopAnalyzer());
|
||||
analyzer.addAnalyzer(CLASSLOCALNAMELOWERCASE, new HtmlLowerStopAnalyzer());
|
||||
|
||||
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
public static final String INDEX_REBUILD_REQUESTED_AT_STARTUP = "LuceneSetup.indexRebuildRequestedAtStarup";
|
||||
public static final String ANALYZER= "lucene.analyzer";
|
||||
public static final String BASE_INDEX_DIR = "lucene.indexDir";
|
||||
public static final String SEARCH_DATAPROPERTY_BLACKLIST =
|
||||
"search.dataproperty.blacklist";
|
||||
public static final String SEARCH_OBJECTPROPERTY_BLACKLIST =
|
||||
"search.objectproperty.blacklist";
|
||||
|
||||
}
|
|
@ -1,205 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.search.lucene;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.lucene.analysis.Analyzer;
|
||||
import org.apache.lucene.analysis.cjk.CJKAnalyzer;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
|
||||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.filtering.WebappDaoFactoryFiltering;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilterUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelContext;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.SearchReindexingListener;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.IndividualProhibitedFromSearchImpl;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.ProhibitedFromSearch;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder;
|
||||
|
||||
/**
|
||||
* Setup objects for lucene searching and indexing.
|
||||
*
|
||||
* The indexing and search objects, IndexBuilder and Searcher are found by the
|
||||
* controllers IndexController and SearchController through the servletContext.
|
||||
* This object will have the method contextInitialized() called when the tomcat
|
||||
* server starts this webapp.
|
||||
*
|
||||
* The contextInitialized() will try to find the lucene index directory,
|
||||
* make a LueceneIndexer and a LuceneSearcher. The LuceneIndexer will
|
||||
* also get a list of Obj2Doc objects so it can translate object to lucene docs.
|
||||
*
|
||||
* To execute this at context creation put this in web.xml:
|
||||
<listener>
|
||||
<listener-class>
|
||||
edu.cornell.mannlib.vitro.search.setup.LuceneSetup
|
||||
</listener-class>
|
||||
</listener>
|
||||
|
||||
* @author bdc34
|
||||
*
|
||||
*/
|
||||
public class LuceneSetupCJK implements javax.servlet.ServletContextListener {
|
||||
private static String indexDir = null;
|
||||
private static final Log log = LogFactory.getLog(LuceneSetupCJK.class.getName());
|
||||
private static final String PROPERTY_VITRO_HOME = "vitro.home.directory";
|
||||
private static final String LUCENE_SUBDIRECTORY_NAME = "luceneIndex";
|
||||
|
||||
/**
|
||||
* Gets run to set up DataSource when the webapp servlet context gets created.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
ServletContext context = sce.getServletContext();
|
||||
log.info("**** Running "+this.getClass().getName()+".contextInitialized()");
|
||||
try{
|
||||
indexDir = getIndexDirName(sce);
|
||||
log.info("Lucene indexDir: " + indexDir);
|
||||
|
||||
setBoolMax();
|
||||
|
||||
HashSet dataPropertyBlacklist = new HashSet<String>();
|
||||
context.setAttribute(LuceneSetup.SEARCH_DATAPROPERTY_BLACKLIST, dataPropertyBlacklist);
|
||||
|
||||
HashSet objectPropertyBlacklist = new HashSet<String>();
|
||||
objectPropertyBlacklist.add("http://www.w3.org/2002/07/owl#differentFrom");
|
||||
context.setAttribute(LuceneSetup.SEARCH_OBJECTPROPERTY_BLACKLIST, objectPropertyBlacklist);
|
||||
|
||||
//This is where to get a LucenIndex from. The indexer will
|
||||
//need to reference this to notify it of updates to the index
|
||||
LuceneIndexFactory lif = LuceneIndexFactory.setup(context, indexDir);
|
||||
String liveIndexDir = lif.getLiveIndexDir(context);
|
||||
|
||||
//here we want to put the LuceneIndex object into the application scope
|
||||
LuceneIndexer indexer = new LuceneIndexer(indexDir, liveIndexDir, null, getAnalyzer());
|
||||
context.setAttribute(LuceneSetup.ANALYZER, getAnalyzer());
|
||||
|
||||
OntModel displayOntModel = (OntModel) sce.getServletContext().getAttribute("displayOntModel");
|
||||
Entity2LuceneDoc translator = new Entity2LuceneDoc(
|
||||
new ProhibitedFromSearch(DisplayVocabulary.PRIMARY_LUCENE_INDEX_URI, displayOntModel),
|
||||
new IndividualProhibitedFromSearchImpl(context)
|
||||
);
|
||||
indexer.addObj2Doc(translator);
|
||||
|
||||
indexer.setLuceneIndexFactory(lif);
|
||||
|
||||
//This is where the builder gets the list of places to try to
|
||||
//get objects to index. It is filtered so that non-public text
|
||||
//does not get into the search index.
|
||||
WebappDaoFactory wadf =
|
||||
(WebappDaoFactory) context.getAttribute("webappDaoFactory");
|
||||
VitroFilters vf = VitroFilterUtils.getPublicFilter(context);
|
||||
wadf = new WebappDaoFactoryFiltering(wadf,vf);
|
||||
|
||||
List sources = new ArrayList();
|
||||
sources.add(wadf.getIndividualDao());
|
||||
|
||||
//IndexBuilder builder = new IndexBuilder(context,indexer,sources);
|
||||
IndexBuilder builder = new IndexBuilder(context, indexer, wadf);
|
||||
|
||||
// here we add the IndexBuilder with the LuceneIndexer
|
||||
// to the servlet context so we can access it later in the webapp.
|
||||
context.setAttribute(IndexBuilder.class.getName(),builder);
|
||||
|
||||
//set up listeners so search index builder is notified of changes to model
|
||||
OntModel baseOntModel = (OntModel)sce.getServletContext().getAttribute("baseOntModel");
|
||||
OntModel jenaOntModel = (OntModel)sce.getServletContext().getAttribute("jenaOntModel");
|
||||
SearchReindexingListener srl = new SearchReindexingListener( builder );
|
||||
ModelContext.registerListenerForChanges(sce.getServletContext(), srl);
|
||||
|
||||
}catch(Exception ex){
|
||||
log.error("Could not setup lucene full text search." , ex);
|
||||
}
|
||||
|
||||
log.debug("**** End of "+this.getClass().getName()+".contextInitialized()");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets run when the webApp Context gets destroyed.
|
||||
*/
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
|
||||
log.info("**** Running "+this.getClass().getName()+".contextDestroyed()");
|
||||
IndexBuilder builder = (IndexBuilder)sce.getServletContext().getAttribute(IndexBuilder.class.getName());
|
||||
builder.stopIndexingThread();
|
||||
}
|
||||
|
||||
/**
|
||||
* In wild card searches the query is first broken into many boolean searches
|
||||
* OR'ed together. So if there is a query that would match a lot of records
|
||||
* we need a high max boolean limit for the lucene search.
|
||||
*
|
||||
* This sets some static method in the lucene library to achieve this.
|
||||
*/
|
||||
public static void setBoolMax() {
|
||||
BooleanQuery.setMaxClauseCount(16384);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the directory to store the lucene index in. The
|
||||
* {@link ConfigurationProperties} should have a property named
|
||||
* 'vitro.home.directory' which has the parent directory of the directory to
|
||||
* store the lucene index for this clone in. If the property is not found,
|
||||
* an exception will be thrown.
|
||||
*
|
||||
* @return a string that is the directory to store the lucene index.
|
||||
* @throws IllegalStateException
|
||||
* if the property is not found,
|
||||
* or if the home directory does not exist.
|
||||
* @throws IOException
|
||||
* if the directory doesn't exist and we fail to create it.
|
||||
*/
|
||||
private String getIndexDirName(ServletContextEvent cte) throws IOException {
|
||||
String homeDirName = ConfigurationProperties.getBean(cte).getProperty(
|
||||
PROPERTY_VITRO_HOME);
|
||||
if (homeDirName == null) {
|
||||
throw new IllegalStateException(PROPERTY_VITRO_HOME
|
||||
+ " not found in properties file.");
|
||||
}
|
||||
|
||||
File homeDir = new File(homeDirName);
|
||||
if (!homeDir.exists()) {
|
||||
throw new IllegalStateException("Vitro home directory '"
|
||||
+ homeDir.getAbsolutePath() + "' does not exist.");
|
||||
}
|
||||
|
||||
File luceneDir = new File(homeDir, LUCENE_SUBDIRECTORY_NAME);
|
||||
if (!luceneDir.exists()) {
|
||||
boolean created = luceneDir.mkdir();
|
||||
if (!created) {
|
||||
throw new IOException(
|
||||
"Unable to create Lucene index directory at '"
|
||||
+ luceneDir + "'");
|
||||
}
|
||||
}
|
||||
|
||||
return luceneDir.getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the analyzer that will be used when building the indexing
|
||||
* and when analyzing the incoming search terms.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Analyzer getAnalyzer() {
|
||||
return new CJKAnalyzer();
|
||||
}
|
||||
|
||||
}
|
|
@ -32,6 +32,8 @@ import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactoryJena;
|
|||
import edu.cornell.mannlib.vitro.webapp.search.IndexConstants;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.IndividualProhibitedFromSearchImpl;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.ProhibitedFromSearch;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.indexing.AdditionalURIsForContextNodes;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.indexing.AdditionalURIsToIndex;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup;
|
||||
|
||||
|
@ -102,7 +104,11 @@ public class SolrSetup implements javax.servlet.ServletContextListener{
|
|||
VitroFilters vf = VitroFilterUtils.getPublicFilter(context);
|
||||
wadf = new WebappDaoFactoryFiltering(wadf, vf);
|
||||
|
||||
IndexBuilder builder = new IndexBuilder(context, solrIndexer, wadf);
|
||||
//make objects that will find additional URIs for context nodes etc
|
||||
List<AdditionalURIsToIndex> uriFinders = new ArrayList<AdditionalURIsToIndex>();
|
||||
uriFinders.add( new AdditionalURIsForContextNodes(jenaOntModel) );
|
||||
|
||||
IndexBuilder builder = new IndexBuilder(context, solrIndexer, wadf, uriFinders);
|
||||
// to the servlet context so we can access it later in the webapp.
|
||||
context.setAttribute(IndexBuilder.class.getName(), builder);
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import org.json.JSONObject;
|
|||
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.JSONServlet;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.SolrJsonServlet;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary;
|
||||
|
@ -81,7 +81,7 @@ public class BrowseDataGetter implements PageDataGetter {
|
|||
VClass vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(classUri);
|
||||
map.put("class", new VClassTemplateModel(vclass));
|
||||
|
||||
JSONObject vclassRes = JSONServlet.getLuceneIndividualsByVClass(vclass.getURI(), request, context);
|
||||
JSONObject vclassRes = SolrJsonServlet.getSolrIndividualsByVClass(vclass.getURI(), request, context);
|
||||
map.put("totalCount", JsonToFmModel.convertJSONObjectToMap( (String) vclassRes.get("totalCount") ));
|
||||
map.put("alpha", JsonToFmModel.convertJSONObjectToMap( (String) vclassRes.get("alpha") ));
|
||||
map.put("individuals", JsonToFmModel.convertJSONArrayToList( (JSONArray) vclassRes.get("individuals") ));
|
||||
|
|
|
@ -12,7 +12,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
@ -26,18 +25,9 @@ import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup;
|
|||
import edu.cornell.mannlib.vitro.webapp.controller.Controllers;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.SolrJsonServlet;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.PageController;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.SolrIndividualListController.PageRecord;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.VClassGroupCache;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.VClassGroupTemplateModel;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individuallist.BaseListedIndividual;
|
||||
import freemarker.ext.beans.BeansWrapper;
|
||||
import freemarker.template.TemplateModel;
|
||||
|
||||
public class DataGetterUtils {
|
||||
protected static final String DATA_GETTER_MAP = "pageTypeToDataGetterMap";
|
||||
|
|
|
@ -4,39 +4,25 @@ package edu.cornell.mannlib.vitro.webapp.utils.pageDataGetter;
|
|||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
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.Controllers;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.SolrIndividualListController;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController.PageRecord;
|
||||
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.web.templatemodels.VClassGroupTemplateModel;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individuallist.BaseListedIndividual;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.JSONServlet;
|
||||
import freemarker.ext.beans.BeansWrapper;
|
||||
import freemarker.template.TemplateModel;
|
||||
|
||||
/**
|
||||
* This will pass these variables to the template:
|
||||
|
@ -52,9 +38,7 @@ public class IndividualsForClassesDataGetter implements PageDataGetter{
|
|||
Map<String, List<String>> classIntersectionsMap = vreq.getWebappDaoFactory().getPageDao().getClassesAndRestrictionsForPage(pageUri);
|
||||
|
||||
|
||||
//Use Individual List Controller to get all the individuals and related data
|
||||
String alpha = IndividualListController.getAlphaParameter(vreq);
|
||||
int pageParam = IndividualListController.getPageParameter(vreq);
|
||||
//Use Individual List Controller to get all the individuals and related data
|
||||
List<Individual> inds = new ArrayList<Individual>();
|
||||
try{
|
||||
List<String> classes = classIntersectionsMap.get("classes");
|
||||
|
@ -184,4 +168,22 @@ public class IndividualsForClassesDataGetter implements PageDataGetter{
|
|||
vc.setEntityCount(0);
|
||||
}
|
||||
}
|
||||
|
||||
protected static String getAlphaParameter(VitroRequest request){
|
||||
return request.getParameter("alpha");
|
||||
}
|
||||
|
||||
protected static int getPageParameter(VitroRequest request) {
|
||||
String pageStr = request.getParameter("page");
|
||||
if( pageStr != null ){
|
||||
try{
|
||||
return Integer.parseInt(pageStr);
|
||||
}catch(NumberFormatException nfe){
|
||||
log.debug("could not parse page parameter");
|
||||
return 1;
|
||||
}
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue