VIVO-871 Improve performance when reading object properties.
Also, improve display.
This commit is contained in:
parent
56a640fe44
commit
78491234db
5 changed files with 196 additions and 148 deletions
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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>
|
Loading…
Add table
Reference in a new issue