[Mulgara-svn] r1046 - trunk/src/jar/sparql-interpreter/java/org/mulgara/sparql
pag at mulgara.org
pag at mulgara.org
Wed Jul 2 21:40:46 UTC 2008
Author: pag
Date: 2008-07-02 14:40:45 -0700 (Wed, 02 Jul 2008)
New Revision: 1046
Modified:
trunk/src/jar/sparql-interpreter/java/org/mulgara/sparql/SparqlInterpreter.java
Log:
Preliminary implementation for CONSTRUCT, ASK, and DESCRIBE queries
Modified: trunk/src/jar/sparql-interpreter/java/org/mulgara/sparql/SparqlInterpreter.java
===================================================================
--- trunk/src/jar/sparql-interpreter/java/org/mulgara/sparql/SparqlInterpreter.java 2008-07-02 21:39:30 UTC (rev 1045)
+++ trunk/src/jar/sparql-interpreter/java/org/mulgara/sparql/SparqlInterpreter.java 2008-07-02 21:40:45 UTC (rev 1046)
@@ -14,18 +14,26 @@
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.mulgara.parser.Interpreter;
import org.mulgara.parser.MulgaraLexerException;
import org.mulgara.parser.MulgaraParserException;
+import org.mulgara.query.AskQuery;
+import org.mulgara.query.ConstantValue;
+import org.mulgara.query.Constraint;
import org.mulgara.query.ConstraintConjunction;
import org.mulgara.query.ConstraintDisjunction;
import org.mulgara.query.ConstraintExpression;
+import org.mulgara.query.ConstraintImpl;
import org.mulgara.query.ConstraintIs;
+import org.mulgara.query.ConstructQuery;
+import org.mulgara.query.GraphAnswer;
import org.mulgara.query.ModelExpression;
import org.mulgara.query.ModelResource;
import org.mulgara.query.ModelUnion;
@@ -35,16 +43,24 @@
import org.mulgara.query.UnconstrainedAnswer;
import org.mulgara.query.Variable;
import org.mulgara.query.operation.Command;
+import org.mulgara.query.rdf.LiteralImpl;
+import org.mulgara.query.rdf.Mulgara;
import org.mulgara.query.rdf.URIReferenceImpl;
import org.mulgara.sparql.parser.ParseException;
import org.mulgara.sparql.parser.QueryStructure;
import org.mulgara.sparql.parser.SparqlParser;
+import org.mulgara.sparql.parser.cst.BlankNode;
import org.mulgara.sparql.parser.cst.Expression;
import org.mulgara.sparql.parser.cst.GroupGraphPattern;
import org.mulgara.sparql.parser.cst.IRIReference;
import org.mulgara.sparql.parser.cst.Node;
import org.mulgara.sparql.parser.cst.Ordering;
+import org.mulgara.sparql.parser.cst.RDFLiteral;
+import org.mulgara.sparql.parser.cst.Triple;
+import static org.jrdf.vocabulary.RDF.TYPE;
+import static org.jrdf.vocabulary.RDFS.LITERAL;
+import static org.mulgara.query.rdf.Mulgara.NODE_TYPE_GRAPH;
/**
* Converts a parsed SPARQL query into a Command for execution.
@@ -59,6 +75,31 @@
/** The default graph to use if none has been set. */
private static final URI INTERNAL_DEFAULT_GRAPH_URI = URI.create("local:null");
+ /** The column variables used to build a graph. */
+ private static final Variable[] GRAPH_VARS = GraphAnswer.getGraphVariables();
+
+ /** A constraint for referring to an entire constructed graph. */
+ private static final Constraint GRAPH_CONSTRAINT = new ConstraintImpl(GRAPH_VARS[0], GRAPH_VARS[1], GRAPH_VARS[2]);
+
+ /** Reference for URI references. */
+ private static final URIReferenceImpl URI_REF = new URIReferenceImpl(URI.create(Mulgara.NAMESPACE + "UriReference"));
+
+ /** Reference for rdf:type. */
+ private static final URIReferenceImpl TYPE_REF = new URIReferenceImpl(TYPE);
+
+ /** Reference for rdfs:Literal. */
+ private static final URIReferenceImpl LITERAL_REF = new URIReferenceImpl(LITERAL);
+
+ /** Reference for the graph of sys:type. */
+ private static final URIReferenceImpl NODE_TYPE_GRAPH_REF = new URIReferenceImpl(URI.create(NODE_TYPE_GRAPH));
+
+ /** A constraint for limiting the graph predicate variable to literals. */
+ private static final ConstraintImpl LITERAL_ONLY_CONSTRAINT = new ConstraintImpl(GRAPH_VARS[2], TYPE_REF, LITERAL_REF, NODE_TYPE_GRAPH_REF);
+
+ /** A constraint for limiting the graph predicate variable to URIs. */
+ private static final ConstraintImpl URI_ONLY_CONSTRAINT = new ConstraintImpl(GRAPH_VARS[2], TYPE_REF, URI_REF, NODE_TYPE_GRAPH_REF);
+
+
/** The default graph to use when none has been parsed. */
private URI defaultGraphUri = null;
@@ -109,11 +150,11 @@
case select:
return buildSelectQuery(struct);
case construct:
- return unhandledType(struct);
+ return buildConstructQuery(struct);
case describe:
return unhandledType(struct);
case ask:
- return unhandledType(struct);
+ return buildAskQuery(struct);
default:
throw new MulgaraParserException("Unknown query type: " + struct.getType().name());
}
@@ -147,6 +188,60 @@
}
/**
+ * Converts the elements of a {@link QueryStructure} into a Mulgara {@link AskQuery}.
+ * @param queryStruct The structure to analyze and convert.
+ * @return A new query that can be run as a {@link org.mulgara.query.operation.Command} on a connection.
+ * @throws MulgaraParserException If the query structure contains elements that are not supported by Mulgara.
+ */
+ AskQuery buildAskQuery(QueryStructure queryStruct) throws MulgaraParserException {
+ List<Variable> selection = new ArrayList<Variable>();
+ Collection<org.mulgara.sparql.parser.cst.Variable> allVars = queryStruct.getAllVariables();
+ for (org.mulgara.sparql.parser.cst.Variable v: allVars) selection.add(new Variable(v.getName()));
+ ModelExpression defaultGraphs = getFrom(queryStruct);
+ ConstraintExpression whereClause = getWhere(queryStruct);
+ return new AskQuery(selection, defaultGraphs, whereClause);
+ }
+
+ /**
+ * Converts the elements of a {@link QueryStructure} into a Mulgara {@link ConstructQuery}.
+ * @param queryStruct The structure to analyze and convert.
+ * @return A new query that can be run as a {@link org.mulgara.query.operation.Command} on a connection.
+ * @throws MulgaraParserException If the query structure contains elements that are not supported by Mulgara.
+ */
+ ConstructQuery buildConstructQuery(QueryStructure queryStruct) throws MulgaraParserException {
+ List<? extends SelectElement> selection = getConstructTemplate(queryStruct);
+ if (selection.size() % 3 != 0) {
+ throw new MulgaraParserException("CONSTRUCT queries require a multiple of 3 nodes in the template.");
+ }
+ ModelExpression defaultGraphs = getFrom(queryStruct);
+ ConstraintExpression whereClause = getWhere(queryStruct);
+ List<Order> orderBy = getOrdering(queryStruct);
+ Integer limit = getLimit(queryStruct);
+ int offset = queryStruct.getOffset();
+ // null having, unconstrained answer
+ return new ConstructQuery(selection, defaultGraphs, whereClause, orderBy, limit, offset);
+ }
+
+ /**
+ * Converts the elements of a {@link QueryStructure} into a Mulgara {@link ConstructQuery}
+ * appropriate for a DESCRIBE query.
+ * @param queryStruct The structure to analyze and convert.
+ * @return A new query that can be run as a {@link org.mulgara.query.operation.Command} on a connection.
+ * @throws MulgaraParserException If the query structure contains elements that are not supported by Mulgara.
+ */
+ ConstructQuery buildDescribeQuery(QueryStructure queryStruct) throws MulgaraParserException {
+ List<? extends SelectElement> described = getSelection(queryStruct);
+ ConstraintExpression whereClause = distributeIntoWhereClause(described, getWhere(queryStruct));
+ whereClause = constraintToNonBlank(whereClause);
+ ModelExpression defaultGraphs = getFrom(queryStruct);
+ List<Order> orderBy = getOrdering(queryStruct);
+ Integer limit = getLimit(queryStruct);
+ int offset = queryStruct.getOffset();
+ // null having, unconstrained answer
+ return new ConstructQuery(graphVariables(), defaultGraphs, whereClause, orderBy, limit, offset);
+ }
+
+ /**
* Extract the requested variables from this query into a list.
* @param queryStruct The query to get the selected variables from.
* @return A new list containing Mulgara {@link Variable}s.
@@ -170,6 +265,59 @@
}
/**
+ * Extract the requested elements from this construction template into a List.
+ * @param queryStruct The query to get the selected variables from.
+ * @return A new list containing Mulgara {@link Variable}s.
+ * @throws MulgaraParserException If and selected elements are not variables.
+ */
+ @SuppressWarnings("unchecked")
+ List<? extends SelectElement> getConstructTemplate(QueryStructure queryStruct) throws MulgaraParserException {
+ List<SelectElement> result = new ArrayList<SelectElement>();
+ List<Triple> template = (List<Triple>)queryStruct.getConstructTemplate().getElements();
+ ConstantVarFactory factory = new ConstantVarFactory();
+ for (Triple triple: template) {
+ result.add(convertForTemplate(triple.getSubject(), factory));
+ result.add(convertForTemplate(triple.getPredicate(), factory));
+ result.add(convertForTemplate(triple.getObject(), factory));
+ }
+ return result;
+ }
+
+ /**
+ * Converts a node to a "selectable" element for use in a CONSTRUCT template.
+ * @param node The query node to convert.
+ * @param constantVars A variable factory for labelling constants.
+ * @return A new element that can be used in a CONSTRUCT template.
+ * @throws MulgaraParserException The template element was not valid.
+ */
+ private SelectElement convertForTemplate(Node node, ConstantVarFactory constantVars) throws MulgaraParserException {
+ // variables are simply converted
+ if (node instanceof org.mulgara.sparql.parser.cst.Variable) {
+ return new Variable(((org.mulgara.sparql.parser.cst.Variable)node).getName());
+ }
+ // blank nodes are converted to unused variables
+ if (node instanceof BlankNode) {
+ // blank node labels are not used elsewhere as variables as they are not parsed as valid variables
+ return new Variable(((BlankNode)node).getLabel());
+ }
+ // RDFLiterals are converted to a literal, and wrapped in a ConstantValue
+ if (node instanceof RDFLiteral) {
+ RDFLiteral rl = (RDFLiteral)node;
+ LiteralImpl literal;
+ if (rl.isLanguageCoded()) literal = new LiteralImpl(rl.getValue(), rl.getLanguage());
+ else if (rl.isTyped()) literal = new LiteralImpl(rl.getValue(), rl.getDatatype().getUri());
+ else literal = new LiteralImpl(rl.getValue());
+ return new ConstantValue(constantVars.newVar(), literal);
+ }
+ // IRIReferences are converted to a URI and wrapped in a ConstantValue
+ if (node instanceof IRIReference) {
+ return new ConstantValue(constantVars.newVar(), new URIReferenceImpl(((IRIReference)node).getUri()));
+ }
+ // nothing else is valid. We probably have a compound expression.
+ throw new MulgaraParserException("Unexpected element in CONSTRUCT template: " + node);
+ }
+
+ /**
* Gets the graph expression ({@link ModelExpression}) the represents the FROM clause, or the default
* graph if none was provided.
* @param queryStruct The structure to query for the FROM clause.
@@ -277,4 +425,61 @@
}
return new ConstraintDisjunction(isConstraints);
}
+
+ /**
+ * Converts a WHERE clause into using "subject" instead of the variables from described.
+ * Then creates a union of this WHERE clause converted for each element in described.
+ * If the base WHERE clause is empty, then ($subject $predicate $object) is presumed.
+ * @param described The elements to distribute into the unioned WHERE clause.
+ * @param baseWhere The WHERE clause to convert and duplicate
+ * @return The UNIONed WHERE clauses with the variables adjusted.
+ */
+ ConstraintExpression distributeIntoWhereClause(List<? extends SelectElement> described, ConstraintExpression baseWhere) throws MulgaraParserException {
+ if (baseWhere == null) baseWhere = GRAPH_CONSTRAINT;
+ List<ConstraintExpression> constraints = new LinkedList<ConstraintExpression>();
+ for (SelectElement e: described) {
+ ConstraintExpression expr;
+ if (e instanceof URIReferenceImpl) {
+ expr = new ConstraintConjunction(baseWhere, new ConstraintIs(GRAPH_VARS[0], (URIReferenceImpl)e));
+ } else if (e instanceof Variable) {
+ expr = mapVariable(baseWhere, (Variable)e, GRAPH_VARS[0]);
+ } else throw new MulgaraParserException("Illegal type in DESCRIBE clause: " + e);
+ constraints.add(expr);
+ }
+ return new ConstraintDisjunction(constraints);
+ }
+
+ /**
+ * Maps a ConstraintExpression to a new ConstraintExpression with all instance of one
+ * {@link Variable} changed to another Variable.
+ * @param base The ConstraintExpression to map.
+ * @param from The Variable to find and replace.
+ * @param to The new Variable to replace <var>from</var> with.
+ * @return A new ConstraintExpression with all instances of <var>from</var> replaced
+ * with <var>to</var>.
+ * @throws MulgaraParserException There was an error with the transformation.
+ */
+ ConstraintExpression mapVariable(ConstraintExpression base, Variable from, Variable to) throws MulgaraParserException {
+ VariableRenameTransformer tx = new VariableRenameTransformer(from, to);
+ try {
+ return tx.transform(base);
+ } catch (SymbolicTransformationException e) {
+ throw new MulgaraParserException("Unable to convert WHERE clause for use in query.", e);
+ }
+ }
+
+
+ ConstraintExpression constraintToNonBlank(ConstraintExpression expr) {
+ ConstraintExpression literals = new ConstraintConjunction(expr, LITERAL_ONLY_CONSTRAINT);
+ ConstraintExpression uris = new ConstraintConjunction(expr, URI_ONLY_CONSTRAINT);
+ return new ConstraintDisjunction(literals, uris);
+ }
+
+ /**
+ * Get the column names used in a Graph.
+ * @return A list of Variables used when defining a graph.
+ */
+ List<? extends SelectElement> graphVariables() {
+ return Arrays.asList(GRAPH_VARS);
+ }
}
More information about the Mulgara-svn
mailing list