Skip to content

Commit 868dd4b

Browse files
committed
Merge branch 'main' into merge-main-4312
# Conflicts: # assembly-descriptors/pom.xml # assembly/pom.xml # bom/pom.xml # compliance/elasticsearch/pom.xml # compliance/geosparql/pom.xml # compliance/lucene/pom.xml # compliance/model/pom.xml # compliance/pom.xml # compliance/repository/pom.xml # compliance/rio/pom.xml # compliance/solr/pom.xml # compliance/sparql/pom.xml # core/client/pom.xml # core/collection-factory/api/pom.xml # core/collection-factory/mapdb/pom.xml # core/collection-factory/mapdb3/pom.xml # core/collection-factory/pom.xml # core/common/annotation/pom.xml # core/common/exception/pom.xml # core/common/io/pom.xml # core/common/iterator/pom.xml # core/common/order/pom.xml # core/common/pom.xml # core/common/text/pom.xml # core/common/transaction/pom.xml # core/common/xml/pom.xml # core/http/client/pom.xml # core/http/pom.xml # core/http/protocol/pom.xml # core/model-api/pom.xml # core/model-vocabulary/pom.xml # core/model/pom.xml # core/pom.xml # core/query/pom.xml # core/queryalgebra/evaluation/pom.xml # core/queryalgebra/geosparql/pom.xml # core/queryalgebra/model/pom.xml # core/queryalgebra/pom.xml # core/queryparser/api/pom.xml # core/queryparser/pom.xml # core/queryparser/sparql/pom.xml # core/queryrender/pom.xml # core/queryresultio/api/pom.xml # core/queryresultio/binary/pom.xml # core/queryresultio/pom.xml # core/queryresultio/sparqljson/pom.xml # core/queryresultio/sparqlxml/pom.xml # core/queryresultio/text/pom.xml # core/repository/api/pom.xml # core/repository/contextaware/pom.xml # core/repository/dataset/pom.xml # core/repository/event/pom.xml # core/repository/http/pom.xml # core/repository/manager/pom.xml # core/repository/pom.xml # core/repository/sail/pom.xml # core/repository/sparql/pom.xml # core/rio/api/pom.xml # core/rio/binary/pom.xml # core/rio/datatypes/pom.xml # core/rio/hdt/pom.xml # core/rio/jsonld/pom.xml # core/rio/languages/pom.xml # core/rio/n3/pom.xml # core/rio/nquads/pom.xml # core/rio/ntriples/pom.xml # core/rio/pom.xml # core/rio/rdfjson/pom.xml # core/rio/rdfxml/pom.xml # core/rio/trig/pom.xml # core/rio/trix/pom.xml # core/rio/turtle/pom.xml # core/sail/api/pom.xml # core/sail/base/pom.xml # core/sail/elasticsearch-store/pom.xml # core/sail/elasticsearch/pom.xml # core/sail/extensible-store/pom.xml # core/sail/inferencer/pom.xml # core/sail/lmdb/pom.xml # core/sail/lucene-api/pom.xml # core/sail/lucene/pom.xml # core/sail/memory/pom.xml # core/sail/model/pom.xml # core/sail/nativerdf/pom.xml # core/sail/pom.xml # core/sail/shacl/pom.xml # core/sail/solr/pom.xml # core/sparqlbuilder/pom.xml # core/spin/pom.xml # core/storage/pom.xml # examples/pom.xml # pom.xml # spring-components/pom.xml # spring-components/rdf4j-spring-demo/pom.xml # spring-components/rdf4j-spring/pom.xml # spring-components/spring-boot-sparql-web/pom.xml # testsuites/benchmark/pom.xml # testsuites/geosparql/pom.xml # testsuites/lucene/pom.xml # testsuites/model/pom.xml # testsuites/pom.xml # testsuites/queryresultio/pom.xml # testsuites/repository/pom.xml # testsuites/rio/pom.xml # testsuites/sail/pom.xml # testsuites/shacl/pom.xml # testsuites/sparql/pom.xml # tools/config/pom.xml # tools/console/pom.xml # tools/federation/pom.xml # tools/pom.xml # tools/runtime-osgi/pom.xml # tools/runtime/pom.xml # tools/server-spring/pom.xml # tools/server/pom.xml # tools/workbench/pom.xml
2 parents a58ff06 + e0f06ad commit 868dd4b

13 files changed

Lines changed: 1904 additions & 18 deletions

File tree

core/model-vocabulary/src/main/java/org/eclipse/rdf4j/model/vocabulary/GEO.java

