diff --git a/solr/exampleSolr/conf/schema.xml b/solr/exampleSolr/conf/schema.xml index 8b70e5ca1..7584c46dd 100644 --- a/solr/exampleSolr/conf/schema.xml +++ b/solr/exampleSolr/conf/schema.xml @@ -483,6 +483,8 @@ + + @@ -495,6 +497,8 @@ + + diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/JSONServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/JSONServlet.java index af6d82d5f..5494938c2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/JSONServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/JSONServlet.java @@ -233,7 +233,7 @@ public class JSONServlet extends VitroHttpServlet { rObj.put("alpha", map.get("alpha")); List inds = (List)map.get("entities"); - List indsTm = new ArrayList(); + JSONArray jInds = new JSONArray(); for(Individual ind : inds ){ JSONObject jo = new JSONObject(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/SolrEntityUrlController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/SolrEntityUrlController.java new file mode 100644 index 000000000..2cfea4d85 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/SolrEntityUrlController.java @@ -0,0 +1,162 @@ +/* $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 SolrEntityUrlController extends VitroHttpServlet { + + private static final long serialVersionUID = 1L; + private static final Log log = LogFactory.getLog(SolrEntityUrlController.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("^/entityurl/$").matcher(url).matches()){ + String redirectURL = null; + if(contentType!=null){ + if ( RDFXML_MIMETYPE.equals(contentType.getMediaType())) + redirectURL = "/entityurl/entityurl.rdf"; + else if( N3_MIMETYPE.equals(contentType.getMediaType())) + redirectURL = "/entityurl/entityurl.n3"; + else if ( TTL_MIMETYPE.equals(contentType.getMediaType())) + redirectURL = "/entityurl/entityurl.ttl"; + } + else{ + redirectURL = "/entityurl/entityrurl.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 actualContentTypes = new ArrayList(); + 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; +} +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/SolrIndividualListController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/SolrIndividualListController.java index 0dab98de1..924a6722f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/SolrIndividualListController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/SolrIndividualListController.java @@ -15,9 +15,7 @@ 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.search.ScoreDoc; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.response.QueryResponse; @@ -180,7 +178,7 @@ public class SolrIndividualListController extends FreemarkerHttpServlet { SolrServer solr = SolrSetup.getSolrServer(context); QueryResponse response = null; - // Execute lucene query for individuals of the specified type + // Execute query for individuals of the specified type try { response = solr.query(query); } catch (Throwable t) { @@ -197,19 +195,19 @@ public class SolrIndividualListController extends FreemarkerHttpServlet { throw new ServletException("Could not run search in IndividualListController"); } - // get list of individuals for the search results - long size = docs.getNumFound(); - log.debug("Number of search results: " + size); + // get list of individuals for the search results + long size = docs.getNumFound(); + log.debug("Number of search results: " + size); - List individuals = new ArrayList((int)size); - for (SolrDocument doc : docs) { - String uri = doc.get(VitroLuceneTermNames.URI).toString(); - Individual individual = indDao.getIndividualByURI( uri ); - if (individual != null) { - individuals.add(individual); - } - } - + List individuals = new ArrayList(); + for (SolrDocument doc : docs) { + String uri = doc.get(VitroLuceneTermNames.URI).toString(); + Individual individual = indDao.getIndividualByURI( uri ); + if (individual != null) { + individuals.add(individual); + } + } + rvMap.put("count", size); if( size > INDIVIDUALS_PER_PAGE ){ @@ -245,7 +243,8 @@ public class SolrIndividualListController extends FreemarkerHttpServlet { int start = (page-1)*INDIVIDUALS_PER_PAGE; query.setStart(start) - .setRows(INDIVIDUALS_PER_PAGE); + .setRows(INDIVIDUALS_PER_PAGE) + .setSortField("nameLowercaseSingleValued", SolrQuery.ORDER.asc); log.debug("Query: " + query); return query; @@ -314,5 +313,4 @@ public class SolrIndividualListController extends FreemarkerHttpServlet { return selected; } } - } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/SolrAutocompleteController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/SolrAutocompleteController.java index 663467256..560ab69cd 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/SolrAutocompleteController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/SolrAutocompleteController.java @@ -114,7 +114,6 @@ public class SolrAutocompleteController extends VitroAjaxController { } } - // Since SolrQuery.setSortField() is buggy, sort the results here Collections.sort(results); // map.put("results", results); @@ -157,8 +156,9 @@ public class SolrAutocompleteController extends VitroAjaxController { } query.setFields(VitroLuceneTermNames.NAME_RAW, VitroLuceneTermNames.URI); // fields to retrieve - // Solr bug: generates sort=nameLowercase asc instead of sort=nameLowercase+asc - //.setSortField(VitroLuceneTermNames.NAME_LOWERCASE, SolrQuery.ORDER.asc); + + // Can't sort on multivalued field, so sort results in Java when we get them + // query.setSortField(VitroLuceneTermNames.NAME_LOWERCASE, SolrQuery.ORDER.asc); return query; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/lucene/Entity2LuceneDoc.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/lucene/Entity2LuceneDoc.java index 30831f197..e4aa2abf5 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/lucene/Entity2LuceneDoc.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/lucene/Entity2LuceneDoc.java @@ -80,6 +80,10 @@ public class Entity2LuceneDoc implements Obj2DocIface{ /** rdfs:label lowercased, no tokenizing, no stop words, no stemming **/ public static String NAME_LOWERCASE = "nameLowercase"; // was NAMELOWERCASE + /** Same as NAME_LOWERCASE, but single-valued so it's sortable. **/ + // RY Need to control how indexing selects which of multiple values to copy. + public static String NAME_LOWERCASE_SINGLE_VALUED = "nameLowercaseSingleValued"; + /** rdfs:label lowercased, tokenized, stop words, no stemming. * Used for autocomplete matching on proper names. **/ public static String AC_NAME_UNSTEMMED = "acNameUnstemmed"; // was NAMEUNSTEMMED