Updated Branches: refs/heads/develop a8d1abea1 -> 8f79ef1a8
SPARQL optimizations for FILTER Project: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/commit/8f79ef1a Tree: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/tree/8f79ef1a Diff: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/diff/8f79ef1a Branch: refs/heads/develop Commit: 8f79ef1a8d224141149704b7fd93e5747dc4ace1 Parents: a8d1abe Author: Sebastian Schaffert <[email protected]> Authored: Mon Apr 29 16:41:18 2013 +0200 Committer: Sebastian Schaffert <[email protected]> Committed: Mon Apr 29 16:41:18 2013 +0200 ---------------------------------------------------------------------- .../evaluation/KiWiEvaluationStrategyImpl.java | 72 ++++- .../sparql/persistence/KiWiSparqlConnection.java | 236 ++++++++++++++- .../kiwi/sparql/sail/KiWiSparqlSailConnection.java | 6 + .../kiwi/sparql/test/KiWiSparqlJoinTest.java | 22 ++ .../marmotta/kiwi/sparql/test/demo-data.foaf | 13 +- .../apache/marmotta/kiwi/sparql/test/query3.sparql | 7 + .../apache/marmotta/kiwi/sparql/test/query4.sparql | 7 + .../apache/marmotta/kiwi/sparql/test/query5.sparql | 8 + .../apache/marmotta/kiwi/sparql/test/query6.sparql | 8 + .../marmotta/kiwi/persistence/KiWiConnection.java | 8 +- .../marmotta/kiwi/persistence/KiWiDialect.java | 20 ++ .../marmotta/kiwi/persistence/h2/H2Dialect.java | 11 + .../kiwi/persistence/mysql/MySQLDialect.java | 10 + .../kiwi/persistence/pgsql/PostgreSQLDialect.java | 10 + .../marmotta/kiwi/sail/KiWiValueFactory.java | 2 +- parent/pom.xml | 5 + platform/marmotta-sparql/pom.xml | 4 + .../sparql/services/sail/SPARQLSailProvider.java | 78 +++++ .../src/main/resources/config-defaults.properties | 28 -- .../main/resources/config-descriptions.properties | 32 +-- 20 files changed, 504 insertions(+), 83 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/evaluation/KiWiEvaluationStrategyImpl.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/evaluation/KiWiEvaluationStrategyImpl.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/evaluation/KiWiEvaluationStrategyImpl.java index 713ff44..5e2fda0 100644 --- a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/evaluation/KiWiEvaluationStrategyImpl.java +++ b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/evaluation/KiWiEvaluationStrategyImpl.java @@ -23,9 +23,7 @@ import org.apache.marmotta.kiwi.sparql.persistence.KiWiSparqlConnection; import org.openrdf.query.BindingSet; import org.openrdf.query.Dataset; import org.openrdf.query.QueryEvaluationException; -import org.openrdf.query.algebra.Join; -import org.openrdf.query.algebra.StatementPattern; -import org.openrdf.query.algebra.TupleExpr; +import org.openrdf.query.algebra.*; import org.openrdf.query.algebra.evaluation.TripleSource; import org.openrdf.query.algebra.evaluation.impl.EvaluationStrategyImpl; import org.slf4j.Logger; @@ -59,7 +57,7 @@ public class KiWiEvaluationStrategyImpl extends EvaluationStrategyImpl{ @Override public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Join join, BindingSet bindings) throws QueryEvaluationException { - if(isPatternJoin(join)) { + if(isSupported(join)) { log.debug("applying KiWi JOIN optimizations on SPARQL query ..."); try { @@ -79,18 +77,80 @@ public class KiWiEvaluationStrategyImpl extends EvaluationStrategyImpl{ } } + @Override + public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Filter join, BindingSet bindings) throws QueryEvaluationException { + if(isSupported(join)) { + log.debug("applying KiWi JOIN optimizations on SPARQL query ..."); + + try { + return new ExceptionConvertingIteration<BindingSet, QueryEvaluationException>(connection.evaluateJoin(join, bindings)) { + @Override + protected QueryEvaluationException convert(Exception e) { + return new QueryEvaluationException(e); + } + }; + } catch (SQLException e) { + throw new QueryEvaluationException(e); + } catch (IllegalArgumentException e) { + throw new QueryEvaluationException(e); + } + } else { + return super.evaluate(join, bindings); + } + } + + /** * Test if a join consists only of joins of statement patterns; in this case we can apply a specific optimization. * @param expr * @return */ - private static boolean isPatternJoin(TupleExpr expr) { + private static boolean isSupported(TupleExpr expr) { if(expr instanceof Join) { - return isPatternJoin(((Join) expr).getLeftArg()) && isPatternJoin(((Join) expr).getRightArg()); + return isSupported(((Join) expr).getLeftArg()) && isSupported(((Join) expr).getRightArg()); + } else if(expr instanceof Filter) { + return isSupported(((Filter) expr).getArg()) && isSupported(((Filter) expr).getCondition()); } else if(expr instanceof StatementPattern) { return true; } else { return false; } } + + + private static boolean isSupported(ValueExpr expr) { + if(expr instanceof Compare) { + return isSupported(((Compare) expr).getLeftArg()) && isSupported(((Compare) expr).getRightArg()); + } else if(expr instanceof MathExpr) { + return isSupported(((MathExpr) expr).getLeftArg()) && isSupported(((MathExpr) expr).getRightArg()); + } else if(expr instanceof And) { + return isSupported(((And) expr).getLeftArg()) && isSupported(((And) expr).getRightArg()); + } else if(expr instanceof Or) { + return isSupported(((Or) expr).getLeftArg()) && isSupported(((Or) expr).getRightArg()); + } else if(expr instanceof ValueConstant) { + return true; + } else if(expr instanceof Var) { + return true; + } else if(expr instanceof Str) { + return isAtomic(((Str) expr).getArg()); + } else if(expr instanceof Lang) { + return isAtomic(((Lang) expr).getArg()); + } else if(expr instanceof LangMatches) { + return isSupported(((LangMatches) expr).getLeftArg()) && isConstant(((LangMatches) expr).getRightArg()); + } else if(expr instanceof Regex) { + return isSupported(((Regex) expr).getArg()) && isAtomic(((Regex) expr).getPatternArg()) && ((Regex) expr).getFlagsArg() == null; + } else { + return false; + } + } + + + private static boolean isAtomic(ValueExpr expr) { + return expr instanceof Var || expr instanceof ValueConstant; + } + + private static boolean isConstant(ValueExpr expr) { + return expr instanceof ValueConstant; + } + } http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/persistence/KiWiSparqlConnection.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/persistence/KiWiSparqlConnection.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/persistence/KiWiSparqlConnection.java index 92bbcb6..6a8566c 100644 --- a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/persistence/KiWiSparqlConnection.java +++ b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/persistence/KiWiSparqlConnection.java @@ -19,21 +19,19 @@ package org.apache.marmotta.kiwi.sparql.persistence; import com.google.common.base.Preconditions; import info.aduna.iteration.CloseableIteration; -import org.apache.marmotta.kiwi.caching.KiWiCacheManager; +import org.apache.commons.lang.StringUtils; +import org.apache.marmotta.commons.sesame.model.Namespaces; +import org.apache.marmotta.commons.util.DateUtils; import org.apache.marmotta.kiwi.model.rdf.KiWiNode; import org.apache.marmotta.kiwi.persistence.KiWiConnection; -import org.apache.marmotta.kiwi.persistence.KiWiDialect; -import org.apache.marmotta.kiwi.persistence.KiWiPersistence; import org.apache.marmotta.kiwi.persistence.util.ResultSetIteration; import org.apache.marmotta.kiwi.persistence.util.ResultTransformerFunction; import org.apache.marmotta.kiwi.sail.KiWiValueFactory; +import org.openrdf.model.Literal; import org.openrdf.model.Value; import org.openrdf.query.Binding; import org.openrdf.query.BindingSet; -import org.openrdf.query.algebra.Join; -import org.openrdf.query.algebra.StatementPattern; -import org.openrdf.query.algebra.TupleExpr; -import org.openrdf.query.algebra.Var; +import org.openrdf.query.algebra.*; import org.openrdf.query.impl.MapBindingSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,6 +39,8 @@ import org.slf4j.LoggerFactory; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.*; /** @@ -55,6 +55,8 @@ public class KiWiSparqlConnection { private static Logger log = LoggerFactory.getLogger(KiWiSparqlConnection.class); + private static DateFormat sqlDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S"); + private KiWiConnection parent; private KiWiValueFactory valueFactory; @@ -69,9 +71,8 @@ public class KiWiSparqlConnection { * @param join * @return */ - public CloseableIteration<BindingSet, SQLException> evaluateJoin(Join join, final BindingSet bindings) throws SQLException { - Preconditions.checkArgument(join.getLeftArg() instanceof StatementPattern || join.getLeftArg() instanceof Join); - Preconditions.checkArgument(join.getRightArg() instanceof StatementPattern || join.getRightArg() instanceof Join); + public CloseableIteration<BindingSet, SQLException> evaluateJoin(TupleExpr join, final BindingSet bindings) throws SQLException { + Preconditions.checkArgument(join instanceof Join || join instanceof Filter || join instanceof StatementPattern); // some definitions String[] positions = new String[] {"subject","predicate","object","context"}; @@ -234,7 +235,7 @@ public class KiWiSparqlConnection { for(Map.Entry<Var,List<String>> entry : queryVariables.entrySet()) { if(entry.getKey().getName() != null && entry.getKey().getName().equals(v) && entry.getValue() != null && entry.getValue().size() > 0) { - List<String> vNames = queryVariables.get(v); + List<String> vNames = entry.getValue(); String vName = vNames.get(0); Value binding = valueFactory.convert(bindings.getValue(v)); if(binding instanceof KiWiNode) { @@ -253,6 +254,15 @@ public class KiWiSparqlConnection { whereConditions.add(pName+".deleted = false"); } + + // 5. for each filter condition, add a statement to the where clause + List<ValueExpr> filters = new ArrayList<ValueExpr>(); + collectFilters(join, filters); + for(ValueExpr expr : filters) { + whereConditions.add(evaluateExpression(expr,queryVariables, null)); + } + + // construct the where clause StringBuilder whereClause = new StringBuilder(); for(Iterator<String> it = whereConditions.iterator(); it.hasNext(); ) { @@ -270,7 +280,9 @@ public class KiWiSparqlConnection { "FROM " + fromClause + "\n " + "WHERE " + whereClause; - log.debug("constructed SQL query string {}",queryString); + log.debug("original SPARQL syntax tree:\n {}", join); + log.debug("constructed SQL query string:\n {}",queryString); + log.debug("SPARQL -> SQL variable mappings:\n {}", queryVariables); PreparedStatement queryStatement = parent.getJDBCConnection().prepareStatement(queryString); ResultSet result = queryStatement.executeQuery(); @@ -296,6 +308,84 @@ public class KiWiSparqlConnection { } + private String evaluateExpression(ValueExpr expr, Map<Var, List<String>> queryVariables, OPTypes optype) { + if(expr instanceof And) { + return "(" + evaluateExpression(((And) expr).getLeftArg(), queryVariables, optype) + " AND " + evaluateExpression(((And) expr).getRightArg(),queryVariables, optype) + ")"; + } else if(expr instanceof Or) { + return "(" + evaluateExpression(((Or) expr).getLeftArg(), queryVariables, optype) + " OR " + evaluateExpression(((Or) expr).getRightArg(),queryVariables, optype) + ")"; + } else if(expr instanceof Str) { + Str str = (Str)expr; + // get value of argument and express it as string + if(str.getArg() instanceof Var) { + return queryVariables.get(str.getArg()).get(0) + ".svalue"; + } else if(str.getArg() instanceof ValueConstant) { + return "'" + ((ValueConstant) str.getArg()).getValue().stringValue() + "'"; + } + } else if(expr instanceof Lang) { + Lang lang = (Lang)expr; + + if(lang.getArg() instanceof Var) { + return queryVariables.get(lang.getArg()).get(0) + ".lang"; + } + } else if(expr instanceof Compare) { + Compare cmp = (Compare)expr; + + OPTypes ot = determineOpType(cmp.getLeftArg(), cmp.getRightArg()); + + return evaluateExpression(cmp.getLeftArg(),queryVariables, ot) + getSQLOperator(cmp.getOperator()) + evaluateExpression(cmp.getRightArg(),queryVariables, ot); + } else if(expr instanceof Regex) { + Regex re = (Regex)expr; + + // TODO: simplify the trivial cases to LIKE + + return parent.getDialect().getRegexp(evaluateExpression(re.getArg(),queryVariables, optype), evaluateExpression(re.getPatternArg(), queryVariables, OPTypes.STRING)); + } else if(expr instanceof LangMatches) { + LangMatches lm = (LangMatches)expr; + String value = evaluateExpression(lm.getLeftArg(), queryVariables, optype); + ValueConstant pattern = (ValueConstant) lm.getRightArg(); + + if(pattern.getValue().stringValue().equals("*")) { + return value + " LIKE '%'"; + } else if(pattern.getValue().stringValue().equals("")) { + return value + " IS NULL"; + } else { + return "(" + value + " = '"+pattern.getValue().stringValue()+"' OR " + parent.getDialect().getILike(value, "'" + pattern.getValue().stringValue() + "-%' )"); + } + } else if(expr instanceof Var) { + String var = queryVariables.get(expr).get(0); + + if(optype == null) { + return var + ".svalue"; + } else { + switch (optype) { + case STRING: return var + ".svalue"; + case INT: return var + ".ivalue"; + case DOUBLE: return var + ".dvalue"; + case DATE: return var + ".tvalue"; + default: throw new IllegalArgumentException("unsupported value type: " + optype); + } + } + } else if(expr instanceof ValueConstant) { + String val = ((ValueConstant) expr).getValue().stringValue(); + + if(optype == null) { + return "'" + val + "'"; + } else { + switch (optype) { + case STRING: return "'" + val + "'"; + case INT: return ""+Integer.parseInt(val); + case DOUBLE: return ""+Double.parseDouble(val); + case DATE: return "'" + DateUtils.parseDate(val) + "'"; + default: throw new IllegalArgumentException("unsupported value type: " + optype); + } + } + } + + + throw new IllegalArgumentException("unsupported value expression: "+expr); + } + + /** * Collect all statement patterns in a tuple expression in depth-first order. The tuple expression may only * contain Join or StatementPattern expressions, otherwise an IllegalArgumentException is thrown. @@ -306,6 +396,8 @@ public class KiWiSparqlConnection { if(expr instanceof Join) { collectPatterns(((Join) expr).getLeftArg(), patterns); collectPatterns(((Join) expr).getRightArg(), patterns); + } else if(expr instanceof Filter) { + collectPatterns(((Filter) expr).getArg(), patterns); } else if(expr instanceof StatementPattern) { patterns.add((StatementPattern)expr); } else { @@ -313,4 +405,124 @@ public class KiWiSparqlConnection { } } + + + /** + * Collect all filter conditions in a tuple expression in depth-first order. The tuple expression may only + * contain Join or StatementPattern expressions, otherwise an IllegalArgumentException is thrown. + * @param expr + * @param filters + */ + private void collectFilters(TupleExpr expr, List<ValueExpr> filters) { + if(expr instanceof Join) { + collectFilters(((Join) expr).getLeftArg(), filters); + collectFilters(((Join) expr).getRightArg(), filters); + } else if(expr instanceof Filter) { + filters.add(((Filter) expr).getCondition()); + } else if(expr instanceof StatementPattern) { + // do nothing + } else { + throw new IllegalArgumentException("the tuple expression was neither a join nor a statement pattern: "+expr); + } + + } + + + private String getSQLOperator(Compare.CompareOp op) { + switch (op) { + case EQ: return " = "; + case GE: return " >= "; + case GT: return " > "; + case LE: return " <= "; + case LT: return " < "; + case NE: return " <> "; + } + throw new IllegalArgumentException("unsupported operator type for comparison: "+op); + } + + + private String getSQLOperator(MathExpr.MathOp op) { + switch (op) { + case PLUS: return " + "; + case MINUS: return " - "; + case DIVIDE: return " / "; + case MULTIPLY: return " / "; + } + throw new IllegalArgumentException("unsupported operator type for math expression: "+op); + } + + + + private OPTypes determineOpType(ValueExpr expr) { + if(expr instanceof ValueConstant) { + if(((ValueConstant) expr).getValue() instanceof Literal) { + Literal l = (Literal)((ValueConstant) expr).getValue(); + String type = l.getDatatype().stringValue(); + + if(StringUtils.equals(Namespaces.NS_XSD + "double", type) + || StringUtils.equals(Namespaces.NS_XSD + "float", type) + || StringUtils.equals(Namespaces.NS_XSD + "decimal", type)) { + return OPTypes.DOUBLE; + } else if(StringUtils.equals(Namespaces.NS_XSD + "integer", type) + || StringUtils.equals(Namespaces.NS_XSD + "long", type) + || StringUtils.equals(Namespaces.NS_XSD + "int", type) + || StringUtils.equals(Namespaces.NS_XSD + "short", type) + || StringUtils.equals(Namespaces.NS_XSD + "nonNegativeInteger", type) + || StringUtils.equals(Namespaces.NS_XSD + "nonPositiveInteger", type) + || StringUtils.equals(Namespaces.NS_XSD + "negativeInteger", type) + || StringUtils.equals(Namespaces.NS_XSD + "positiveInteger", type) + || StringUtils.equals(Namespaces.NS_XSD + "unsignedLong", type) + || StringUtils.equals(Namespaces.NS_XSD + "unsignedShort", type) + || StringUtils.equals(Namespaces.NS_XSD + "byte", type) + || StringUtils.equals(Namespaces.NS_XSD + "unsignedByte", type)) { + return OPTypes.INT; + } else if(StringUtils.equals(Namespaces.NS_XSD + "dateTime", type) + || StringUtils.equals(Namespaces.NS_XSD + "date", type) + || StringUtils.equals(Namespaces.NS_XSD + "time", type)) { + return OPTypes.DATE; + } else { + return OPTypes.STRING; + } + } else { + return OPTypes.STRING; + } + } else if(expr instanceof Str) { + return OPTypes.STRING; + } else if(expr instanceof Lang) { + return OPTypes.STRING; + } else if(expr instanceof LocalName) { + return OPTypes.STRING; + } else if(expr instanceof Label) { + return OPTypes.STRING; + } else if(expr instanceof MathExpr) { + return determineOpType(((MathExpr) expr).getLeftArg(), ((MathExpr) expr).getRightArg()); + } else if(expr instanceof Var) { + return OPTypes.ANY; + } else { + throw new IllegalArgumentException("unsupported expression: "+expr); + } + } + + private OPTypes determineOpType(ValueExpr expr1, ValueExpr expr2) { + OPTypes left = determineOpType(expr1); + OPTypes right = determineOpType(expr2); + + if(left == OPTypes.ANY) { + return right; + } else if(right == OPTypes.ANY) { + return left; + } else if(left == right) { + return left; + } else if( (left == OPTypes.INT && right == OPTypes.DOUBLE) || (left == OPTypes.DOUBLE && right == OPTypes.INT)) { + return OPTypes.DOUBLE; + } else if( (left == OPTypes.STRING) || (right == OPTypes.STRING)) { + return OPTypes.STRING; + } else { + throw new IllegalArgumentException("unsupported type coercion: " + left + " and " + right); + } + } + + private static enum OPTypes { + STRING, DOUBLE, INT, DATE, ANY + } } http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSailConnection.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSailConnection.java b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSailConnection.java index d1a798f..bad56e3 100644 --- a/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSailConnection.java +++ b/libraries/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sail/KiWiSparqlSailConnection.java @@ -36,6 +36,8 @@ import org.openrdf.sail.NotifyingSailConnection; import org.openrdf.sail.SailConnection; import org.openrdf.sail.SailException; import org.openrdf.sail.helpers.NotifyingSailConnectionWrapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Add file description here! @@ -44,6 +46,8 @@ import org.openrdf.sail.helpers.NotifyingSailConnectionWrapper; */ public class KiWiSparqlSailConnection extends NotifyingSailConnectionWrapper { + private static Logger log = LoggerFactory.getLogger(KiWiSparqlSailConnection.class); + private KiWiSparqlConnection connection; private KiWiValueFactory valueFactory; @@ -80,6 +84,8 @@ public class KiWiSparqlSailConnection extends NotifyingSailConnectionWrapper { new FilterOptimizer().optimize(tupleExpr, dataset, bindings); new OrderLimitOptimizer().optimize(tupleExpr, dataset, bindings); + log.debug("evaluating SPARQL query:\n {}", tupleExpr); + return strategy.evaluate(tupleExpr, bindings); } catch (QueryEvaluationException e) { http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-sparql/src/test/java/org/apache/marmotta/kiwi/sparql/test/KiWiSparqlJoinTest.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/test/java/org/apache/marmotta/kiwi/sparql/test/KiWiSparqlJoinTest.java b/libraries/kiwi/kiwi-sparql/src/test/java/org/apache/marmotta/kiwi/sparql/test/KiWiSparqlJoinTest.java index 81ddf6e..59455b8 100644 --- a/libraries/kiwi/kiwi-sparql/src/test/java/org/apache/marmotta/kiwi/sparql/test/KiWiSparqlJoinTest.java +++ b/libraries/kiwi/kiwi-sparql/src/test/java/org/apache/marmotta/kiwi/sparql/test/KiWiSparqlJoinTest.java @@ -211,6 +211,28 @@ public class KiWiSparqlJoinTest { testQuery("query2.sparql"); } + @Test + public void testQuery3() throws Exception { + testQuery("query3.sparql"); + } + + @Test + public void testQuery4() throws Exception { + testQuery("query4.sparql"); + } + + // numeric operator + @Test + public void testQuery5() throws Exception { + testQuery("query5.sparql"); + } + + // language match + @Test + public void testQuery6() throws Exception { + testQuery("query6.sparql"); + } + private void testQuery(String filename) throws Exception { String queryString = IOUtils.toString(this.getClass().getResourceAsStream(filename), "UTF-8"); http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/demo-data.foaf ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/demo-data.foaf b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/demo-data.foaf index c2d786b..bde1322 100644 --- a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/demo-data.foaf +++ b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/demo-data.foaf @@ -22,7 +22,8 @@ <foaf:Person rdf:about="http://localhost:8080/LMF/resource/hans_meier" xmlns:foaf="http://xmlns.com/foaf/0.1/"> <foaf:name>Hans Meier</foaf:name> - <dc:description>Hans Meier is a software engineer living in Salzburg</dc:description> + <dc:description xml:lang="en">Hans Meier is a software engineer living in Salzburg</dc:description> + <dc:description xml:lang="de">Hans Meier ist ein Softwareentwickler aus Salzburg</dc:description> <foaf:interest rdf:resource="http://rdf.freebase.com/ns/en.software_engineering"/> <foaf:interest rdf:resource="http://rdf.freebase.com/ns/en.linux"/> <foaf:interest rdf:resource="http://dbpedia.org/resource/Java" /> @@ -30,6 +31,8 @@ <foaf:based_near rdf:resource="http://sws.geonames.org/2766824/"/> <foaf:depiction rdf:resource="http://localhost:8080/LMF/resource/hans_meier.jpg"/> + <foaf:age rdf:datatype="http://www.w3.org/2001/XMLSchema#integer">29</foaf:age> + <foaf:knows rdf:resource="http://localhost:8080/LMF/resource/sepp_huber" /> <foaf:knows rdf:resource="http://localhost:8080/LMF/resource/anna_schmidt"/> @@ -43,19 +46,23 @@ <foaf:Person rdf:about="http://localhost:8080/LMF/resource/sepp_huber" xmlns:foaf="http://xmlns.com/foaf/0.1/"> <foaf:name>Sepp Huber</foaf:name> - <dc:description>Sepp Huber is an alpinist living in Traunstein. He is a good climber, but not as famous as his cousin Alexander Huber.</dc:description> + <dc:description xml:lang="en">Sepp Huber is an alpinist living in Traunstein. He is a good climber, but not as famous as his cousin Alexander Huber.</dc:description> + <dc:description xml:lang="de-DE">Sepp Huber ist ein Bergsteiger aus Traunstein. Er ist ein guter Kletterer.</dc:description> <foaf:interest rdf:resource="http://dbpedia.org/resource/Mountaineering"/> <foaf:interest rdf:resource="http://dbpedia.org/resource/Climbing"/> <foaf:interest rdf:resource="http://localhost:8080/LMF/resource/Chess" /> <foaf:based_near rdf:resource="http://dbpedia.org/resource/Traunstein"/> + <foaf:age rdf:datatype="http://www.w3.org/2001/XMLSchema#integer">31</foaf:age> + + <foaf:knows rdf:resource="http://dbpedia.org/resource/Alexander_Huber" /> <foaf:knows rdf:resource="http://localhost:8080/LMF/resource/hans_meier" /> </foaf:Person> <foaf:Person rdf:about="http://localhost:8080/LMF/resource/anna_schmidt" xmlns:foaf="http://xmlns.com/foaf/0.1/"> <foaf:name>Anna Schmidt</foaf:name> - <dc:description>Anna Schmidt is working as PR manager for mountaineers coming from Garmisch-Partenkirchen. She likes mountaineering and is also a Linux enthusiast.</dc:description> + <dc:description xml:lang="en">Anna Schmidt is working as PR manager for mountaineers coming from Garmisch-Partenkirchen. She likes mountaineering and is also a Linux enthusiast.</dc:description> <foaf:interest rdf:resource="http://dbpedia.org/resource/Mountaineering"/> <foaf:interest rdf:resource="http://dbpedia.org/resource/Linux"/> <foaf:interest rdf:resource="http://localhost:8080/LMF/resource/Chess" /> http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query3.sparql ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query3.sparql b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query3.sparql new file mode 100644 index 0000000..4e22987 --- /dev/null +++ b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query3.sparql @@ -0,0 +1,7 @@ +PREFIX foaf: <http://xmlns.com/foaf/0.1/> +PREFIX dc: <http://purl.org/dc/elements/1.1/> + +SELECT ?p1 ?fn ?desc ?friend WHERE { + ?p1 foaf:name ?fn . + FILTER( regex(?fn, "Anna.*") ) +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query4.sparql ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query4.sparql b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query4.sparql new file mode 100644 index 0000000..3cf4787 --- /dev/null +++ b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query4.sparql @@ -0,0 +1,7 @@ +PREFIX foaf: <http://xmlns.com/foaf/0.1/> +PREFIX dc: <http://purl.org/dc/elements/1.1/> + +SELECT ?p1 ?fn ?desc ?friend WHERE { + ?p1 foaf:name ?fn . + FILTER( regex(str(?p1), "^http://localhost:8080/LMF/resource/sepp.*") ) +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query5.sparql ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query5.sparql b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query5.sparql new file mode 100644 index 0000000..325bb6b --- /dev/null +++ b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query5.sparql @@ -0,0 +1,8 @@ +PREFIX foaf: <http://xmlns.com/foaf/0.1/> +PREFIX dc: <http://purl.org/dc/elements/1.1/> + +SELECT ?p1 ?fn ?desc ?friend WHERE { + ?p1 foaf:name ?fn . + ?p1 foaf:age ?age . + FILTER( ?age > 30 ) +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query6.sparql ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query6.sparql b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query6.sparql new file mode 100644 index 0000000..1a953df --- /dev/null +++ b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/test/query6.sparql @@ -0,0 +1,8 @@ +PREFIX foaf: <http://xmlns.com/foaf/0.1/> +PREFIX dc: <http://purl.org/dc/elements/1.1/> + +SELECT ?p1 ?fn ?desc ?friend WHERE { + ?p1 foaf:name ?fn . + ?p1 dc:description ?d . + FILTER( langMatches(lang(?d), "de") ) +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiConnection.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiConnection.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiConnection.java index fa9834a..f7130d9 100644 --- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiConnection.java +++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiConnection.java @@ -184,6 +184,10 @@ public class KiWiConnection { return cacheManager; } + public KiWiDialect getDialect() { + return dialect; + } + /** * Load a KiWiNamespace with the given prefix, or null if the namespace does not exist. The method will first * look in the node cache for cached nodes. If no cache entry is found, it will run a database query @@ -1361,8 +1365,8 @@ public class KiWiConnection { protected static Locale getLocale(String language) { Locale locale = localeMap.get(language); - if(locale == null) { - locale = LocaleUtils.toLocale(language); + if(locale == null && language != null) { + locale = LocaleUtils.toLocale(language.replace("-","_")); localeMap.put(language,locale); } http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiDialect.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiDialect.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiDialect.java index 9cd130e..5e261c8 100644 --- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiDialect.java +++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/KiWiDialect.java @@ -152,4 +152,24 @@ public abstract class KiWiDialect { public Set<String> getStatementIdentifiers() { return statements.stringPropertyNames(); } + + + /** + * Return the database specific operator for matching a text against a regular expression. + * + * @param text + * @param pattern + * @return + */ + public abstract String getRegexp(String text, String pattern); + + + /** + * Return the database specific case insensitive like comparison, e.g. ILIKE in Postgres. + * + * @param text + * @param pattern + * @return + */ + public abstract String getILike(String text, String pattern); } http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java index dc57948..2be3575 100644 --- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java +++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java @@ -44,4 +44,15 @@ public class H2Dialect extends KiWiDialect { public String getDriverClass() { return "org.h2.Driver"; } + + @Override + public String getRegexp(String text, String pattern) { + return text + " REGEXP " + pattern; + } + + @Override + public String getILike(String text, String pattern) { + return "lower("+text+") LIKE lower("+pattern+")"; + } + } http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java index 73722de..d4125e2 100644 --- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java +++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java @@ -55,4 +55,14 @@ public class MySQLDialect extends KiWiDialect { public String getDriverClass() { return "com.mysql.jdbc.Driver"; } + + @Override + public String getRegexp(String text, String pattern) { + return text + " RLIKE " + pattern; + } + + @Override + public String getILike(String text, String pattern) { + return "lower("+text+") LIKE lower("+pattern+")"; + } } http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java index c517d0f..1d7e875 100644 --- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java +++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/pgsql/PostgreSQLDialect.java @@ -45,4 +45,14 @@ public class PostgreSQLDialect extends KiWiDialect { public String getDriverClass() { return "org.postgresql.Driver"; } + + @Override + public String getRegexp(String text, String pattern) { + return text + " ~ " + pattern; + } + + @Override + public String getILike(String text, String pattern) { + return text + " ILIKE " + pattern; + } } http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiValueFactory.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiValueFactory.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiValueFactory.java index dc7c631..a6964ff 100644 --- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiValueFactory.java +++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/sail/KiWiValueFactory.java @@ -338,7 +338,7 @@ public class KiWiValueFactory implements ValueFactory { final KiWiUriResource rtype = (KiWiUriResource)createURI(type); final Locale locale; if(lang != null) { - locale = LocaleUtils.toLocale(lang); + locale = LocaleUtils.toLocale(lang.replace("-","_")); } else locale = null; http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/parent/pom.xml ---------------------------------------------------------------------- diff --git a/parent/pom.xml b/parent/pom.xml index 2eb8e91..0e9a564 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -1139,6 +1139,11 @@ </dependency> <dependency> <groupId>org.apache.marmotta</groupId> + <artifactId>kiwi-sparql</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.marmotta</groupId> <artifactId>kiwi-transactions</artifactId> <version>${project.version}</version> </dependency> http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/platform/marmotta-sparql/pom.xml ---------------------------------------------------------------------- diff --git a/platform/marmotta-sparql/pom.xml b/platform/marmotta-sparql/pom.xml index 41970b7..ac86efb 100644 --- a/platform/marmotta-sparql/pom.xml +++ b/platform/marmotta-sparql/pom.xml @@ -138,6 +138,10 @@ </dependency> <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>kiwi-sparql</artifactId> + </dependency> + <dependency> <groupId>org.openrdf.sesame</groupId> <artifactId>sesame-query</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/services/sail/SPARQLSailProvider.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/services/sail/SPARQLSailProvider.java b/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/services/sail/SPARQLSailProvider.java new file mode 100644 index 0000000..6b4112f --- /dev/null +++ b/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/services/sail/SPARQLSailProvider.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.marmotta.platform.sparql.services.sail; + +import org.apache.marmotta.kiwi.sparql.sail.KiWiSparqlSail; +import org.apache.marmotta.platform.core.api.config.ConfigurationService; +import org.apache.marmotta.platform.core.api.triplestore.NotifyingSailProvider; +import org.apache.marmotta.platform.core.api.triplestore.SesameService; +import org.apache.marmotta.platform.core.events.ConfigurationChangedEvent; +import org.openrdf.sail.NotifyingSail; +import org.openrdf.sail.helpers.NotifyingSailWrapper; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.event.Observes; +import javax.inject.Inject; + +/** + * This service wraps enhanced KiWi SPARQL support around the KiWi Store to improve the performance of typical + * SPARQL queries. + * + * @author Sebastian Schaffert ([email protected]) + */ +@ApplicationScoped +public class SPARQLSailProvider implements NotifyingSailProvider { + + public static final String SPARQL_STRATEGY = "sparql.strategy"; + + + @Inject + private ConfigurationService configurationService; + + @Inject + private SesameService sesameService; + + @Override + public NotifyingSailWrapper createSail(NotifyingSail parent) { + KiWiSparqlSail sail = new KiWiSparqlSail(parent); + + return sail; + } + + public void configurationChanged(@Observes ConfigurationChangedEvent e) { + if(e.containsChangedKey(SPARQL_STRATEGY)) { + sesameService.shutdown(); + sesameService.initialise(); + } + } + + + @Override + public String getName() { + return "SPARQL Optimizer"; + } + + @Override + public boolean isEnabled() { + if("native".equalsIgnoreCase(configurationService.getStringConfiguration(SPARQL_STRATEGY))) { + return true; + } else { + return false; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/platform/marmotta-sparql/src/main/resources/config-defaults.properties ---------------------------------------------------------------------- diff --git a/platform/marmotta-sparql/src/main/resources/config-defaults.properties b/platform/marmotta-sparql/src/main/resources/config-defaults.properties index 529e817..ef5ff2e 100644 --- a/platform/marmotta-sparql/src/main/resources/config-defaults.properties +++ b/platform/marmotta-sparql/src/main/resources/config-defaults.properties @@ -25,31 +25,3 @@ sparql.allow_origin = * # SPARQL queries directly to database queries; more efficient but not tested extensively sparql.strategy = native - -# turn on/off fallback to Sesame in-memory SPARQL evaluation in case the default evaluation strategy fails for -# whatever reason; this is a safe-guard option to always yield the correct results, but suffers the memory -# and performance problems of the in-memory SPARQL evaulation -sparql.fallback = true - -# select the way literal types are handled in SPARQL queries in case they are not correctly stored in the database -# or not properly given in the query; value "strict" means that the evaluator always tries to cast a type -# appropriately, but can result in considerable performance impacts; value "loose" means that all possible -# types are used, ignoring the type specification; value "none" means that no type casting takes place, types -# are used as given by the user (this is the most efficient setting, but may be less tolerant to faulty data or queries) -sparql.native.casttype = none - - -# log SQL statements to the lmf-main.log file for testing and debugging -sparql.native.logsql = false - - -# preload constant nodes in SPARQL expressions using the triple store functionality; constant values in SPARQL -# expressions are substituted with the database ID of the respective nodes; setting this option to true -# will reduce significantly the number of joins needed for a SPARQL query, but can require database access at -# query construction time. -sparql.native.preload_constants = true - -# interpret the SPARQL REDUCED query parameter as distinct; the specification for REDUCED says it is left to the -# query optimizer whether to make results distinct or not; DISTINCT in SQL can introduce significant computational -# overhead, so the default is false -sparql.native.reduced_as_distinct = false http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/8f79ef1a/platform/marmotta-sparql/src/main/resources/config-descriptions.properties ---------------------------------------------------------------------- diff --git a/platform/marmotta-sparql/src/main/resources/config-descriptions.properties b/platform/marmotta-sparql/src/main/resources/config-descriptions.properties index bae7d61..2477ebf 100644 --- a/platform/marmotta-sparql/src/main/resources/config-descriptions.properties +++ b/platform/marmotta-sparql/src/main/resources/config-descriptions.properties @@ -24,34 +24,4 @@ sparql.allow_origin.type = java.lang.String sparql.strategy.description = select the SPARQL evaluation strategy to use (default: sesame); other settings than \ "sesame" allow to translate SPARQL queries directly to database queries; more efficient but not tested extensively -sparql.strategy.type = java.lang.Enum("native"|"sesame") - - -sparql.fallback.description = turn on/off fallback to Sesame in-memory SPARQL evaluation in case the default \ - evaluation strategy fails for whatever reason; this is a safe-guard option to always yield the correct results, \ - but suffers the memory and performance problems of the in-memory SPARQL evaulation -sparql.fallback.type = java.lang.Boolean - -sparql.native.casttype.description = select the way literal types are handled in SPARQL queries in case they are \ - not correctly stored in the database or not properly given in the query; value "strict" means that the evaluator \ - always tries to cast a type appropriately, but can result in considerable performance impacts; value "loose" means \ - that all possible types are used, ignoring the type specification; value "none" means that no type casting takes \ - place, types are used as given by the user (this is the most efficient setting, but may be less tolerant to faulty \ - data or queries) -sparql.native.casttype.type = java.lang.Enum("none"|"loose"|"strict") - - -sparql.native.logsql.description = log SQL statements to the lmf-main.log file for testing and debugging -sparql.native.logsql.type = java.lang.Boolean - - -sparql.native.preload_constants.description = preload constant nodes in SPARQL expressions using the triple store \ - functionality; constant values in SPARQL expressions are substituted with the database ID of the respective nodes; \ - setting this option to true will reduce significantly the number of joins needed for a SPARQL query, but can require \ - database access at query construction time. -sparql.native.preload_constants.type = java.lang.Boolean - -sparql.native.reduced_as_distinct.description = interpret the SPARQL REDUCED query parameter as distinct; the \ - specification for REDUCED says it is left to the query optimizer whether to make results distinct or not; DISTINCT \ - in SQL can introduce significant computational overhead, so the default is false -sparql.native.reduced_as_distinct.type = java.lang.Boolean +sparql.strategy.type = java.lang.Enum("native"|"memory") \ No newline at end of file