Lines changed: 456 additions & 7 deletions
Large diffs are not rendered by default.

core/sail/lucene/src/main/java/org/eclipse/rdf4j/sail/lucene/impl/LuceneDocument.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,12 @@ private void indexShape(Object shape, String field) {
166166
doc.add(f);
167167
}
168168
} else if (shape instanceof double[]) { // WKT:POINT
169-
double point[] = (double[]) shape;
169+
double[] point = (double[]) shape;
170+
171+
for (Field f : LatLonShape.createIndexableFields(GEO_FIELD_PREFIX + field, point[1],
172+
point[0])) {
173+
doc.add(f);
174+
}
170175
doc.add(new LatLonPoint(POINT_FIELD_PREFIX + field, point[1], point[0]));
171176
} else if (shape instanceof Rectangle) { // WKT:ENVELOPE / RECTANGLE
172177
Rectangle box = (Rectangle) shape;

core/sail/lucene/src/test/java/org/eclipse/rdf4j/sail/lucene/impl/LuceneIndexTest.java

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919

2020
import java.io.IOException;
2121
import java.util.HashSet;
22+
import java.util.Iterator;
2223
import java.util.Set;
24+
import java.util.function.Function;
2325

2426
import org.apache.lucene.analysis.en.EnglishAnalyzer;
2527
import org.apache.lucene.analysis.standard.StandardAnalyzer;
@@ -39,12 +41,23 @@
3941
import org.eclipse.rdf4j.common.concurrent.locks.Properties;
4042
import org.eclipse.rdf4j.model.IRI;
4143
import org.eclipse.rdf4j.model.Literal;
44+
import org.eclipse.rdf4j.model.Model;
4245
import org.eclipse.rdf4j.model.Resource;
4346
import org.eclipse.rdf4j.model.Statement;
47+
import org.eclipse.rdf4j.model.Value;
4448
import org.eclipse.rdf4j.model.ValueFactory;
49+
import org.eclipse.rdf4j.model.base.CoreDatatype;
4550
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
51+
import org.eclipse.rdf4j.model.impl.TreeModel;
52+
import org.eclipse.rdf4j.model.vocabulary.GEO;
53+
import org.eclipse.rdf4j.model.vocabulary.GEOF;
54+
import org.eclipse.rdf4j.query.BindingSet;
55+
import org.eclipse.rdf4j.query.TupleQuery;
56+
import org.eclipse.rdf4j.query.TupleQueryResult;
4657
import org.eclipse.rdf4j.repository.sail.SailRepository;
4758
import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection;
59+
import org.eclipse.rdf4j.repository.util.Repositories;
60+
import org.eclipse.rdf4j.sail.evaluation.TupleFunctionEvaluationMode;
4861
import org.eclipse.rdf4j.sail.lucene.LuceneSail;
4962
import org.eclipse.rdf4j.sail.lucene.SearchFields;
5063
import org.eclipse.rdf4j.sail.memory.MemoryStore;
@@ -478,4 +491,85 @@ private void assertNoStatement(Statement statement, Document document) {
478491
* for(String notFound : toFind) { assertEquals("Was the expected text value '" + notFound + "' found?", true,
479492
* false); } }
480493
*/
494+
495+
@Test
496+
public void geoSparqlQueryTest() {
497+
final String prefix = "http://www.example.org/#";
498+
final String prefixes = "PREFIX ex: <" + prefix + ">\n"
499+
+ "PREFIX geof: <" + GEOF.NAMESPACE + ">\n"
500+
+ "PREFIX geo: <" + CoreDatatype.GEO.NAMESPACE + ">\n"
501+
+ "PREFIX uom: <http://www.opengis.net/def/uom/OGC/1.0/>\n";
502+
Model data = new TreeModel();
503+
504+
IRI cp = vf.createIRI(prefix + "cp");
505+
IRI bm = vf.createIRI(prefix + "bm");
506+
IRI nkv = vf.createIRI(prefix + "nkv");
507+
508+
data.add(cp, GEO.AS_WKT, vf.createLiteral("Point(4.38436 45.44917)", CoreDatatype.GEO.WKT_LITERAL));
509+
data.add(bm, GEO.AS_WKT, vf.createLiteral("Point(4.38311 45.45423)", CoreDatatype.GEO.WKT_LITERAL));
510+
data.add(nkv, GEO.AS_WKT, vf.createLiteral("Point(4.87306 45.77903)", CoreDatatype.GEO.WKT_LITERAL));
511+
data.add(vf.createIRI(prefix + "arp"), GEO.AS_WKT,
512+
vf.createLiteral("Point(2.89271 42.69848)", CoreDatatype.GEO.WKT_LITERAL));
513+
514+
String polyVill = "POLYGON((4.864712 45.784405, 4.883165 45.787756, 4.889946 45.785781, 4.904881 45.767403, 4.900761 45.765487, 4.872093 45.770995, 4.86454 45.770457, 4.858789 45.770277, 4.859905 45.784644, 4.864712 45.784405))";
515+
String polySain = "POLYGON((4.380627 45.463983, 4.400539 45.462177, 4.428349 45.436286, 4.399509 45.411346, 4.374447 45.426528, 4.370499 45.450618, 4.380627 45.463983))";
516+
517+
SailRepository m1 = new SailRepository(new MemoryStore());
518+
LuceneSail lc = new LuceneSail();
519+
lc.setBaseSail(new MemoryStore());
520+
lc.setParameter(LuceneSail.WKT_FIELDS, GEO.AS_WKT.toString());
521+
lc.setLuceneIndex(index);
522+
lc.setEvaluationMode(TupleFunctionEvaluationMode.NATIVE);
523+
SailRepository m2 = new SailRepository(lc);
524+
525+
// add test data
526+
Repositories.consume(m1, conn -> conn.add(data));
527+
Repositories.consume(m2, conn -> conn.add(data));
528+
529+
lc.reindex();
530+
531+
Function<TupleQueryResult, Set<Value>> toval = (res) -> {
532+
Set<Value> list = new HashSet<>();
533+
while (res.hasNext()) {
534+
BindingSet next = res.next();
535+
list.add(next.getValue("v"));
536+
}
537+
return list;
538+
};
539+
540+
// test queries
541+
542+
String q0 = prefixes
543+
+ "SELECT * {\n"
544+
+ " ?v geo:asWKT ?loc .\n"
545+
+ " FILTER(geof:distance(\"Point(4.386914 45.440637)\"^^geo:wktLiteral, ?loc, uom:metre) < 10000) \n"
546+
+ "}\n";
547+
Set<Value> q0ex = Set.of(bm, cp);
548+
549+
String q1 = prefixes
550+
+ "SELECT * {\n"
551+
+ " ?v geo:asWKT ?loc .\n"
552+
+ " FILTER(geof:ehContains(\"" + polySain + "\"^^geo:wktLiteral, ?loc)) \n"
553+
+ "}\n";
554+
Set<Value> q1ex = Set.of(bm, cp);
555+
556+
String q2 = prefixes
557+
+ "SELECT * {\n"
558+
+ " ?v geo:asWKT ?loc .\n"
559+
+ " FILTER(geof:ehContains(\"" + polyVill + "\"^^geo:wktLiteral, ?loc)) \n"
560+
+ "}\n";
561+
Set<Value> q2ex = Set.of(nkv);
562+
563+
Set<Value> nlcq0 = Repositories.tupleQuery(m1, q0, toval);
564+
Set<Value> nlcq1 = Repositories.tupleQuery(m1, q1, toval);
565+
Set<Value> nlcq2 = Repositories.tupleQuery(m1, q2, toval);
566+
567+
assertEquals(q0ex, nlcq0);
568+
assertEquals(q1ex, nlcq1);
569+
assertEquals(q2ex, nlcq2);
570+
571+
assertEquals(nlcq0, Repositories.tupleQuery(m2, q0, toval));
572+
assertEquals(nlcq1, Repositories.tupleQuery(m2, q1, toval));
573+
assertEquals(nlcq2, Repositories.tupleQuery(m2, q2, toval));
574+
}
481575
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 Eclipse RDF4J contributors.
3+
*
4+
* All rights reserved. This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Distribution License v1.0
6+
* which accompanies this distribution, and is available at
7+
* http://www.eclipse.org/org/documents/edl-v10.php.
8+
*
9+
* SPDX-License-Identifier: BSD-3-Clause
10+
*******************************************************************************/
11+
package org.eclipse.rdf4j.federated.algebra;
12+
13+
import java.util.List;
14+
15+
import org.eclipse.rdf4j.federated.structures.QueryInfo;
16+
import org.eclipse.rdf4j.federated.util.QueryAlgebraUtil;
17+
import org.eclipse.rdf4j.query.algebra.ArbitraryLengthPath;
18+
import org.eclipse.rdf4j.query.algebra.Var;
19+
20+
/**
21+
* A specialization of {@link ArbitraryLengthPath} to maintain the {@link QueryInfo}
22+
*
23+
* @author Andreas Schwarte
24+
*/
25+
public class FedXArbitraryLengthPath extends ArbitraryLengthPath implements FedXTupleExpr {
26+
27+
private static final long serialVersionUID = -7512248084095130084L;
28+
29+
private final QueryInfo queryInfo;
30+
31+
public FedXArbitraryLengthPath(ArbitraryLengthPath path, QueryInfo queryInfo) {
32+
super(path.getScope(), clone(path.getSubjectVar()), path.getPathExpression(), clone(path.getObjectVar()),
33+
clone(path.getContextVar()), path.getMinLength());
34+
this.queryInfo = queryInfo;
35+
}
36+
37+
private static Var clone(Var var) {
38+
if (var == null) {
39+
return null;
40+
}
41+
return var.clone();
42+
}
43+
44+
@Override
45+
public List<String> getFreeVars() {
46+
return List.copyOf(QueryAlgebraUtil.getFreeVars(getPathExpression()));
47+
}
48+
49+
@Override
50+
public QueryInfo getQueryInfo() {
51+
return queryInfo;
52+
}
53+
54+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 Eclipse RDF4J contributors.
3+
*
4+
* All rights reserved. This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Distribution License v1.0
6+
* which accompanies this distribution, and is available at
7+
* http://www.eclipse.org/org/documents/edl-v10.php.
8+
*
9+
* SPDX-License-Identifier: BSD-3-Clause
10+
*******************************************************************************/
11+
package org.eclipse.rdf4j.federated.algebra;
12+
13+
import java.util.List;
14+
15+
import org.eclipse.rdf4j.federated.structures.QueryInfo;
16+
import org.eclipse.rdf4j.query.algebra.StatementPattern.Scope;
17+
import org.eclipse.rdf4j.query.algebra.Var;
18+
import org.eclipse.rdf4j.query.algebra.ZeroLengthPath;
19+
20+
/**
21+
* A specialization of {@link ZeroLengthPath} that keeps track of {@link QueryInfo} and statement sources.
22+
*
23+
* @author Andreas Schwarte
24+
*/
25+
public class FedXZeroLengthPath extends ZeroLengthPath implements QueryRef {
26+
27+
private static final long serialVersionUID = 2241037911187178861L;
28+
29+
private final QueryInfo queryInfo;
30+
31+
private final List<StatementSource> statementSources;
32+
33+
public FedXZeroLengthPath(Scope scope, Var subjVar, Var objVar, Var conVar, QueryInfo queryInfo,
34+
List<StatementSource> statementSources) {
35+
super(scope, subjVar, objVar, conVar);
36+
this.queryInfo = queryInfo;
37+
this.statementSources = statementSources;
38+
}
39+
40+
public List<StatementSource> getStatementSources() {
41+
return statementSources;
42+
}
43+
44+
@Override
45+
public QueryInfo getQueryInfo() {
46+
return queryInfo;
47+
}
48+
49+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 Eclipse RDF4J contributors.
3+
*
4+
* All rights reserved. This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Distribution License v1.0
6+
* which accompanies this distribution, and is available at
7+
* http://www.eclipse.org/org/documents/edl-v10.php.
8+
*
9+
* SPDX-License-Identifier: BSD-3-Clause
10+
*******************************************************************************/
11+
package org.eclipse.rdf4j.federated.algebra;
12+
13+
import org.eclipse.rdf4j.query.algebra.AbstractQueryModelNode;
14+
import org.eclipse.rdf4j.query.algebra.QueryModelNode;
15+
import org.eclipse.rdf4j.query.algebra.QueryModelVisitor;
16+
17+
/**
18+
* An artificial holder node serving as parent holder to allow replacement.
19+
*/
20+
public class HolderNode extends AbstractQueryModelNode {
21+
22+
private static final long serialVersionUID = -4689963986499825771L;
23+
private QueryModelNode child;
24+
25+
public HolderNode(QueryModelNode child) {
26+
super();
27+
setChild(child);
28+
}
29+
30+
public void setChild(QueryModelNode child) {
31+
this.child = child;
32+
this.child.setParentNode(this);
33+
}
34+
35+
@Override
36+
public <X extends Exception> void visitChildren(QueryModelVisitor<X> visitor) throws X {
37+
child.visit(visitor);
38+
}
39+
40+
@Override
41+
public <X extends Exception> void visit(QueryModelVisitor<X> visitor) throws X {
42+
visitor.meetOther(this);
43+
}
44+
45+
@Override
46+
public void replaceChildNode(QueryModelNode current, QueryModelNode replacement) {
47+
if (child.equals(current)) {
48+
setChild(replacement);
49+
50+
}
51+
}
52+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 Eclipse RDF4J contributors.
3+
*
4+
* All rights reserved. This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Distribution License v1.0
6+
* which accompanies this distribution, and is available at
7+
* http://www.eclipse.org/org/documents/edl-v10.php.
8+
*
9+
* SPDX-License-Identifier: BSD-3-Clause
10+
*******************************************************************************/
11+
package org.eclipse.rdf4j.federated.evaluation;
12+
13+
import java.util.List;
14+
import java.util.function.Supplier;
15+
16+
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
17+
import org.eclipse.rdf4j.federated.algebra.FedXZeroLengthPath;
18+
import org.eclipse.rdf4j.federated.algebra.StatementSource;
19+
import org.eclipse.rdf4j.federated.evaluation.iterator.FedXZeroLengthPathIteration;
20+
import org.eclipse.rdf4j.federated.structures.QueryInfo;
21+
import org.eclipse.rdf4j.model.Value;
22+
import org.eclipse.rdf4j.query.BindingSet;
23+
import org.eclipse.rdf4j.query.QueryEvaluationException;
24+
import org.eclipse.rdf4j.query.algebra.Var;
25+
import org.eclipse.rdf4j.query.algebra.evaluation.EvaluationStrategy;
26+
import org.eclipse.rdf4j.query.algebra.evaluation.QueryEvaluationStep;
27+
import org.eclipse.rdf4j.query.algebra.evaluation.QueryValueEvaluationStep;
28+
import org.eclipse.rdf4j.query.algebra.evaluation.impl.QueryEvaluationContext;
29+
import org.eclipse.rdf4j.query.algebra.evaluation.impl.evaluationsteps.ZeroLengthPathEvaluationStep;
30+
31+
/**
32+
* An evaluation step used for {@link FedXZeroLengthPath}.
33+
*
34+
* @see ZeroLengthPathEvaluationStep
35+
*/
36+
public final class FedXZeroLengthPathEvaluationStep implements QueryEvaluationStep {
37+
private final Var subjectVar;
38+
private final Var objVar;
39+
private final Var contextVar;
40+
private final QueryValueEvaluationStep subPrep;
41+
private final QueryValueEvaluationStep objPrep;
42+
private final EvaluationStrategy strategy;
43+
private final QueryEvaluationContext context;
44+
45+
private final Supplier<List<StatementSource>> statementSources;
46+
private final Supplier<QueryInfo> queryInfo;
47+
48+
public FedXZeroLengthPathEvaluationStep(Var subjectVar, Var objVar, Var contextVar,
49+
QueryValueEvaluationStep subPrep,
50+
QueryValueEvaluationStep objPrep, EvaluationStrategy strategy, QueryEvaluationContext context,
51+
Supplier<List<StatementSource>> statementSources, Supplier<QueryInfo> queryInfo) {
52+
this.subjectVar = subjectVar;
53+
this.objVar = objVar;
54+
this.contextVar = contextVar;
55+
this.subPrep = subPrep;
56+
this.objPrep = objPrep;
57+
this.strategy = strategy;
58+
this.context = context;
59+
60+
this.statementSources = statementSources;
61+
this.queryInfo = queryInfo;
62+
}
63+
64+
@Override
65+
public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(BindingSet bindings) {
66+
Value subj = null;
67+
try {
68+
subj = subPrep.evaluate(bindings);
69+
} catch (QueryEvaluationException ignored) {
70+
}
71+
72+
Value obj = null;
73+
try {
74+
obj = objPrep.evaluate(bindings);
75+
} catch (QueryEvaluationException ignored) {
76+
}
77+
78+
if (subj != null && obj != null) {
79+
if (!subj.equals(obj)) {
80+
return EMPTY_ITERATION;
81+
}
82+
}
83+
return getZeroLengthPathIterator(bindings, subjectVar, objVar, contextVar, subj, obj, context);
84+
}
85+
86+
protected FedXZeroLengthPathIteration getZeroLengthPathIterator(final BindingSet bindings, final Var subjectVar,
87+
final Var objVar, final Var contextVar, Value subj, Value obj, QueryEvaluationContext context) {
88+
return new FedXZeroLengthPathIteration(strategy, subjectVar, objVar, subj, obj, contextVar, bindings, context,
89+
queryInfo.get(), statementSources.get());
90+
}
91+
}

0 commit comments

Comments
 (0)