NIHVIVO-2437 Sort individuallist page results
This commit is contained in:
parent
1c975919c5
commit
5364161038
6 changed files with 189 additions and 21 deletions
|
@ -483,6 +483,8 @@
|
||||||
<field name="nameRaw" type="string" indexed="false" stored="true" multiValued="true"/>
|
<field name="nameRaw" type="string" indexed="false" stored="true" multiValued="true"/>
|
||||||
<!-- RY Not sure if we need to store nameLowercase. Is it ever displayed? -->
|
<!-- RY Not sure if we need to store nameLowercase. Is it ever displayed? -->
|
||||||
<field name="nameLowercase" type="lowercase" indexed="true" stored="true" multiValued="true"/>
|
<field name="nameLowercase" type="lowercase" indexed="true" stored="true" multiValued="true"/>
|
||||||
|
<!-- A sortable version of nameLowercase -->
|
||||||
|
<field name="nameLowercaseSingleValued" type="lowercase" indexed="true" stored="false" multiValued="false" />
|
||||||
<field name="acNameUnstemmed" type="textUnstemmed" indexed="true" stored="false" multiValued="true"/>
|
<field name="acNameUnstemmed" type="textUnstemmed" indexed="true" stored="false" multiValued="true"/>
|
||||||
<field name="acNameStemmed" type="text" indexed="true" stored="false" multiValued="true"/>
|
<field name="acNameStemmed" type="text" indexed="true" stored="false" multiValued="true"/>
|
||||||
<field name="indexedTime" type="string" indexed="true" stored="true" multiValued="true"/>
|
<field name="indexedTime" type="string" indexed="true" stored="true" multiValued="true"/>
|
||||||
|
@ -495,6 +497,8 @@
|
||||||
<field name="modType" type="ignored"/>
|
<field name="modType" type="ignored"/>
|
||||||
<field name="JCLASS" type="ignored"/>
|
<field name="JCLASS" type="ignored"/>
|
||||||
|
|
||||||
|
<!-- Copy nameLowercase to sortable field. -->
|
||||||
|
<copyField source="nameLowercase" dest="nameLowercaseSingleValued" />
|
||||||
|
|
||||||
<!-- **************************** End Vitro Fields *************************** -->
|
<!-- **************************** End Vitro Fields *************************** -->
|
||||||
|
|
||||||
|
|
|
@ -233,7 +233,7 @@ public class JSONServlet extends VitroHttpServlet {
|
||||||
rObj.put("alpha", map.get("alpha"));
|
rObj.put("alpha", map.get("alpha"));
|
||||||
|
|
||||||
List<Individual> inds = (List<Individual>)map.get("entities");
|
List<Individual> inds = (List<Individual>)map.get("entities");
|
||||||
List<IndividualTemplateModel> indsTm = new ArrayList<IndividualTemplateModel>();
|
|
||||||
JSONArray jInds = new JSONArray();
|
JSONArray jInds = new JSONArray();
|
||||||
for(Individual ind : inds ){
|
for(Individual ind : inds ){
|
||||||
JSONObject jo = new JSONObject();
|
JSONObject jo = new JSONObject();
|
||||||
|
|
|
@ -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<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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,9 +15,7 @@ import javax.servlet.ServletException;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.lucene.document.Document;
|
|
||||||
import org.apache.lucene.index.CorruptIndexException;
|
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.SolrQuery;
|
||||||
import org.apache.solr.client.solrj.SolrServer;
|
import org.apache.solr.client.solrj.SolrServer;
|
||||||
import org.apache.solr.client.solrj.response.QueryResponse;
|
import org.apache.solr.client.solrj.response.QueryResponse;
|
||||||
|
@ -180,7 +178,7 @@ public class SolrIndividualListController extends FreemarkerHttpServlet {
|
||||||
SolrServer solr = SolrSetup.getSolrServer(context);
|
SolrServer solr = SolrSetup.getSolrServer(context);
|
||||||
QueryResponse response = null;
|
QueryResponse response = null;
|
||||||
|
|
||||||
// Execute lucene query for individuals of the specified type
|
// Execute query for individuals of the specified type
|
||||||
try {
|
try {
|
||||||
response = solr.query(query);
|
response = solr.query(query);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
@ -197,18 +195,18 @@ public class SolrIndividualListController extends FreemarkerHttpServlet {
|
||||||
throw new ServletException("Could not run search in IndividualListController");
|
throw new ServletException("Could not run search in IndividualListController");
|
||||||
}
|
}
|
||||||
|
|
||||||
// get list of individuals for the search results
|
// get list of individuals for the search results
|
||||||
long size = docs.getNumFound();
|
long size = docs.getNumFound();
|
||||||
log.debug("Number of search results: " + size);
|
log.debug("Number of search results: " + size);
|
||||||
|
|
||||||
List<Individual> individuals = new ArrayList<Individual>((int)size);
|
List<Individual> individuals = new ArrayList<Individual>();
|
||||||
for (SolrDocument doc : docs) {
|
for (SolrDocument doc : docs) {
|
||||||
String uri = doc.get(VitroLuceneTermNames.URI).toString();
|
String uri = doc.get(VitroLuceneTermNames.URI).toString();
|
||||||
Individual individual = indDao.getIndividualByURI( uri );
|
Individual individual = indDao.getIndividualByURI( uri );
|
||||||
if (individual != null) {
|
if (individual != null) {
|
||||||
individuals.add(individual);
|
individuals.add(individual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rvMap.put("count", size);
|
rvMap.put("count", size);
|
||||||
|
|
||||||
|
@ -245,7 +243,8 @@ public class SolrIndividualListController extends FreemarkerHttpServlet {
|
||||||
|
|
||||||
int start = (page-1)*INDIVIDUALS_PER_PAGE;
|
int start = (page-1)*INDIVIDUALS_PER_PAGE;
|
||||||
query.setStart(start)
|
query.setStart(start)
|
||||||
.setRows(INDIVIDUALS_PER_PAGE);
|
.setRows(INDIVIDUALS_PER_PAGE)
|
||||||
|
.setSortField("nameLowercaseSingleValued", SolrQuery.ORDER.asc);
|
||||||
|
|
||||||
log.debug("Query: " + query);
|
log.debug("Query: " + query);
|
||||||
return query;
|
return query;
|
||||||
|
@ -314,5 +313,4 @@ public class SolrIndividualListController extends FreemarkerHttpServlet {
|
||||||
return selected;
|
return selected;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,6 @@ public class SolrAutocompleteController extends VitroAjaxController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since SolrQuery.setSortField() is buggy, sort the results here
|
|
||||||
Collections.sort(results);
|
Collections.sort(results);
|
||||||
|
|
||||||
// map.put("results", results);
|
// map.put("results", results);
|
||||||
|
@ -157,8 +156,9 @@ public class SolrAutocompleteController extends VitroAjaxController {
|
||||||
}
|
}
|
||||||
|
|
||||||
query.setFields(VitroLuceneTermNames.NAME_RAW, VitroLuceneTermNames.URI); // fields to retrieve
|
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;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,10 @@ public class Entity2LuceneDoc implements Obj2DocIface{
|
||||||
/** rdfs:label lowercased, no tokenizing, no stop words, no stemming **/
|
/** rdfs:label lowercased, no tokenizing, no stop words, no stemming **/
|
||||||
public static String NAME_LOWERCASE = "nameLowercase"; // was NAMELOWERCASE
|
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.
|
/** rdfs:label lowercased, tokenized, stop words, no stemming.
|
||||||
* Used for autocomplete matching on proper names. **/
|
* Used for autocomplete matching on proper names. **/
|
||||||
public static String AC_NAME_UNSTEMMED = "acNameUnstemmed"; // was NAMEUNSTEMMED
|
public static String AC_NAME_UNSTEMMED = "acNameUnstemmed"; // was NAMEUNSTEMMED
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue