Faster implementation of TPF for SDB (#54)
* Initial performance improvements to TPF * Add faster counts for TPF * Correct end count * Bug fixes, use hashes for filtering * Initial LDF SPARQL client * Handle blank nodes correctly
This commit is contained in:
parent
0191ae6dbb
commit
b5da11c2be
17 changed files with 1446 additions and 112 deletions
|
@ -8,6 +8,7 @@ import java.util.List;
|
||||||
|
|
||||||
import org.apache.jena.rdf.model.Model;
|
import org.apache.jena.rdf.model.Model;
|
||||||
import org.apache.jena.rdf.model.ModelChangedListener;
|
import org.apache.jena.rdf.model.ModelChangedListener;
|
||||||
|
import org.apache.jena.rdf.model.RDFNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for API to write, read, and update Vitro's RDF store, with support
|
* Interface for API to write, read, and update Vitro's RDF store, with support
|
||||||
|
@ -249,6 +250,10 @@ public interface RDFService {
|
||||||
*/
|
*/
|
||||||
public ChangeSet manufactureChangeSet();
|
public ChangeSet manufactureChangeSet();
|
||||||
|
|
||||||
|
public long countTriples(RDFNode subject, RDFNode predicate, RDFNode object) throws RDFServiceException;
|
||||||
|
|
||||||
|
public Model getTriples(RDFNode subject, RDFNode predicate, RDFNode object, long limit, long offset) throws RDFServiceException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frees any resources held by this RDFService object
|
* Frees any resources held by this RDFService object
|
||||||
*
|
*
|
||||||
|
|
|
@ -468,6 +468,16 @@ public class LanguageFilteringRDFService implements RDFService {
|
||||||
return s.manufactureChangeSet();
|
return s.manufactureChangeSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countTriples(RDFNode subject, RDFNode predicate, RDFNode object) throws RDFServiceException {
|
||||||
|
return s.countTriples(subject, predicate, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model getTriples(RDFNode subject, RDFNode predicate, RDFNode object, long limit, long offset) throws RDFServiceException {
|
||||||
|
return s.getTriples(subject, predicate, object, limit, offset);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
s.close();
|
s.close();
|
||||||
|
|
|
@ -16,6 +16,7 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString;
|
import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString;
|
||||||
|
import org.apache.jena.rdf.model.RDFNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An RDFServiceFactory that always returns the same RDFService object
|
* An RDFServiceFactory that always returns the same RDFService object
|
||||||
|
@ -192,6 +193,16 @@ public class RDFServiceFactorySingle implements RDFServiceFactory {
|
||||||
return s.manufactureChangeSet();
|
return s.manufactureChangeSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countTriples(RDFNode subject, RDFNode predicate, RDFNode object) throws RDFServiceException {
|
||||||
|
return s.countTriples(subject, predicate, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model getTriples(RDFNode subject, RDFNode predicate, RDFNode object, long limit, long offset) throws RDFServiceException {
|
||||||
|
return s.getTriples(subject, predicate, object, limit, offset);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
// Don't close s. It's being used by everybody.
|
// Don't close s. It's being used by everybody.
|
||||||
|
|
|
@ -12,18 +12,24 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
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.jena.atlas.io.StringWriterI;
|
||||||
import org.apache.jena.graph.Node;
|
import org.apache.jena.graph.Node;
|
||||||
import org.apache.jena.graph.NodeFactory;
|
import org.apache.jena.graph.NodeFactory;
|
||||||
import org.apache.jena.graph.Triple;
|
import org.apache.jena.graph.Triple;
|
||||||
import org.apache.jena.query.Query;
|
import org.apache.jena.query.Query;
|
||||||
import org.apache.jena.query.QueryFactory;
|
import org.apache.jena.query.QueryFactory;
|
||||||
import org.apache.jena.query.QueryParseException;
|
import org.apache.jena.query.QueryParseException;
|
||||||
|
import org.apache.jena.query.QuerySolution;
|
||||||
import org.apache.jena.query.Syntax;
|
import org.apache.jena.query.Syntax;
|
||||||
|
import org.apache.jena.rdf.model.Literal;
|
||||||
import org.apache.jena.rdf.model.Model;
|
import org.apache.jena.rdf.model.Model;
|
||||||
import org.apache.jena.rdf.model.ModelChangedListener;
|
import org.apache.jena.rdf.model.ModelChangedListener;
|
||||||
import org.apache.jena.rdf.model.ModelFactory;
|
import org.apache.jena.rdf.model.ModelFactory;
|
||||||
|
import org.apache.jena.rdf.model.RDFNode;
|
||||||
import org.apache.jena.rdf.model.Statement;
|
import org.apache.jena.rdf.model.Statement;
|
||||||
import org.apache.jena.rdf.model.StmtIterator;
|
import org.apache.jena.rdf.model.StmtIterator;
|
||||||
|
import org.apache.jena.riot.out.NodeFormatter;
|
||||||
|
import org.apache.jena.riot.out.NodeFormatterTTL;
|
||||||
import org.apache.jena.vocabulary.RDF;
|
import org.apache.jena.vocabulary.RDF;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener;
|
||||||
|
@ -34,6 +40,7 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString;
|
import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString;
|
||||||
|
import org.vivoweb.linkeddatafragments.datasource.rdfservice.RDFServiceBasedRequestProcessorForTPFs;
|
||||||
|
|
||||||
public abstract class RDFServiceImpl implements RDFService {
|
public abstract class RDFServiceImpl implements RDFService {
|
||||||
|
|
||||||
|
@ -341,4 +348,120 @@ public abstract class RDFServiceImpl implements RDFService {
|
||||||
return ToString.simpleName(this) + "[" + ToString.hashHex(this) + "]";
|
return ToString.simpleName(this) + "[" + ToString.hashHex(this) + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countTriples(RDFNode subject, RDFNode predicate, RDFNode object) throws RDFServiceException {
|
||||||
|
StringBuilder whereClause = new StringBuilder();
|
||||||
|
StringBuilder orderBy = new StringBuilder();
|
||||||
|
|
||||||
|
if ( subject != null ) {
|
||||||
|
appendNode(whereClause.append(' '), subject);
|
||||||
|
} else {
|
||||||
|
whereClause.append(" ?s");
|
||||||
|
orderBy.append(" ?s");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( predicate != null ) {
|
||||||
|
appendNode(whereClause.append(' '), predicate);
|
||||||
|
} else {
|
||||||
|
whereClause.append(" ?p");
|
||||||
|
orderBy.append(" ?p");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( object != null ) {
|
||||||
|
appendNode(whereClause.append(' '), object);
|
||||||
|
} else {
|
||||||
|
whereClause.append(" ?o");
|
||||||
|
orderBy.append(" ?o");
|
||||||
|
}
|
||||||
|
|
||||||
|
long estimate = -1;
|
||||||
|
|
||||||
|
StringBuilder count = new StringBuilder();
|
||||||
|
count.append("SELECT (COUNT(*) AS ?count) WHERE { ");
|
||||||
|
count.append(whereClause.toString());
|
||||||
|
count.append(" . ");
|
||||||
|
count.append(" }");
|
||||||
|
CountConsumer countConsumer = new CountConsumer();
|
||||||
|
this.sparqlSelectQuery(count.toString(), countConsumer);
|
||||||
|
return countConsumer.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model getTriples(RDFNode subject, RDFNode predicate, RDFNode object, long limit, long offset) throws RDFServiceException {
|
||||||
|
StringBuilder whereClause = new StringBuilder();
|
||||||
|
StringBuilder orderBy = new StringBuilder();
|
||||||
|
|
||||||
|
if ( subject != null ) {
|
||||||
|
appendNode(whereClause.append(' '), subject);
|
||||||
|
} else {
|
||||||
|
whereClause.append(" ?s");
|
||||||
|
orderBy.append(" ?s");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( predicate != null ) {
|
||||||
|
appendNode(whereClause.append(' '), predicate);
|
||||||
|
} else {
|
||||||
|
whereClause.append(" ?p");
|
||||||
|
orderBy.append(" ?p");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( object != null ) {
|
||||||
|
appendNode(whereClause.append(' '), object);
|
||||||
|
} else {
|
||||||
|
whereClause.append(" ?o");
|
||||||
|
orderBy.append(" ?o");
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder constructQuery = new StringBuilder();
|
||||||
|
|
||||||
|
constructQuery.append("CONSTRUCT { ");
|
||||||
|
constructQuery.append(whereClause.toString());
|
||||||
|
constructQuery.append(" } WHERE { ");
|
||||||
|
constructQuery.append(whereClause.toString()).append(" . ");
|
||||||
|
constructQuery.append(" }");
|
||||||
|
|
||||||
|
if (orderBy.length() > 0) {
|
||||||
|
constructQuery.append(" ORDER BY").append(orderBy.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (limit > 0) {
|
||||||
|
constructQuery.append(" LIMIT ").append(limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset > 0) {
|
||||||
|
constructQuery.append(" OFFSET ").append(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
Model triples = ModelFactory.createDefaultModel();
|
||||||
|
this.sparqlConstructQuery(constructQuery.toString(), triples);
|
||||||
|
|
||||||
|
return triples;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendNode(StringBuilder builder, RDFNode node) {
|
||||||
|
if (node.isLiteral()) {
|
||||||
|
builder.append(literalToString(node.asLiteral()));
|
||||||
|
} else if (node.isURIResource()) {
|
||||||
|
builder.append('<' + node.asResource().getURI() + '>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String literalToString(Literal l) {
|
||||||
|
StringWriterI sw = new StringWriterI();
|
||||||
|
NodeFormatter fmt = new NodeFormatterTTL(null, null);
|
||||||
|
fmt.formatLiteral(sw, l.asNode());
|
||||||
|
return sw.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
class CountConsumer extends ResultSetConsumer {
|
||||||
|
public long count = -1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processQuerySolution(QuerySolution qs) {
|
||||||
|
if (count == -1) {
|
||||||
|
Literal literal = qs.getLiteral("count");
|
||||||
|
count = literal.getLong();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,9 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
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.jena.query.QuerySolutionMap;
|
||||||
|
import org.apache.jena.query.Syntax;
|
||||||
|
import org.apache.jena.rdf.model.Literal;
|
||||||
import org.apache.jena.riot.RDFDataMgr;
|
import org.apache.jena.riot.RDFDataMgr;
|
||||||
import org.apache.log4j.lf5.util.StreamUtils;
|
import org.apache.log4j.lf5.util.StreamUtils;
|
||||||
|
|
||||||
|
@ -612,6 +615,71 @@ public abstract class RDFServiceJena extends RDFServiceImpl implements RDFServic
|
||||||
return graph.isIsomorphicWith(fromTripleStoreModel);
|
return graph.isIsomorphicWith(fromTripleStoreModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countTriples(RDFNode subject, RDFNode predicate, RDFNode object) throws RDFServiceException {
|
||||||
|
Query countQuery = QueryFactory.create("SELECT (COUNT(?s) AS ?count) WHERE { ?s ?p ?o } ORDER BY ?s ?p ?o", Syntax.syntaxSPARQL_11);
|
||||||
|
QuerySolutionMap map = new QuerySolutionMap();
|
||||||
|
if ( subject != null ) {
|
||||||
|
map.add("s", subject);
|
||||||
|
}
|
||||||
|
if ( predicate != null ) {
|
||||||
|
map.add("p", predicate);
|
||||||
|
}
|
||||||
|
if ( object != null ) {
|
||||||
|
map.add("o", object);
|
||||||
|
}
|
||||||
|
|
||||||
|
DatasetWrapper dw = getDatasetWrapper();
|
||||||
|
try {
|
||||||
|
Dataset d = dw.getDataset();
|
||||||
|
try (QueryExecution qexec = QueryExecutionFactory.create(countQuery, d, map)) {
|
||||||
|
ResultSet results = qexec.execSelect();
|
||||||
|
if (results.hasNext()) {
|
||||||
|
QuerySolution soln = results.nextSolution() ;
|
||||||
|
Literal literal = soln.getLiteral("count");
|
||||||
|
return literal.getLong();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
dw.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model getTriples(RDFNode subject, RDFNode predicate, RDFNode object, long limit, long offset) throws RDFServiceException {
|
||||||
|
Query query = QueryFactory.create("CONSTRUCT WHERE { ?s ?p ?o }", Syntax.syntaxSPARQL_11);
|
||||||
|
QuerySolutionMap map = new QuerySolutionMap();
|
||||||
|
if ( subject != null ) {
|
||||||
|
map.add("s", subject);
|
||||||
|
}
|
||||||
|
if ( predicate != null ) {
|
||||||
|
map.add("p", predicate);
|
||||||
|
}
|
||||||
|
if ( object != null ) {
|
||||||
|
map.add("o", object);
|
||||||
|
}
|
||||||
|
|
||||||
|
query.setOffset(offset);
|
||||||
|
query.setLimit(limit);
|
||||||
|
|
||||||
|
Model triples = ModelFactory.createDefaultModel();
|
||||||
|
|
||||||
|
DatasetWrapper dw = getDatasetWrapper();
|
||||||
|
try {
|
||||||
|
Dataset d = dw.getDataset();
|
||||||
|
try (QueryExecution qexec = QueryExecutionFactory.create(query, d, map)) {
|
||||||
|
qexec.execConstruct(triples);
|
||||||
|
}
|
||||||
|
|
||||||
|
return triples;
|
||||||
|
} finally {
|
||||||
|
dw.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
// nothing
|
// nothing
|
||||||
|
@ -620,5 +688,4 @@ public abstract class RDFServiceJena extends RDFServiceImpl implements RDFServic
|
||||||
protected QueryExecution createQueryExecution(String queryString, Query q, Dataset d) {
|
protected QueryExecution createQueryExecution(String queryString, Query q, Dataset d) {
|
||||||
return QueryExecutionFactory.create(q, d);
|
return QueryExecutionFactory.create(q, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,20 +4,34 @@ package edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.sdb;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.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.jena.datatypes.RDFDatatype;
|
||||||
|
import org.apache.jena.datatypes.TypeMapper;
|
||||||
|
import org.apache.jena.datatypes.xsd.XSDDatatype;
|
||||||
|
import org.apache.jena.graph.Node;
|
||||||
|
import org.apache.jena.graph.NodeFactory;
|
||||||
|
import org.apache.jena.graph.Triple;
|
||||||
import org.apache.jena.query.Dataset;
|
import org.apache.jena.query.Dataset;
|
||||||
import org.apache.jena.query.Query;
|
import org.apache.jena.query.Query;
|
||||||
import org.apache.jena.query.QueryExecution;
|
import org.apache.jena.query.QueryExecution;
|
||||||
import org.apache.jena.query.QueryExecutionFactory;
|
import org.apache.jena.query.QueryExecutionFactory;
|
||||||
|
import org.apache.jena.rdf.model.Model;
|
||||||
|
import org.apache.jena.rdf.model.ModelFactory;
|
||||||
|
import org.apache.jena.rdf.model.RDFNode;
|
||||||
import org.apache.jena.sdb.SDBFactory;
|
import org.apache.jena.sdb.SDBFactory;
|
||||||
import org.apache.jena.sdb.Store;
|
import org.apache.jena.sdb.Store;
|
||||||
import org.apache.jena.sdb.StoreDesc;
|
import org.apache.jena.sdb.StoreDesc;
|
||||||
|
import org.apache.jena.sdb.layout2.NodeLayout2;
|
||||||
|
import org.apache.jena.sdb.layout2.ValueType;
|
||||||
import org.apache.jena.sdb.sql.SDBConnection;
|
import org.apache.jena.sdb.sql.SDBConnection;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.DatasetWrapper;
|
import edu.cornell.mannlib.vitro.webapp.dao.jena.DatasetWrapper;
|
||||||
|
@ -28,6 +42,8 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet;
|
||||||
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.RDFServiceException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.RDFServiceJena;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.RDFServiceJena;
|
||||||
|
import org.apache.jena.sdb.store.DatabaseType;
|
||||||
|
import org.apache.jena.sdb.store.LayoutType;
|
||||||
|
|
||||||
public class RDFServiceSDB extends RDFServiceJena implements RDFService {
|
public class RDFServiceSDB extends RDFServiceJena implements RDFService {
|
||||||
|
|
||||||
|
@ -148,6 +164,116 @@ public class RDFServiceSDB extends RDFServiceJena implements RDFService {
|
||||||
// However, in recent Jena this turns out to be much slower than executing against the dataset directly
|
// However, in recent Jena this turns out to be much slower than executing against the dataset directly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countTriples(RDFNode subject, RDFNode predicate, RDFNode object) throws RDFServiceException {
|
||||||
|
if (LayoutType.LayoutTripleNodesHash.equals(storeDesc.getLayout())) {
|
||||||
|
if (DatabaseType.MySQL.equals(storeDesc.getDbType()) ||
|
||||||
|
DatabaseType.PostgreSQL.equals(storeDesc.getDbType())) {
|
||||||
|
SDBConnection sdbConn = getSDBConnection();
|
||||||
|
try {
|
||||||
|
String whereClause = makeWhereClause(subject, predicate, object);
|
||||||
|
Statement stmt = sdbConn.getSqlConnection().createStatement();
|
||||||
|
ResultSet rs = stmt.executeQuery("SELECT count(DISTINCT s,p,o) AS tcount FROM Quads" + (StringUtils.isEmpty(whereClause) ? "" : " WHERE " + whereClause));
|
||||||
|
try {
|
||||||
|
while (rs.next()) {
|
||||||
|
return rs.getLong("tcount");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
rs.close();
|
||||||
|
}
|
||||||
|
} catch (SQLException sqle) {
|
||||||
|
throw new RDFServiceException("Unable to retrieve triples", sqle);
|
||||||
|
} finally {
|
||||||
|
close(sdbConn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return super.countTriples(subject, predicate, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.countTriples(subject, predicate, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model getTriples(RDFNode subject, RDFNode predicate, RDFNode object, long limit, long offset) throws RDFServiceException {
|
||||||
|
if (LayoutType.LayoutTripleNodesHash.equals(storeDesc.getLayout())) {
|
||||||
|
if (DatabaseType.MySQL.equals(storeDesc.getDbType()) ||
|
||||||
|
DatabaseType.PostgreSQL.equals(storeDesc.getDbType())) {
|
||||||
|
Model triples = ModelFactory.createDefaultModel();
|
||||||
|
|
||||||
|
SDBConnection sdbConn = getSDBConnection();
|
||||||
|
try {
|
||||||
|
String whereClause = makeWhereClause(subject, predicate, object);
|
||||||
|
Statement stmt = sdbConn.getSqlConnection().createStatement();
|
||||||
|
ResultSet rs = stmt.executeQuery("SELECT \n" +
|
||||||
|
"N1.lex AS s_lex,\n" +
|
||||||
|
"N1.lang AS s_lang,\n" +
|
||||||
|
"N1.datatype AS s_datatype,\n" +
|
||||||
|
"N1.type AS s_type,\n" +
|
||||||
|
"N2.lex AS p_lex,\n" +
|
||||||
|
"N2.lang AS p_lang,\n" +
|
||||||
|
"N2.datatype AS p_datatype,\n" +
|
||||||
|
"N2.type AS p_type,\n" +
|
||||||
|
"N3.lex AS o_lex,\n" +
|
||||||
|
"N3.lang AS o_lang,\n" +
|
||||||
|
"N3.datatype AS o_datatype,\n" +
|
||||||
|
"N3.type AS o_type\n" +
|
||||||
|
"FROM\n" +
|
||||||
|
"(SELECT DISTINCT s,p,o FROM Quads" +
|
||||||
|
(StringUtils.isEmpty(whereClause) ? "" : " WHERE " + whereClause) +
|
||||||
|
" ORDER BY s,p,o " +
|
||||||
|
(limit > 0 ? "LIMIT " + limit : "") +
|
||||||
|
(offset > 0 ? " OFFSET " + offset : "") + ") Q\n" +
|
||||||
|
"LEFT OUTER JOIN\n" +
|
||||||
|
"\tNodes AS N1\n" +
|
||||||
|
"ON ( Q.s = N1.hash )\n" +
|
||||||
|
"LEFT OUTER JOIN\n" +
|
||||||
|
"\tNodes AS N2\n" +
|
||||||
|
"ON ( Q.p = N2.hash )\n" +
|
||||||
|
"LEFT OUTER JOIN\n" +
|
||||||
|
"\tNodes AS N3\n" +
|
||||||
|
"ON ( Q.o = N3.hash )");
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (rs.next()) {
|
||||||
|
Node subjectNode = makeNode(
|
||||||
|
rs.getString("s_lex"),
|
||||||
|
rs.getString("s_datatype"),
|
||||||
|
rs.getString("s_lang"),
|
||||||
|
ValueType.lookup(rs.getInt("s_type")));
|
||||||
|
|
||||||
|
Node predicateNode = makeNode(
|
||||||
|
rs.getString("p_lex"),
|
||||||
|
rs.getString("p_datatype"),
|
||||||
|
rs.getString("p_lang"),
|
||||||
|
ValueType.lookup(rs.getInt("p_type")));
|
||||||
|
|
||||||
|
Node objectNode = makeNode(
|
||||||
|
rs.getString("o_lex"),
|
||||||
|
rs.getString("o_datatype"),
|
||||||
|
rs.getString("o_lang"),
|
||||||
|
ValueType.lookup(rs.getInt("o_type")));
|
||||||
|
|
||||||
|
triples.add(
|
||||||
|
triples.asStatement(Triple.create(subjectNode, predicateNode, objectNode))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
rs.close();
|
||||||
|
}
|
||||||
|
} catch (SQLException sqle) {
|
||||||
|
throw new RDFServiceException("Unable to retrieve triples", sqle);
|
||||||
|
} finally {
|
||||||
|
close(sdbConn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return triples;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getTriples(subject, predicate, object, limit, offset);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
if (conn != null) {
|
if (conn != null) {
|
||||||
|
@ -159,4 +285,55 @@ public class RDFServiceSDB extends RDFServiceJena implements RDFService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copied from Jena SQLBridge2
|
||||||
|
private static Node makeNode(String lex, String datatype, String lang, ValueType vType) {
|
||||||
|
switch(vType) {
|
||||||
|
case BNODE:
|
||||||
|
return NodeFactory.createBlankNode(lex);
|
||||||
|
case URI:
|
||||||
|
return NodeFactory.createURI(lex);
|
||||||
|
case STRING:
|
||||||
|
return NodeFactory.createLiteral(lex, lang);
|
||||||
|
case XSDSTRING:
|
||||||
|
return NodeFactory.createLiteral(lex, XSDDatatype.XSDstring);
|
||||||
|
case INTEGER:
|
||||||
|
return NodeFactory.createLiteral(lex, XSDDatatype.XSDinteger);
|
||||||
|
case DOUBLE:
|
||||||
|
return NodeFactory.createLiteral(lex, XSDDatatype.XSDdouble);
|
||||||
|
case DATETIME:
|
||||||
|
return NodeFactory.createLiteral(lex, XSDDatatype.XSDdateTime);
|
||||||
|
case OTHER:
|
||||||
|
RDFDatatype dt = TypeMapper.getInstance().getSafeTypeByName(datatype);
|
||||||
|
return NodeFactory.createLiteral(lex, dt);
|
||||||
|
default:
|
||||||
|
log.warn("Unrecognized: (" + lex + ", " + lang + ", " + vType + ")");
|
||||||
|
return NodeFactory.createLiteral("UNRECOGNIZED");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String makeWhereClause(RDFNode subject, RDFNode predicate, RDFNode object) {
|
||||||
|
StringBuilder whereClause = new StringBuilder();
|
||||||
|
if (subject != null) {
|
||||||
|
if (whereClause.length() > 0) {
|
||||||
|
whereClause.append(" AND ");
|
||||||
|
}
|
||||||
|
whereClause.append("s=").append(NodeLayout2.hash(subject.asNode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (predicate != null) {
|
||||||
|
if (whereClause.length() > 0) {
|
||||||
|
whereClause.append(" AND ");
|
||||||
|
}
|
||||||
|
whereClause.append("p=").append(NodeLayout2.hash(predicate.asNode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object != null) {
|
||||||
|
if (whereClause.length() > 0) {
|
||||||
|
whereClause.append(" AND ");
|
||||||
|
}
|
||||||
|
whereClause.append("o=").append(NodeLayout2.hash(object.asNode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return whereClause.length() > 0 ? whereClause.toString() : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet;
|
||||||
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.RDFServiceException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
||||||
|
import org.apache.jena.rdf.model.RDFNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This RDFService wrapper adds instrumentation to the time-consuming methods of
|
* This RDFService wrapper adds instrumentation to the time-consuming methods of
|
||||||
|
@ -182,6 +183,16 @@ public class LoggingRDFService implements RDFService {
|
||||||
return innerService.manufactureChangeSet();
|
return innerService.manufactureChangeSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countTriples(RDFNode subject, RDFNode predicate, RDFNode object) throws RDFServiceException {
|
||||||
|
return innerService.countTriples(subject, predicate, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model getTriples(RDFNode subject, RDFNode predicate, RDFNode object, long limit, long offset) throws RDFServiceException {
|
||||||
|
return innerService.getTriples(subject, predicate, object, limit, offset);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
innerService.close();
|
innerService.close();
|
||||||
|
|
|
@ -106,7 +106,7 @@ public class HtmlTriplePatternFragmentWriterImpl extends TriplePatternFragmentWr
|
||||||
// Calculate start and end triple number
|
// Calculate start and end triple number
|
||||||
Long start = ((tpfRequest.getPageNumber() - 1) * fragment.getMaxPageSize()) + 1;
|
Long start = ((tpfRequest.getPageNumber() - 1) * fragment.getMaxPageSize()) + 1;
|
||||||
data.put("start", start);
|
data.put("start", start);
|
||||||
data.put("end", start + (triples.size() < fragment.getMaxPageSize() ? triples.size() : fragment.getMaxPageSize()));
|
data.put("end", (start - 1) + (triples.size() < fragment.getMaxPageSize() ? triples.size() : fragment.getMaxPageSize()));
|
||||||
|
|
||||||
// Compose query object
|
// Compose query object
|
||||||
Map query = new HashMap();
|
Map query = new HashMap();
|
||||||
|
|
|
@ -6,6 +6,9 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
||||||
import org.apache.jena.atlas.io.StringWriterI;
|
import org.apache.jena.atlas.io.StringWriterI;
|
||||||
|
import org.apache.jena.graph.Node;
|
||||||
|
import org.apache.jena.graph.NodeFactory;
|
||||||
|
import org.apache.jena.graph.Triple;
|
||||||
import org.apache.jena.query.Dataset;
|
import org.apache.jena.query.Dataset;
|
||||||
import org.apache.jena.query.Query;
|
import org.apache.jena.query.Query;
|
||||||
import org.apache.jena.query.QueryExecution;
|
import org.apache.jena.query.QueryExecution;
|
||||||
|
@ -19,6 +22,8 @@ import org.apache.jena.rdf.model.Literal;
|
||||||
import org.apache.jena.rdf.model.Model;
|
import org.apache.jena.rdf.model.Model;
|
||||||
import org.apache.jena.rdf.model.ModelFactory;
|
import org.apache.jena.rdf.model.ModelFactory;
|
||||||
import org.apache.jena.rdf.model.RDFNode;
|
import org.apache.jena.rdf.model.RDFNode;
|
||||||
|
import org.apache.jena.rdf.model.Statement;
|
||||||
|
import org.apache.jena.rdf.model.StmtIterator;
|
||||||
import org.apache.jena.riot.out.NodeFormatter;
|
import org.apache.jena.riot.out.NodeFormatter;
|
||||||
import org.apache.jena.riot.out.NodeFormatterTTL;
|
import org.apache.jena.riot.out.NodeFormatterTTL;
|
||||||
import org.apache.jena.tdb.TDBFactory;
|
import org.apache.jena.tdb.TDBFactory;
|
||||||
|
@ -74,6 +79,32 @@ public class RDFServiceBasedRequestProcessorForTPFs
|
||||||
return sw.toString();
|
return sw.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Node skolemize(Node node) {
|
||||||
|
if (node != null && node.isBlank()) {
|
||||||
|
return NodeFactory.createURI("bnode://" + node.getBlankNodeLabel());
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RDFNode deskolemize(RDFNode node) {
|
||||||
|
if (node == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.isResource()) {
|
||||||
|
String uri = node.asResource().getURI();
|
||||||
|
if (uri != null && uri.startsWith("bnode://")) {
|
||||||
|
String bnodeId = uri.substring(8);
|
||||||
|
return ModelFactory.createDefaultModel().asRDFNode(
|
||||||
|
NodeFactory.createBlankNode(bnodeId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ILinkedDataFragment createFragment(
|
protected ILinkedDataFragment createFragment(
|
||||||
final ITriplePatternElement<RDFNode,String,String> subject,
|
final ITriplePatternElement<RDFNode,String,String> subject,
|
||||||
|
@ -82,100 +113,51 @@ public class RDFServiceBasedRequestProcessorForTPFs
|
||||||
final long offset,
|
final long offset,
|
||||||
final long limit )
|
final long limit )
|
||||||
{
|
{
|
||||||
StringBuilder whereClause = new StringBuilder();
|
|
||||||
StringBuilder filter = new StringBuilder();
|
|
||||||
StringBuilder orderBy = new StringBuilder();
|
|
||||||
|
|
||||||
if ( ! subject.isVariable() ) {
|
|
||||||
appendNode(whereClause.append(' '), subject.asConstantTerm());
|
|
||||||
} else {
|
|
||||||
whereClause.append(" ?s");
|
|
||||||
if (filter.length() > 0) { filter.append(" && "); }
|
|
||||||
filter.append("!isBlank(?s)");
|
|
||||||
orderBy.append(" ?s");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! predicate.isVariable() ) {
|
|
||||||
appendNode(whereClause.append(' '), predicate.asConstantTerm());
|
|
||||||
} else {
|
|
||||||
whereClause.append(" ?p");
|
|
||||||
if (filter.length() > 0) { filter.append(" && "); }
|
|
||||||
filter.append("!isBlank(?p)");
|
|
||||||
orderBy.append(" ?p");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! object.isVariable() ) {
|
|
||||||
appendNode(whereClause.append(' '), object.asConstantTerm());
|
|
||||||
} else {
|
|
||||||
whereClause.append(" ?o");
|
|
||||||
if (filter.length() > 0) { filter.append(" && "); }
|
|
||||||
filter.append("!isBlank(?o)");
|
|
||||||
orderBy.append(" ?o");
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder constructQuery = new StringBuilder();
|
|
||||||
|
|
||||||
constructQuery.append("CONSTRUCT { ");
|
|
||||||
constructQuery.append(whereClause.toString());
|
|
||||||
constructQuery.append(" } WHERE { ");
|
|
||||||
constructQuery.append(whereClause.toString()).append(" . ");
|
|
||||||
if (filter.length() > 0) {
|
|
||||||
constructQuery.append(" FILTER(").append(filter.toString()).append(")");
|
|
||||||
}
|
|
||||||
constructQuery.append(" }");
|
|
||||||
|
|
||||||
if (orderBy.length() > 0) {
|
|
||||||
constructQuery.append(" ORDER BY").append(orderBy.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (limit > 0) {
|
|
||||||
constructQuery.append(" LIMIT ").append(limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset > 0) {
|
|
||||||
constructQuery.append(" OFFSET ").append(offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
Model triples = ModelFactory.createDefaultModel();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
rdfService.sparqlConstructQuery(constructQuery.toString(), triples);
|
RDFNode nSubject = subject.isVariable() ? null : deskolemize(subject.asConstantTerm());
|
||||||
|
RDFNode nPredicate = predicate.isVariable() ? null : deskolemize(predicate.asConstantTerm());
|
||||||
|
RDFNode nObject = object.isVariable() ? null : deskolemize(object.asConstantTerm());
|
||||||
|
|
||||||
|
Model triples = rdfService.getTriples(nSubject, nPredicate, nObject, limit, offset);
|
||||||
|
if (triples == null || triples.isEmpty()) {
|
||||||
|
return createEmptyTriplePatternFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triples.size() > 0) {
|
||||||
|
Model replacedBlankNodes = ModelFactory.createDefaultModel();
|
||||||
|
StmtIterator iter = triples.listStatements();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Statement oldStmt = iter.next();
|
||||||
|
Triple t = oldStmt.asTriple();
|
||||||
|
replacedBlankNodes.add(
|
||||||
|
replacedBlankNodes.asStatement(
|
||||||
|
new Triple(
|
||||||
|
skolemize(t.getSubject()),
|
||||||
|
skolemize(t.getPredicate()),
|
||||||
|
skolemize(t.getObject())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
triples = replacedBlankNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
long size = triples.size();
|
||||||
|
long estimate = -1;
|
||||||
|
estimate = rdfService.countTriples(nSubject, nPredicate, nObject);
|
||||||
|
|
||||||
|
// No estimate or incorrect
|
||||||
|
if (estimate < offset + size) {
|
||||||
|
estimate = (size == limit) ? offset + size + 1 : offset + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the fragment
|
||||||
|
final boolean isLastPage = ( estimate < offset + limit );
|
||||||
|
return createTriplePatternFragment( triples, estimate, isLastPage );
|
||||||
} catch (RDFServiceException e) {
|
} catch (RDFServiceException e) {
|
||||||
return createEmptyTriplePatternFragment();
|
return createEmptyTriplePatternFragment();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (triples.isEmpty()) {
|
|
||||||
return createEmptyTriplePatternFragment();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to get an estimate
|
|
||||||
long size = triples.size();
|
|
||||||
long estimate = -1;
|
|
||||||
|
|
||||||
StringBuilder count = new StringBuilder();
|
|
||||||
count.append("SELECT (COUNT(*) AS ?count) WHERE { ");
|
|
||||||
count.append(whereClause.toString());
|
|
||||||
count.append(" . ");
|
|
||||||
if (filter.length() > 0) {
|
|
||||||
count.append(" FILTER(").append(filter.toString()).append(") ");
|
|
||||||
}
|
|
||||||
count.append(" }");
|
|
||||||
try {
|
|
||||||
CountConsumer countConsumer = new CountConsumer();
|
|
||||||
rdfService.sparqlSelectQuery(count.toString(), countConsumer);
|
|
||||||
estimate = countConsumer.estimate;
|
|
||||||
} catch (RDFServiceException e) {
|
|
||||||
return createEmptyTriplePatternFragment();
|
|
||||||
}
|
|
||||||
|
|
||||||
// No estimate or incorrect
|
|
||||||
if (estimate < offset + size) {
|
|
||||||
estimate = (size == limit) ? offset + size + 1 : offset + size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the fragment
|
|
||||||
final boolean isLastPage = ( estimate < offset + limit );
|
|
||||||
return createTriplePatternFragment( triples, estimate, isLastPage );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of class Worker
|
} // end of class Worker
|
||||||
|
@ -186,16 +168,4 @@ public class RDFServiceBasedRequestProcessorForTPFs
|
||||||
*/
|
*/
|
||||||
public RDFServiceBasedRequestProcessorForTPFs() {
|
public RDFServiceBasedRequestProcessorForTPFs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
class CountConsumer extends ResultSetConsumer {
|
|
||||||
public long estimate = -1;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void processQuerySolution(QuerySolution qs) {
|
|
||||||
if (estimate == -1) {
|
|
||||||
Literal literal = qs.getLiteral("count");
|
|
||||||
estimate = literal.getLong();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ public class HtmlTriplePatternFragmentWriterImpl extends TriplePatternFragmentWr
|
||||||
// Calculate start and end triple number
|
// Calculate start and end triple number
|
||||||
Long start = ((tpfRequest.getPageNumber() - 1) * fragment.getMaxPageSize()) + 1;
|
Long start = ((tpfRequest.getPageNumber() - 1) * fragment.getMaxPageSize()) + 1;
|
||||||
data.put("start", start);
|
data.put("start", start);
|
||||||
data.put("end", start + (triples.size() < fragment.getMaxPageSize() ? triples.size() : fragment.getMaxPageSize()));
|
data.put("end", (start - 1) + (triples.size() < fragment.getMaxPageSize() ? triples.size() : fragment.getMaxPageSize()));
|
||||||
|
|
||||||
// Compose query object
|
// Compose query object
|
||||||
Map query = new HashMap();
|
Map query = new HashMap();
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,549 @@
|
||||||
|
/*! @license MIT ©2014–2016 Ruben Verborgh, Ghent University – imec */
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 11pt;
|
||||||
|
background: #f6f6f6;
|
||||||
|
}
|
||||||
|
html, input, textarea, button, pre {
|
||||||
|
font: 1em/1.4 'Open Sans', Verdana, Arial, sans-serif;
|
||||||
|
-webkit-text-size-adjust: none;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
max-width: 650px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 1em 3em;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 2px 2px 15px 0px rgba(50, 50, 50, 0.75);
|
||||||
|
}
|
||||||
|
|
||||||
|
a, button, label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
a, button, input:hover, label {
|
||||||
|
color: #be1622;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: #be1622;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-weight: bold;
|
||||||
|
color: black;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
border: 1px solid #999999;
|
||||||
|
border-radius: 3px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 5px 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
background-color: #ececec;
|
||||||
|
}
|
||||||
|
button:active {
|
||||||
|
margin: 1px -1px -1px 1px;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
padding: 1px 5px;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
label:after {
|
||||||
|
content: ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1 {
|
||||||
|
margin: .3em 0 .1em;
|
||||||
|
font-size: 1.95em;
|
||||||
|
}
|
||||||
|
header p {
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0 0 1.5em;
|
||||||
|
}
|
||||||
|
header a {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
header .logo {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
header img {
|
||||||
|
margin: -9px -11px 0 0;
|
||||||
|
height: 81px;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.ldf-client, .ldf-client * {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
fieldset > ul > li {
|
||||||
|
margin: .3em 0;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
fieldset > ul > li:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
width: 430px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timing {
|
||||||
|
float: right;
|
||||||
|
font-size: 10pt;
|
||||||
|
padding: .7em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chosen {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.datetime {
|
||||||
|
float: right;
|
||||||
|
font-size: 13px;
|
||||||
|
border: 1px solid #999999;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.details-toggle {
|
||||||
|
display: block;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
margin: 0 -35px;
|
||||||
|
float: right;
|
||||||
|
cursor: pointer;
|
||||||
|
background: url(../images/memento.svg) no-repeat center center / contain;
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
.details-toggle:hover, .details-toggle.enabled {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.details-toggle.enabled {
|
||||||
|
background-image: url(../images/memento.svg#active);
|
||||||
|
width: 25px; /* for Chrome */
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
box-sizing: border-box;
|
||||||
|
min-height: 11em;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 1em;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: .95em;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results {
|
||||||
|
height: 23.5em;
|
||||||
|
font-size: 10pt;
|
||||||
|
margin: .5em 0 1em;
|
||||||
|
}
|
||||||
|
.results a {
|
||||||
|
font-weight: normal;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
.result {
|
||||||
|
width: calc(100% - 2px);
|
||||||
|
}
|
||||||
|
.result dl {
|
||||||
|
border: 1px solid #be1622;
|
||||||
|
margin: 0 0 1em;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.result dl:hover {
|
||||||
|
color: white;
|
||||||
|
background-color: #be1622;
|
||||||
|
}
|
||||||
|
.result dl:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.result dt {
|
||||||
|
float: left;
|
||||||
|
clear: left;
|
||||||
|
background-color: #be1622;
|
||||||
|
color: white;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0 .5em;
|
||||||
|
margin: 0 .5em 0 0;
|
||||||
|
}
|
||||||
|
.result dd {
|
||||||
|
margin: 0 .5em 0 1em;
|
||||||
|
}
|
||||||
|
.result dt:last-of-type {
|
||||||
|
border-radius: 0 0 0 5px;
|
||||||
|
}
|
||||||
|
.results .text {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
margin-right: -999999px; /* avoid that long URLs alter body width */
|
||||||
|
}
|
||||||
|
|
||||||
|
.log {
|
||||||
|
color: #666;
|
||||||
|
height: 6.3em;
|
||||||
|
font-size: 9pt;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: .5em -999999px 1em 0;
|
||||||
|
}
|
||||||
|
.log p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.log a {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results, .log {
|
||||||
|
width: 100%;
|
||||||
|
overflow: scroll;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
position: relative;
|
||||||
|
contain: layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
font-size: .8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 725px) {
|
||||||
|
body {
|
||||||
|
padding: .1em 1em;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 1.4em;
|
||||||
|
}
|
||||||
|
header img {
|
||||||
|
height: 70px;
|
||||||
|
}
|
||||||
|
header p {
|
||||||
|
margin: 0 0 .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
width: 350px;
|
||||||
|
}
|
||||||
|
.chosen, input.datetime {
|
||||||
|
float: none;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.details-toggle {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 0 -8px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log {
|
||||||
|
max-width: 90%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 550px) {
|
||||||
|
h1 {
|
||||||
|
ine-height: 1.2;
|
||||||
|
}
|
||||||
|
header p, .logo {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Styling below derived from
|
||||||
|
* Chosen, a Select Box Enhancer for jQuery and Prototype
|
||||||
|
* by Patrick Filler for Harvest, http://getharvest.com
|
||||||
|
*
|
||||||
|
* Version 1.4.2
|
||||||
|
* Full source at https://github.com/harvesthq/chosen
|
||||||
|
* Copyright (c) 2011-2015 Harvest http://getharvest.com
|
||||||
|
*
|
||||||
|
* MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
.chosen {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-size: 13px;
|
||||||
|
zoom: 1;
|
||||||
|
*display: inline;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.chosen * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.chosen .chosen-drop {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: -9999px;
|
||||||
|
z-index: 1010;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid #999999;
|
||||||
|
border-top: 0;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.chosen.chosen-with-drop .chosen-drop {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.chosen a {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.chosen-single .chosen-single {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0 0 0 8px;
|
||||||
|
height: 25px;
|
||||||
|
border: 1px solid #999999;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
line-height: 24px;
|
||||||
|
font-weight: normal;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
.chosen-single .chosen-single span {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-right: 26px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.chosen-single .chosen-single-with-deselect span {
|
||||||
|
margin-right: 38px;
|
||||||
|
}
|
||||||
|
.chosen-single .chosen-single abbr {
|
||||||
|
position: absolute;
|
||||||
|
top: 6px;
|
||||||
|
right: 26px;
|
||||||
|
display: block;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
background: url('../images/chosen-sprite.png') -42px 1px no-repeat;
|
||||||
|
font-size: 1px;
|
||||||
|
}
|
||||||
|
.chosen-single .chosen-single abbr:hover {
|
||||||
|
background-position: -42px -10px;
|
||||||
|
}
|
||||||
|
.chosen-single .chosen-single div {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
display: block;
|
||||||
|
width: 18px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.chosen-single .chosen-single div b {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: url('../images/chosen-sprite.png') no-repeat 0px 2px;
|
||||||
|
}
|
||||||
|
.chosen-single .chosen-search {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1010;
|
||||||
|
margin: 0;
|
||||||
|
padding: 3px 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.chosen-single .chosen-search input[type="text"] {
|
||||||
|
margin: 1px 0;
|
||||||
|
padding: 4px 20px 4px 5px;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
outline: 0;
|
||||||
|
border: 1px solid #999999;
|
||||||
|
background: white url('../images/chosen-sprite.png') no-repeat 100% -20px;
|
||||||
|
background: url('../images/chosen-sprite.png') no-repeat 100% -20px;
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: normal;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
.chosen-single .chosen-drop {
|
||||||
|
margin-top: -1px;
|
||||||
|
border-radius: 0 0 4px 4px;
|
||||||
|
background-clip: padding-box;
|
||||||
|
}
|
||||||
|
.chosen-single.chosen-single-nosearch .chosen-search {
|
||||||
|
position: absolute;
|
||||||
|
left: -9999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chosen-results {
|
||||||
|
position: relative;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin: 0 4px 4px 0;
|
||||||
|
padding: 0 0 0 4px;
|
||||||
|
max-height: 240px;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
.chosen-results li {
|
||||||
|
display: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 5px 6px;
|
||||||
|
list-style: none;
|
||||||
|
line-height: 15px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
}
|
||||||
|
li.active-result {
|
||||||
|
display: list-item;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
li.highlighted {
|
||||||
|
background-color: #be1622;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
li.no-results {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.chosen-results li em {
|
||||||
|
font-style: normal;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chosen-choices {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 5px;
|
||||||
|
width: 100%;
|
||||||
|
height: auto !important;
|
||||||
|
height: 1%;
|
||||||
|
border: 1px solid #999999;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: #fff;
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
.chosen-choices li {
|
||||||
|
float: left;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
li.search-field {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
li.search-field input[type="text"] {
|
||||||
|
margin: 1px 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 20px;
|
||||||
|
outline: 0;
|
||||||
|
border: 0 !important;
|
||||||
|
font-size: 100%;
|
||||||
|
line-height: normal;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
li.search-choice {
|
||||||
|
position: relative;
|
||||||
|
margin: 1px 5px 1px 0;
|
||||||
|
padding: 3px 20px 3px 5px;
|
||||||
|
max-width: 100%;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
border: 1px solid #cacaca;
|
||||||
|
line-height: 13px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
li.search-choice:hover {
|
||||||
|
background-color: #ececec;
|
||||||
|
}
|
||||||
|
li.search-choice span {
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
li.search-choice .search-choice-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
right: 3px;
|
||||||
|
display: block;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
background: url('../images/chosen-sprite.png') -42px 1px no-repeat;
|
||||||
|
font-size: 1px;
|
||||||
|
}
|
||||||
|
li.search-choice .search-choice-close:hover {
|
||||||
|
background-position: -42px -10px;
|
||||||
|
}
|
||||||
|
li.search-choice-focus {
|
||||||
|
background: #d4d4d4;
|
||||||
|
}
|
||||||
|
li.search-choice-focus .search-choice-close {
|
||||||
|
background-position: -42px -10px;
|
||||||
|
}
|
||||||
|
.chosen-results {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.chosen-drop .result-selected {
|
||||||
|
display: list-item;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chosen-active.chosen-with-drop .chosen-single {
|
||||||
|
border: 1px solid #999999;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
.chosen-active.chosen-with-drop .chosen-single div {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
.chosen-active.chosen-with-drop .chosen-single div b {
|
||||||
|
background-position: -18px 2px;
|
||||||
|
}
|
||||||
|
.chosen-active .chosen-choices {
|
||||||
|
z-index: 100;
|
||||||
|
max-height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi), only screen and (min-resolution: 1.5dppx) {
|
||||||
|
.chosen-rtl .chosen-search input[type="text"],
|
||||||
|
.chosen-single .chosen-single abbr,
|
||||||
|
.chosen-single .chosen-single div b,
|
||||||
|
.chosen-single .chosen-search input[type="text"],
|
||||||
|
.chosen-multi .chosen-choices .search-choice .search-choice-close,
|
||||||
|
.chosen .chosen-results-scroll-down span,
|
||||||
|
.chosen .chosen-results-scroll-up span {
|
||||||
|
background-image: url('../images/chosen-sprite@2x.png') !important;
|
||||||
|
background-size: 52px 37px !important;
|
||||||
|
background-repeat: no-repeat !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.results {
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
|
@ -85,7 +85,7 @@ legend {
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
width: 100px;
|
width: 200px;
|
||||||
display: block;
|
display: block;
|
||||||
float: left;
|
float: left;
|
||||||
clear: both;
|
clear: both;
|
||||||
|
|
43
api/src/main/resources/tpf/client.ftl.html
Normal file
43
api/src/main/resources/tpf/client.ftl.html
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<h2>Query from your browser</h2>
|
||||||
|
<p>
|
||||||
|
Your browser executes these queries locally
|
||||||
|
using <a href="http://linkeddatafragments.org/in-depth/#tpf" target="_blank">Triple Pattern Fragments</a>.
|
||||||
|
</p>
|
||||||
|
<fieldset class="ldf-client">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<label>Query</label>
|
||||||
|
<textarea class="queryText"></textarea>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class="start" style="display: inline-block;">Execute query</button>
|
||||||
|
<button class="stop" style="display: none;">Stop execution</button>
|
||||||
|
<span class="timing"></span>
|
||||||
|
</li>
|
||||||
|
<!-- example queries -->
|
||||||
|
<li>
|
||||||
|
<label>Query results</label>
|
||||||
|
<div class="results"><div class="text"></div><div class="scrollRunway" style="position: absolute; height: 1px; width: 1px; transition: transform 0.2s; -webkit-transition: transform 0.2s; transform: translate(0px, 0px);"> </div></div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</fieldset>
|
||||||
|
<link rel="stylesheet" href="${ assetsPath }ldf-client.css">
|
||||||
|
<script>
|
||||||
|
var ldfAssetsPath = '${ assetsPath }';
|
||||||
|
</script>
|
||||||
|
<script src="${ assetsPath }ldf-client-ui-packaged.js"></script>
|
||||||
|
<script>jQuery(function($){$(".ldf-client").queryui(
|
||||||
|
{
|
||||||
|
"datasources": [
|
||||||
|
<#if datasources??>
|
||||||
|
<#list datasources?keys as datasourceName>
|
||||||
|
{
|
||||||
|
"name": "${datasources[datasourceName].getTitle() }",
|
||||||
|
"url": "${homePath}/${datasourceName}"
|
||||||
|
}<#if datasourceName?has_next>, </#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
)})</script>
|
122
api/src/main/resources/tpf/examples.ftl.html
Normal file
122
api/src/main/resources/tpf/examples.ftl.html
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
<li>
|
||||||
|
<label>Example queries</label>
|
||||||
|
<select class="query" style="display: none;"><option></option><option value="SELECT ?movie ?title ?name
|
||||||
|
WHERE {
|
||||||
|
?movie dbpedia-owl:starring [ rdfs:label "Brad Pitt"@en ];
|
||||||
|
rdfs:label ?title;
|
||||||
|
dbpedia-owl:director [ rdfs:label ?name ].
|
||||||
|
FILTER LANGMATCHES(LANG(?title), "EN")
|
||||||
|
FILTER LANGMATCHES(LANG(?name), "EN")
|
||||||
|
}">Directors of movies starring Brad Pitt</option><option value="SELECT DISTINCT ?entity WHERE {
|
||||||
|
?entity a dbpedia-owl:Airport;
|
||||||
|
dbpprop:cityServed dbpedia:Italy.
|
||||||
|
}">Airports in Italy</option><option value="SELECT ?name ?deathDate WHERE {
|
||||||
|
?person a dbpedia-owl:Artist;
|
||||||
|
rdfs:label ?name;
|
||||||
|
dbpedia-owl:birthPlace [ rdfs:label "York"@en ].
|
||||||
|
FILTER LANGMATCHES(LANG(?name), "EN")
|
||||||
|
OPTIONAL { ?person dbpprop:dateOfDeath ?deathDate. }
|
||||||
|
}">Artists born in York</option><option value="CONSTRUCT {
|
||||||
|
?artist a dbpedia-owl:Artist.
|
||||||
|
?artist dbpedia-owl:birthDate ?date.
|
||||||
|
}
|
||||||
|
WHERE {
|
||||||
|
?artist dbpedia-owl:influencedBy dbpedia:Pablo_Picasso.
|
||||||
|
?artist a dbpedia-owl:Artist.
|
||||||
|
?artist dbpedia-owl:birthDate ?date.
|
||||||
|
}">Artists influenced by Picasso</option><option value="SELECT DISTINCT ?book ?author
|
||||||
|
WHERE {
|
||||||
|
?book rdf:type dbpedia-owl:Book;
|
||||||
|
dbpedia-owl:author ?author.
|
||||||
|
}
|
||||||
|
LIMIT 100">Authors of books</option><option value="SELECT ?award WHERE {
|
||||||
|
?award a dbpedia-owl:Award;
|
||||||
|
dbpprop:country [ dbpedia-owl:language dbpedia:Dutch_language ].
|
||||||
|
}">Award ceremonies in Dutch speaking countries</option><option value="SELECT DISTINCT ?performer ?name WHERE {
|
||||||
|
?work dbpedia-owl:writer dbpedia:Michael_Jackson;
|
||||||
|
dbpedia-owl:musicalArtist ?performer.
|
||||||
|
OPTIONAL {
|
||||||
|
?performer rdfs:label ?name.
|
||||||
|
FILTER LANGMATCHES(LANG(?name), "EN")
|
||||||
|
}
|
||||||
|
}">Bands Michael Jackson wrote a song for</option><option value="SELECT ?software ?company WHERE {
|
||||||
|
?software dbpedia-owl:developer ?company.
|
||||||
|
?company dbpedia-owl:locationCountry [ rdfs:label "Belgium"@en ].
|
||||||
|
}">Belgian software</option><option value="PREFIX yago: <http://dbpedia.org/class/yago/>
|
||||||
|
SELECT ?person
|
||||||
|
WHERE {
|
||||||
|
?person a yago:Carpenters, yago:PeopleExecutedByCrucifixion.
|
||||||
|
}">Carpenters killed by crucifixion</option><option value="PREFIX dbpedia-owl: <http://dbpedia.org/ontology/>
|
||||||
|
SELECT ?actor ?cause
|
||||||
|
WHERE {
|
||||||
|
?actor dbpedia-owl:deathCause ?cause.
|
||||||
|
?actor dc:subject <http://dbpedia.org/resource/Category:American_male_film_actors>
|
||||||
|
}">Death causes of male American actors</option><option value="SELECT ?dessert ?fruit
|
||||||
|
WHERE {
|
||||||
|
?dessert dbpedia-owl:type <http://dbpedia.org/resource/Dessert>;
|
||||||
|
dbpedia-owl:ingredient ?fruit.
|
||||||
|
?fruit dbpedia-owl:kingdom <http://dbpedia.org/resource/Plant>.
|
||||||
|
}">Desserts made with plants</option><option value="SELECT DISTINCT ?device WHERE {
|
||||||
|
dbpedia:Raspberry_Pi dbpprop:os ?operatingSystem.
|
||||||
|
?device a dbpedia-owl:Device;
|
||||||
|
dbpprop:os ?operatingSystem.
|
||||||
|
FILTER (!(?device = dbpedia:Raspberry_Pi))
|
||||||
|
}">Devices with the same OS as the Raspberry Pi</option><option value="SELECT DISTINCT ?entity ?event
|
||||||
|
WHERE {
|
||||||
|
?entity a dbpedia-owl:Event;
|
||||||
|
rdfs:label ?event;
|
||||||
|
?predicate <http://dbpedia.org/resource/Trentino> .
|
||||||
|
FILTER(langMatches(lang(?event), "EN"))
|
||||||
|
}">Events that took place in the Trentino region</option><option value="SELECT ?titleEng ?title
|
||||||
|
WHERE {
|
||||||
|
?movie dbpprop:starring [ rdfs:label "Natalie Portman"@en ];
|
||||||
|
rdfs:label ?titleEng, ?title.
|
||||||
|
FILTER LANGMATCHES(LANG(?titleEng), "EN")
|
||||||
|
FILTER (!LANGMATCHES(LANG(?title), "EN"))
|
||||||
|
}">Foreign titles of Natalie Portman movies</option><option value="SELECT ?indDish ?belDish ?ingredient
|
||||||
|
WHERE {
|
||||||
|
?indDish a dbpedia-owl:Food;
|
||||||
|
dbpedia-owl:origin dbpedia:India;
|
||||||
|
dbpedia-owl:ingredient ?ingredient.
|
||||||
|
?belDish a dbpedia-owl:Food;
|
||||||
|
dbpedia-owl:origin dbpedia:Belgium;
|
||||||
|
dbpedia-owl:ingredient ?ingredient.
|
||||||
|
}">Indian dishes that have ingredients in common with Belgian dishes</option><option value="SELECT DISTINCT ?artist ?band ?bandName WHERE {
|
||||||
|
{ <http://dbpedia.org/resource/Queen_(band)> dbpedia-owl:bandMember ?artist. }
|
||||||
|
UNION
|
||||||
|
{ <http://dbpedia.org/resource/Queen_(band)> dbpedia-owl:formerBandMember ?artist. }
|
||||||
|
?band dbpedia-owl:formerBandMember ?artist;
|
||||||
|
rdfs:label ?bandName.
|
||||||
|
FILTER (?band != <http://dbpedia.org/resource/Queen_(band)>)
|
||||||
|
}">Other bands of Queen members</option><option value="SELECT DISTINCT ?person
|
||||||
|
WHERE {
|
||||||
|
dbpedia:Jesus dc:subject ?common.
|
||||||
|
?person a foaf:Person;
|
||||||
|
dc:subject ?common.
|
||||||
|
}
|
||||||
|
LIMIT 1000">People who have something in common with Jesus</option><option value="SELECT ?place ?relation
|
||||||
|
WHERE {
|
||||||
|
?place rdf:type dbpedia-owl:Settlement;
|
||||||
|
?relation dbpedia:Barack_Obama;
|
||||||
|
}">Places that have something to do with Barack Obama</option><option value="SELECT ?clubName ?playerName WHERE {
|
||||||
|
?club a dbpedia-owl:SoccerClub;
|
||||||
|
dbpedia-owl:ground ?city;
|
||||||
|
rdfs:label ?clubName.
|
||||||
|
?player dbpedia-owl:team ?club;
|
||||||
|
dbpedia-owl:birthPlace ?city;
|
||||||
|
rdfs:label ?playerName.
|
||||||
|
?city dbpedia-owl:country dbpedia:Spain.
|
||||||
|
|
||||||
|
FILTER LANGMATCHES(LANG(?clubName), "EN")
|
||||||
|
FILTER LANGMATCHES(LANG(?playerName), "EN")
|
||||||
|
}">Soccer players born in their club's city</option><option value="SELECT ?entity ?label ?comment
|
||||||
|
WHERE {
|
||||||
|
?entity a dbpedia-owl:MythologicalFigure;
|
||||||
|
rdfs:label ?label;
|
||||||
|
dc:subject <http://dbpedia.org/resource/Category:Women_in_Greek_mythology>;
|
||||||
|
rdfs:comment ?comment
|
||||||
|
|
||||||
|
FILTER(langMatches(lang(?label), "EN"))
|
||||||
|
FILTER(langMatches(lang(?comment), "EN"))
|
||||||
|
}">Women in Greek mythology</option></select><div class="chosen chosen-single" style="width: 430px;" title=""><a class="chosen-single chosen-default" tabindex="-1"><span> </span><div><b></b></div></a><div class="chosen-drop"><div class="chosen-search"><input type="text" autocomplete="off"></div><ul class="chosen-results"></ul></div></div>
|
||||||
|
</li>
|
|
@ -12,10 +12,9 @@
|
||||||
</#list>
|
</#list>
|
||||||
</#if>
|
</#if>
|
||||||
</dl>
|
</dl>
|
||||||
<p>The current dataset <em class="dataset">index</em> contains metadata about these datasets.</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<#include "fragment.ftl.html">
|
<#include "client.ftl.html">
|
||||||
</#macro>
|
</#macro>
|
||||||
|
|
||||||
<@display_page/>
|
<@display_page/>
|
Loading…
Add table
Reference in a new issue