VIVO-871 Improve performance when reading object properties.

Also, improve display.
This commit is contained in:
Jim Blake 2015-01-20 10:25:55 -05:00
parent 56a640fe44
commit 78491234db
5 changed files with 196 additions and 148 deletions

View file

@ -53,8 +53,8 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec
private static final Log log = LogFactory.getLog(ObjectPropertyStatementDaoJena.class); private static final Log log = LogFactory.getLog(ObjectPropertyStatementDaoJena.class);
private DatasetWrapperFactory dwf; protected DatasetWrapperFactory dwf;
private RDFService rdfService; protected RDFService rdfService;
public ObjectPropertyStatementDaoJena(RDFService rdfService, public ObjectPropertyStatementDaoJena(RDFService rdfService,
DatasetWrapperFactory dwf, DatasetWrapperFactory dwf,

View file

@ -2,164 +2,205 @@
package edu.cornell.mannlib.vitro.webapp.dao.jena; package edu.cornell.mannlib.vitro.webapp.dao.jena;
import static edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ModelSerializationFormat.N3;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Set;
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 com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.query.Dataset;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.util.iterator.ClosableIterator;
import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatementImpl; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatementImpl;
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao;
import edu.cornell.mannlib.vitro.webapp.dao.jena.IndividualSDB.IndividualNotFoundException;
import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactorySDB.SDBDatasetMode; import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactorySDB.SDBDatasetMode;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils;
public class ObjectPropertyStatementDaoSDB extends public class ObjectPropertyStatementDaoSDB extends
ObjectPropertyStatementDaoJena implements ObjectPropertyStatementDao { ObjectPropertyStatementDaoJena implements ObjectPropertyStatementDao {
private static final Log log = LogFactory
.getLog(ObjectPropertyStatementDaoSDB.class);
private static final Log log = LogFactory.getLog(ObjectPropertyStatementDaoSDB.class); // Get the types of the base entity.
private static final String SUBJECT_TYPE_QUERY = ""
+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n"
+ "CONSTRUCT { \n" //
+ " ?uri rdf:type ?type . \n" //
+ "} WHERE { \n" //
+ " ?uri rdf:type ?type . \n" //
+ "} \n";
private DatasetWrapperFactory dwf; // Get the types of all objects of properties.
private SDBDatasetMode datasetMode; private static final String OBJECT_TYPE_QUERY = ""
private WebappDaoFactorySDB wadf; + "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n"
+ "CONSTRUCT { \n" //
+ " ?uri ?p ?o . \n" //
+ " ?o rdf:type ?type . \n" //
+ "} WHERE { \n" //
+ " ?uri ?p ?o . \n" //
+ " ?o rdf:type ?type . \n" //
+ "} \n";
public ObjectPropertyStatementDaoSDB( // Get the labels of all objects of properties.
RDFService rdfService, private static final String OBJECT_LABEL_QUERY = ""
DatasetWrapperFactory dwf, + "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
SDBDatasetMode datasetMode, + "CONSTRUCT { \n" //
+ " ?uri ?p ?o . \n" //
+ " ?o rdfs:label ?label . \n" //
+ "} WHERE { \n" //
+ " ?uri ?p ?o . \n" //
+ " ?o rdfs:label ?label . \n" //
+ "} \n";
private final WebappDaoFactorySDB wadf;
private final SDBDatasetMode datasetMode;
public ObjectPropertyStatementDaoSDB(RDFService rdfService,
DatasetWrapperFactory dwf, SDBDatasetMode datasetMode,
WebappDaoFactorySDB wadf) { WebappDaoFactorySDB wadf) {
super (rdfService, dwf, wadf); super(rdfService, dwf, wadf);
this.dwf = dwf;
this.datasetMode = datasetMode;
this.wadf = wadf; this.wadf = wadf;
this.datasetMode = datasetMode;
} }
@Override @Override
public Individual fillExistingObjectPropertyStatements(Individual entity) { public Individual fillExistingObjectPropertyStatements(Individual entity) {
if (entity.getURI() == null) if (entity == null || entity.getURI() == null)
return entity; return entity;
else { else {
Map<String, ObjectProperty> uriToObjectProperty = new HashMap<String,ObjectProperty>(); List<ObjectPropertyStatement> objectPropertyStatements = new ArrayList<>();
String query = "CONSTRUCT { \n" + String subjectUri = entity.getURI();
" <" + entity.getURI() + "> ?p ?o . \n" +
// " ?o a ?oType . \n" +
// " ?o <" + RDFS.label.getURI() + "> ?oLabel . \n" +
// " ?o <" + VitroVocabulary.MONIKER + "> ?oMoniker \n" +
"} WHERE { \n" +
" { <" + entity.getURI() + "> ?p ?o } \n" +
// " UNION { <" + entity.getURI() + "> ?p ?o . ?o a ?oType } \n" +
// " UNION { <" + entity.getURI() + "> ?p ?o . \n" +
// " ?o <" + RDFS.label.getURI() + "> ?oLabel } \n" +
// " UNION { <" + entity.getURI() + "> ?p ?o . \n " +
// " ?o <" + VitroVocabulary.MONIKER + "> ?oMoniker } \n" +
"}";
long startTime = System.currentTimeMillis();
Model m = null;
DatasetWrapper w = dwf.getDatasetWrapper();
Dataset dataset = w.getDataset();
dataset.getLock().enterCriticalSection(Lock.READ);
QueryExecution qexec = null;
try {
qexec = QueryExecutionFactory.create(QueryFactory.create(query), dataset);
m = qexec.execConstruct();
} finally {
if(qexec != null) qexec.close();
dataset.getLock().leaveCriticalSection();
w.close();
}
if (log.isDebugEnabled()) {
log.debug("Time (ms) to query for related individuals: " + (System.currentTimeMillis() - startTime));
if (System.currentTimeMillis() - startTime > 1000) {
//log.debug(query);
log.debug("Results size (statements): " + m.size());
}
}
OntModel ontModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM, m); Model m = getInfoForObjectsOfThisEntity(subjectUri);
ontModel.enterCriticalSection(Lock.READ);
try {
Resource ind = ontModel.getResource(entity.getURI());
List<ObjectPropertyStatement> objPropertyStmtList = new ArrayList<ObjectPropertyStatement>();
ClosableIterator<Statement> propIt = ind.listProperties();
try {
while (propIt.hasNext()) {
Statement st = propIt.next();
if (st.getObject().isResource() && !(NONUSER_NAMESPACES.contains(st.getPredicate().getNameSpace()))) {
try {
ObjectPropertyStatement objPropertyStmt = new ObjectPropertyStatementImpl();
objPropertyStmt.setSubjectURI(entity.getURI());
objPropertyStmt.setSubject(entity);
objPropertyStmt.setObjectURI(((Resource)st.getObject()).getURI());
objPropertyStmt.setPropertyURI(st.getPredicate().getURI()); Set<String> subjectTypes = getTypes(m, subjectUri);
Property prop = st.getPredicate(); for (ObjectPropertyPair pair : getRawObjectPropertyPairs(m,
if( uriToObjectProperty.containsKey(prop.getURI())){ subjectUri)) {
objPropertyStmt.setProperty(uriToObjectProperty.get(prop.getURI())); String predicateUri = pair.getPredicateUri();
}else{ String objectUri = pair.getObjectUri();
ObjectProperty p = getWebappDaoFactory().getObjectPropertyDao().getObjectPropertyByURI(prop.getURI()); Set<String> objectTypes = getTypes(m, objectUri);
if( p != null ){
uriToObjectProperty.put(prop.getURI(), p); ObjectProperty prop = findRawProperty(predicateUri);
objPropertyStmt.setProperty(uriToObjectProperty.get(prop.getURI())); if (prop == null) {
}else{
//if ObjectProperty not found in ontology, skip it
continue; continue;
} }
}
if (objPropertyStmt.getObjectURI() != null) { Individual object = new IndividualSDB(objectUri, dwf,
//this might throw IndividualNotFoundException datasetMode, wadf, m);
Individual objInd = new IndividualSDB( objectPropertyStatements.add(createStatement(entity, prop,
objPropertyStmt.getObjectURI(), object));
this.dwf,
datasetMode,
wadf);
objPropertyStmt.setObject(objInd);
}
//only add statement to list if it has its values filled out
if ( (objPropertyStmt.getSubjectURI() != null)
&& (objPropertyStmt.getPropertyURI() != null)
&& (objPropertyStmt.getObject() != null) ) {
objPropertyStmtList.add(objPropertyStmt);
}
} catch (IndividualNotFoundException t) {
log.debug(t,t);
continue;
} catch (Throwable t){
log.error(t,t);
continue;
}
}
}
} finally {
propIt.close();
}
entity.setObjectPropertyStatements(objPropertyStmtList);
} finally {
ontModel.leaveCriticalSection();
} }
entity.setObjectPropertyStatements(objectPropertyStatements);
return entity; return entity;
} }
} }
/**
* Get the types of this entity. Get the related object and the predicates
* by which they are related. Get the types and labels of those related
* objects.
*/
private Model getInfoForObjectsOfThisEntity(String subjectUri) {
Model m = ModelFactory.createDefaultModel();
try {
m.add(RDFServiceUtils.parseModel(
rdfService.sparqlConstructQuery(
substituteUri(subjectUri, SUBJECT_TYPE_QUERY), N3),
N3));
m.add(RDFServiceUtils.parseModel(
rdfService.sparqlConstructQuery(
substituteUri(subjectUri, OBJECT_TYPE_QUERY), N3),
N3));
m.add(RDFServiceUtils.parseModel(
rdfService.sparqlConstructQuery(
substituteUri(subjectUri, OBJECT_LABEL_QUERY), N3),
N3));
} catch (RDFServiceException e) {
log.warn("Failed to fill object property statements for '"
+ subjectUri + "'", e);
}
return m;
}
private String substituteUri(String uri, String query) {
return query.replace("?uri", "<" + uri + "> ");
}
private Set<String> getTypes(Model m, String uri) {
Set<String> typeUris = new HashSet<>();
for (RDFNode typeNode : m.listObjectsOfProperty(m.createResource(uri),
RDF.type).toSet()) {
if (typeNode.isURIResource()) {
typeUris.add(typeNode.asResource().getURI());
}
}
return typeUris;
}
private List<ObjectPropertyPair> getRawObjectPropertyPairs(Model m,
String subjectUri) {
List<ObjectPropertyPair> list = new ArrayList<>();
for (Statement stmt : m.listStatements(m.createResource(subjectUri),
null, (RDFNode) null).toList()) {
if (wadf.getNonuserNamespaces().contains(
stmt.getPredicate().getNameSpace())) {
continue;
}
if (!stmt.getObject().isURIResource()) {
continue;
}
list.add(new ObjectPropertyPair(stmt.getPredicate().getURI(), stmt
.getObject().asResource().getURI()));
}
return list;
}
private ObjectProperty findRawProperty(String predicateUri) {
return wadf.getObjectPropertyDao().getObjectPropertyByURI(predicateUri);
}
private ObjectPropertyStatement createStatement(Individual entity,
ObjectProperty prop, Individual object) {
ObjectPropertyStatementImpl ops = new ObjectPropertyStatementImpl();
ops.setSubject(entity);
ops.setProperty(prop);
ops.setObject(object);
return ops;
}
// ----------------------------------------------------------------------
// Helper classes
// ----------------------------------------------------------------------
private static class ObjectPropertyPair {
private final String predicateUri;
private final String objectUri;
public ObjectPropertyPair(String predicateUri, String objectUri) {
this.predicateUri = predicateUri;
this.objectUri = objectUri;
}
public String getPredicateUri() {
return predicateUri;
}
public String getObjectUri() {
return objectUri;
}
}
} }

View file

@ -77,7 +77,7 @@ public class UpdateStatementsTask implements Task {
this.uris = Collections.synchronizedSet(new HashSet<String>()); this.uris = Collections.synchronizedSet(new HashSet<String>());
this.status = new Status(changes.size(), 200, listeners); this.status = new Status(changes.size(), 500, listeners);
} }
@Override @Override

View file

@ -66,7 +66,7 @@ public class UpdateUrisTask implements Task {
this.listeners = listeners; this.listeners = listeners;
this.pool = pool; this.pool = pool;
this.status = new Status(uris.size(), 200, listeners); this.status = new Status(uris.size(), 500, listeners);
this.searchEngine = ApplicationUtils.instance().getSearchEngine(); this.searchEngine = ApplicationUtils.instance().getSearchEngine();

View file

@ -20,12 +20,19 @@ table.threadInfo th {
<h2>${i18n().background_threads}</h2> <h2>${i18n().background_threads}</h2>
<section id="show-threads" role="region"> <section id="show-threads" role="region">
<table class="threadInfo" summary="Status of background threads.">
<tr>
<th>${i18n().name}</th>
<th>${i18n().work_level}</th>
<th>${i18n().since}</th>
<th>${i18n().flags}</th>
</tr>
<#list threads as threadInfo> <#list threads as threadInfo>
<table class="threadInfo ${threadInfo.workLevel}" summary="Thread ${threadInfo.name}"> <tr>
<tr><th>${i18n().name}</th><td>${threadInfo.name}</td></tr> <td>${threadInfo.name}</td>
<tr><th>${i18n().work_level}</th><td>${threadInfo.workLevel}</td></tr> <td>${threadInfo.workLevel}</td>
<tr><th>${i18n().since}</th><td>${threadInfo.since}</td></tr> <td>${threadInfo.since}</td>
<tr><th>${i18n().flags}</th><td>${threadInfo.flags}</td></tr> <td>${threadInfo.flags}</td>
</table>
</#list> </#list>
</table>
</section> </section>