NIHVIVO-2660 Filter out data property statements that don't have a literal object. Some associated refactoring.

This commit is contained in:
ryounes 2011-05-31 21:37:04 +00:00
parent a7a576340f
commit 010ffda62c
7 changed files with 166 additions and 132 deletions

View file

@ -58,31 +58,6 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements
protected static final Log log = LogFactory.getLog(DataPropertyDaoJena.class.getName());
/* This may be the intent behind JenaBaseDao.NONUSER_NAMESPACES, but that
* value does not contain all of these namespaces.
*/
protected static final List<String> EXCLUDED_NAMESPACES = Arrays.asList(
// Don't need to exclude these, because they are not owl:DatatypeProperty
//"http://www.w3.org/1999/02/22-rdf-syntax-ns#",
//"http://www.w3.org/2000/01/rdf-schema#",
"http://www.w3.org/2002/07/owl#",
"http://vitro.mannlib.cornell.edu/ns/vitro/0.7#",
"http://vitro.mannlib.cornell.edu/ns/vitro/public#"
);
/*
* This is a hack to throw out properties in the vitro, rdf, rdfs, and owl namespaces.
* It will be implemented in a better way in v1.3 (Editing and Display Configuration).
*/
protected static final String PROPERTY_FILTERS;
static {
List<String> namespaceFilters = new ArrayList<String>();
for (String namespace : EXCLUDED_NAMESPACES) {
namespaceFilters.add("( afn:namespace(?property) != \"" + namespace + "\" )");
}
PROPERTY_FILTERS = StringUtils.join(namespaceFilters, " && ");
}
private class DataPropertyRanker implements Comparator {
public int compare (Object o1, Object o2) {
DataProperty dp1 = (DataProperty) o1;
@ -735,34 +710,63 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements
return rootProperties;
}
/*
* SPARQL-based methods for getting the individual's data properties.
* Ideally this implementation should replace the existing way of getting
* the data property list, but the consequences of this may be far-reaching,
* so we are implementing a new method now and will merge the old approach
* into the new one in a future release.
*/
/* This may be the intent behind JenaBaseDao.NONUSER_NAMESPACES, but that
* value does not contain all of these namespaces.
*/
protected static final List<String> EXCLUDED_NAMESPACES = Arrays.asList(
// Don't need to exclude these, because they are not owl:DatatypeProperty
//"http://www.w3.org/1999/02/22-rdf-syntax-ns#",
//"http://www.w3.org/2000/01/rdf-schema#",
"http://www.w3.org/2002/07/owl#",
"http://vitro.mannlib.cornell.edu/ns/vitro/0.7#",
"http://vitro.mannlib.cornell.edu/ns/vitro/public#"
);
/*
* This is a hack to throw out properties in the vitro, rdf, rdfs, and owl namespaces.
* It will be implemented in a better way in v1.3 (Editing and Display Configuration).
*/
protected static final String PROPERTY_FILTERS;
static {
List<String> namespaceFilters = new ArrayList<String>();
for (String namespace : EXCLUDED_NAMESPACES) {
namespaceFilters.add("( afn:namespace(?property) != \"" + namespace + "\" )");
}
PROPERTY_FILTERS = StringUtils.join(namespaceFilters, " && ");
}
protected static final String DATA_PROPERTY_QUERY_STRING =
PREFIXES + "\n" +
"SELECT DISTINCT ?property WHERE { \n" +
" ?subject ?property ?object . \n" +
" ?property a owl:DatatypeProperty . \n" +
" FILTER ( \n" +
" isLiteral(?object) && \n" +
PROPERTY_FILTERS + "\n" +
" ) \n" +
"}";
@Override
public List<DataProperty> getDataPropertyList(Individual subject) {
return getDataPropertyList(subject.getURI());
}
@Override
/*
* SPARQL-based method for getting the individual's data properties.
* Ideally this implementation should replace the existing way of getting
* the data property list, but the consequences of this may be far-reaching,
* so we are implementing a new method now and will merge the old approach
* into the new one in a future release.
*/
public List<DataProperty> getDataPropertyList(String subjectUri) {
// Due to a Jena bug, prebinding on ?subject combined with the isLiteral()
// filter causes the query to fail. Using string concatenation to insert the
// subject uri instead.
String queryString =
prefixes + "\n" +
"SELECT DISTINCT ?property WHERE { \n" +
" <" + subjectUri + "> ?property ?object . \n" +
" ?property a owl:DatatypeProperty . \n" +
" FILTER ( \n" +
" isLiteral(?object) && \n" +
PROPERTY_FILTERS + "\n" +
" ) \n" +
"}";
// filter causes the query to fail. Insert the subjectUri manually instead.
// QuerySolutionMap initialBindings = new QuerySolutionMap();
// initialBindings.add("subject", ResourceFactory.createResource(subjectUri));
String queryString = subUriForQueryVar(DATA_PROPERTY_QUERY_STRING, "subject", subjectUri);
Query query = null;
try {

View file

@ -4,10 +4,11 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.hp.hpl.jena.datatypes.TypeMapper;
import com.hp.hpl.jena.ontology.DatatypeProperty;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntResource;
import com.hp.hpl.jena.query.Dataset;
@ -16,7 +17,6 @@ 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.query.QuerySolution;
import com.hp.hpl.jena.query.QuerySolutionMap;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.AnonId;
import com.hp.hpl.jena.rdf.model.Literal;
@ -42,21 +42,6 @@ public class DataPropertyStatementDaoJena extends JenaBaseDao implements DataPro
private DatasetWrapperFactory dwf;
protected static final String DATA_PROPERTY_VALUE_QUERY_STRING =
"SELECT ?value WHERE { \n" +
" ?subject ?property ?value . \n" +
"}";
static protected Query dataPropertyValueQuery;
static {
try {
dataPropertyValueQuery = QueryFactory.create(DATA_PROPERTY_VALUE_QUERY_STRING);
} catch(Throwable th){
log.error("could not create SPARQL query for DATA_PROPERTY_VALUE_QUERY_STRING " + th.getMessage());
log.error(DATA_PROPERTY_VALUE_QUERY_STRING);
}
}
public DataPropertyStatementDaoJena(DatasetWrapperFactory dwf,
WebappDaoFactoryJena wadf) {
super(wadf);
@ -311,6 +296,23 @@ public class DataPropertyStatementDaoJena extends JenaBaseDao implements DataPro
* SPARQL-based methods for getting the individual's values for a single data property.
*/
protected static final String DATA_PROPERTY_VALUE_QUERY_STRING =
"SELECT ?value WHERE { \n" +
" ?subject ?property ?value . \n" +
// ignore statements with uri values
" FILTER ( isLiteral(?value) ) " +
"} ";
protected static Query dataPropertyValueQuery;
static {
try {
dataPropertyValueQuery = QueryFactory.create(DATA_PROPERTY_VALUE_QUERY_STRING);
} catch(Throwable th) {
log.error("could not create SPARQL query for DATA_PROPERTY_VALUE_QUERY_STRING " + th.getMessage());
log.error(DATA_PROPERTY_VALUE_QUERY_STRING);
}
}
@Override
public List<Literal> getDataPropertyValuesForIndividualByProperty(Individual subject, DataProperty property) {
return getDataPropertyValuesForIndividualByProperty(subject.getURI(), property.getURI());
@ -320,10 +322,16 @@ public class DataPropertyStatementDaoJena extends JenaBaseDao implements DataPro
public List<Literal> getDataPropertyValuesForIndividualByProperty(String subjectUri, String propertyUri) {
log.debug("Data property value query string:\n" + DATA_PROPERTY_VALUE_QUERY_STRING);
log.debug("Data property value:\n" + dataPropertyValueQuery);
QuerySolutionMap initialBindings = new QuerySolutionMap();
initialBindings.add("subject", ResourceFactory.createResource(subjectUri));
initialBindings.add("property", ResourceFactory.createResource(propertyUri));
// Due to a Jena bug, prebinding on ?subject combined with the isLiteral()
// filter causes the query to fail. Insert the subjectUri manually instead.
// QuerySolutionMap initialBindings = new QuerySolutionMap();
// initialBindings.add("subject", ResourceFactory.createResource(subjectUri));
// initialBindings.add("property", ResourceFactory.createResource(propertyUri));
Map<String, String> bindings = new HashMap<String, String>();
bindings.put("subject", subjectUri);
bindings.put("property", propertyUri);
String queryString = subUrisForQueryVars(DATA_PROPERTY_VALUE_QUERY_STRING, bindings);
// Run the SPARQL query to get the properties
List<Literal> values = new ArrayList<Literal>();
@ -332,7 +340,7 @@ public class DataPropertyStatementDaoJena extends JenaBaseDao implements DataPro
dataset.getLock().enterCriticalSection(Lock.READ);
try {
QueryExecution qexec = QueryExecutionFactory.create(
dataPropertyValueQuery, dataset, initialBindings);
queryString, dataset);
ResultSet results = qexec.execSelect();
while (results.hasNext()) {

View file

@ -1071,5 +1071,21 @@ public class JenaBaseDao extends JenaBaseDaoCon {
return temp;
}
/** Manually replace query variables with uris when prebinding causes the query to fail, probably
* due to a Jena bug.
*/
protected static String subUrisForQueryVars(String queryString, Map<String, String> varsToUris) {
for (String var : varsToUris.keySet()) {
queryString = subUriForQueryVar(queryString, var, varsToUris.get(var));
}
return queryString;
}
/** Manually replace a query variable with a uri when prebinding causes the query to fail, probably
* due to a Jena bug.
*/
protected static String subUriForQueryVar(String queryString, String varName, String uri) {
return queryString.replaceAll("\\?" + varName + "\\b", "<" + uri + ">");
}
}

View file

@ -52,44 +52,6 @@ import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent;
public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectPropertyDao {
private static final Log log = LogFactory.getLog(ObjectPropertyDaoJena.class.getName());
protected static final List<String> EXCLUDED_NAMESPACES = Arrays.asList(
"http://www.w3.org/2002/07/owl#"
);
/*
* This is a hack to throw out properties in the vitro, rdf, rdfs, and owl namespaces.
* It will be implemented in a better way in v1.3 (Editing and Display Configuration).
*/
protected static final String PROPERTY_FILTERS;
static {
List<String> namespaceFilters = new ArrayList<String>();
for (String namespace : EXCLUDED_NAMESPACES) {
namespaceFilters.add("( afn:namespace(?property) != \"" + namespace + "\" )");
}
// A hack to include the vitro:primaryLink and vitro:additionalLink properties in the list
namespaceFilters.add("( ?property = vitro:primaryLink ||" +
"?property = vitro:additionalLink ||" +
"afn:namespace(?property) != \"http://vitro.mannlib.cornell.edu/ns/vitro/0.7#\" )");
PROPERTY_FILTERS = StringUtils.join(namespaceFilters, " && ");
}
protected static final String LIST_VIEW_CONFIG_FILE_QUERY_STRING =
"PREFIX display: <http://vitro.mannlib.cornell.edu/ontologies/display/1.1#>" +
"SELECT ?property ?filename WHERE { \n" +
" ?property display:listViewConfigFile ?filename . \n" +
"}";
protected static Query listViewConfigFileQuery = null;
static {
try {
listViewConfigFileQuery = QueryFactory.create(LIST_VIEW_CONFIG_FILE_QUERY_STRING);
} catch(Throwable th){
log.error("could not create SPARQL query for LIST_VIEW_CONFIG_FILE_QUERY_STRING " + th.getMessage());
log.error(LIST_VIEW_CONFIG_FILE_QUERY_STRING);
}
}
Map<ObjectProperty, String> customListViewConfigFileMap = null;
public ObjectPropertyDaoJena(DatasetWrapperFactory dwf,
WebappDaoFactoryJena wadf) {
super(dwf, wadf);
@ -847,34 +809,57 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp
return false;
}
/*
* SPARQL-based methods for getting the individual's object properties.
* Ideally this implementation should replace the existing way of getting
* the object property list, but the consequences of this may be far-reaching,
* so we are implementing a new method now and will merge the old approach
* into the new one in a future release.
*/
protected static final List<String> EXCLUDED_NAMESPACES = Arrays.asList(
"http://www.w3.org/2002/07/owl#"
);
/*
* This is a hack to throw out properties in the vitro, rdf, rdfs, and owl namespaces.
* It will be implemented in a better way in v1.3 (Editing and Display Configuration).
*/
protected static final String PROPERTY_FILTERS;
static {
List<String> namespaceFilters = new ArrayList<String>();
for (String namespace : EXCLUDED_NAMESPACES) {
namespaceFilters.add("( afn:namespace(?property) != \"" + namespace + "\" )");
}
// A hack to include the vitro:primaryLink and vitro:additionalLink properties in the list
namespaceFilters.add("( ?property = vitro:primaryLink ||" +
"?property = vitro:additionalLink ||" +
"afn:namespace(?property) != \"http://vitro.mannlib.cornell.edu/ns/vitro/0.7#\" )");
PROPERTY_FILTERS = StringUtils.join(namespaceFilters, " && ");
}
protected static final String OBJECT_PROPERTY_QUERY_STRING =
PREFIXES + "\n" +
"SELECT DISTINCT ?property WHERE { \n" +
" ?subject ?property ?object . \n" +
" ?property a owl:ObjectProperty . \n" +
" FILTER ( \n" +
" isURI(?object) && \n" +
PROPERTY_FILTERS + "\n" +
" ) \n" +
"}";
@Override
public List<ObjectProperty> getObjectPropertyList(Individual subject) {
return getObjectPropertyList(subject.getURI());
}
@Override
/*
* SPARQL-based method for getting the individual's object properties.
* Ideally this implementation should replace the existing way of getting
* the object property list, but the consequences of this may be far-reaching,
* so we are implementing a new method now and will merge the old approach
* into the new one in a future release.
*/
public List<ObjectProperty> getObjectPropertyList(String subjectUri) {
// Due to a Jena bug, prebinding on ?subject combined with the isURI()
// filter causes the query to fail. Using string concatenation to insert the
// subject uri instead.
String queryString =
prefixes + "\n" +
"SELECT DISTINCT ?property WHERE { \n" +
" <" + subjectUri + "> ?property ?object . \n" +
" ?property a owl:ObjectProperty . \n" +
" FILTER ( \n" +
" isURI(?object) && \n" +
PROPERTY_FILTERS + "\n" +
" ) \n" +
"}";
String queryString = subUriForQueryVar(OBJECT_PROPERTY_QUERY_STRING, "subject", subjectUri);
Query query = null;
try {
@ -900,6 +885,24 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp
}
return properties;
}
protected static final String LIST_VIEW_CONFIG_FILE_QUERY_STRING =
"PREFIX display: <http://vitro.mannlib.cornell.edu/ontologies/display/1.1#>" +
"SELECT ?property ?filename WHERE { \n" +
" ?property display:listViewConfigFile ?filename . \n" +
"}";
protected static Query listViewConfigFileQuery = null;
static {
try {
listViewConfigFileQuery = QueryFactory.create(LIST_VIEW_CONFIG_FILE_QUERY_STRING);
} catch(Throwable th){
log.error("could not create SPARQL query for LIST_VIEW_CONFIG_FILE_QUERY_STRING " + th.getMessage());
log.error(LIST_VIEW_CONFIG_FILE_QUERY_STRING);
}
}
Map<ObjectProperty, String> customListViewConfigFileMap = null;
@Override
public String getCustomListViewConfigFileName(ObjectProperty op) {

View file

@ -251,6 +251,14 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec
return 0;
}
/*
* SPARQL-based method for getting values related to a single object property.
* We cannot return a List<ObjectPropertyStatement> here, the way the corresponding method of
* DataPropertyStatementDaoJena returns a List<DataPropertyStatement>. We need to accomodate
* custom queries that could request any data in addition to just the object of the statement.
* However, we do need to get the object of the statement so that we have it to create editing links.
*/
@Override
public List<Map<String, String>> getObjectPropertyStatementsForIndividualByProperty(
String subjectUri,
@ -263,13 +271,6 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec
}
@Override
/*
* SPARQL-based method for getting values related to a single object property.
* We cannot return a List<ObjectPropertyStatement> here, the way the corresponding method of
* DataPropertyStatementDaoJena returns a List<DataPropertyStatement>. We need to accomodate
* custom queries that could request any data in addition to just the object of the statement.
* However, we do need to get the object of the statement so that we have it to create editing links.
*/
public List<Map<String, String>> getObjectPropertyStatementsForIndividualByProperty(
String subjectUri,
String propertyUri,
@ -315,7 +316,7 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec
while (results.hasNext()) {
QuerySolution soln = results.nextSolution();
RDFNode node = soln.get(objectKey);
if (node.isResource()) {
if (node.isURIResource()) {
list.add(QueryUtils.querySolutionToStringValueMap(soln));
}
}

View file

@ -53,12 +53,14 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao {
put("vitroPublic", VitroVocabulary.VITRO_PUBLIC);
}};
protected static String prefixes = "";
protected static final String PREFIXES;
static {
String prefixes = "";
for (String key : NAMESPACES.keySet()) {
prefixes += "PREFIX " + key + ": <" + NAMESPACES.get(key) + ">\n";
}
log.debug("Query prefixes: " + prefixes);
PREFIXES = prefixes;
log.debug("Query prefixes: " + PREFIXES);
}
protected DatasetWrapperFactory dwf;

View file

@ -109,7 +109,7 @@ public class GroupedPropertyList extends BaseTemplateModel {
}
// It's possible that a collated object property retrieved in the call to getPopulatedObjectPropertyList()
// It's possible that an object property retrieved in the call to getPopulatedObjectPropertyList()
// is now empty of statements, because if not editing, some statements without a linked individual
// are not retrieved by the query. (See <linked-individual-required> elements in queries.)
// Remove these properties, and also remove any groups with no remaining properties.