Skip to content

Commit c58eb52

Browse files
authored
Merge main into develop (#5011)
2 parents a58ff06 + 510e719 commit c58eb52

15 files changed

Lines changed: 2089 additions & 27 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/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/iterator/PathIteration.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.function.Predicate;
2121

2222
import org.eclipse.rdf4j.collection.factory.api.CollectionFactory;
23+
import org.eclipse.rdf4j.common.annotation.InternalUseOnly;
2324
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
2425
import org.eclipse.rdf4j.common.iteration.LookAheadIteration;
2526
import org.eclipse.rdf4j.model.Value;
@@ -130,7 +131,8 @@ public PathIteration(EvaluationStrategy strategy, Scope scope, Var startVar,
130131
* @param s the name of the variable to see if it is in the bindingset
131132
* @return the value of the start or end or if asked for a different field a null.
132133
*/
133-
private static final BiConsumer<Value, MutableBindingSet> getSet(String s) {
134+
@InternalUseOnly
135+
public static final BiConsumer<Value, MutableBindingSet> getSet(String s) {
134136
switch (s) {
135137
case START:
136138
return (v, vp) -> ((ValuePair) vp).startValue = v;
@@ -149,7 +151,7 @@ private static final BiConsumer<Value, MutableBindingSet> getSet(String s) {
149151
* @param s the name of the variable to see if it is in the bindingset
150152
* @return the value of the start or end, if asked for a different field throw an illegalstate exception
151153
*/
152-
private static final Function<BindingSet, Value> getGet(String s) {
154+
public static final Function<BindingSet, Value> getGet(String s) {
153155
switch (s) {
154156
case START:
155157
return (vp) -> ((ValuePair) vp).startValue;
@@ -168,7 +170,7 @@ private static final Function<BindingSet, Value> getGet(String s) {
168170
* @param s the name of the variable to see if it is in the bindingset
169171
* @return true if start or end is not null, if asked for a different field throw an illegalstate exception
170172
*/
171-
private static final Predicate<BindingSet> getHas(String s) {
173+
public static final Predicate<BindingSet> getHas(String s) {
172174
switch (s) {
173175
case START:
174176
return (vp) -> ((ValuePair) vp).startValue != null;
@@ -431,7 +433,7 @@ protected boolean isUnbound(Var var, BindingSet bindings) {
431433
* A specialized BingingSet that can only hold the start and end values of a Path. Minimizing unneeded memory use,
432434
* and allows specialization in the sets required to answer this part of a query.
433435
*/
434-
protected static class ValuePair implements MutableBindingSet {
436+
public static class ValuePair implements MutableBindingSet {
435437
private static final long serialVersionUID = 1L;
436438

437439
private Value startValue;
@@ -614,7 +616,7 @@ public void meet(Var var) {
614616
QueryModelNode parent = var.getParentNode();
615617
parent.replaceChildNode(var, replacement.clone());
616618
} else if (replaceAnons && var.isAnonymous() && !var.hasValue()) {
617-
String varName = "anon-replace-" + var.getName() + index;
619+
String varName = "anon_replace_" + var.getName() + index;
618620
Var replacementVar = createAnonVar(varName, null, true);
619621
QueryModelNode parent = var.getParentNode();
620622
parent.replaceChildNode(var, replacementVar);

core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/iterator/ZeroLengthPathIteration.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ public class ZeroLengthPathIteration extends LookAheadIteration<BindingSet> {
3838

3939
private static final Literal SUBJECT = SimpleValueFactory.getInstance().createLiteral("subject");
4040

41-
public static final String ANON_SUBJECT_VAR = "zero-length-internal-start";
41+
public static final String ANON_SUBJECT_VAR = "zero_length_internal_start";
4242

43-
public static final String ANON_PREDICATE_VAR = "zero-length-internal-pred";
43+
public static final String ANON_PREDICATE_VAR = "zero_length_internal_pred";
4444

45-
public static final String ANON_OBJECT_VAR = "zero-length-internal-end";
45+
public static final String ANON_OBJECT_VAR = "zero_length_internal_end";
4646

47-
public static final String ANON_SEQUENCE_VAR = "zero-length-internal-seq";
47+
public static final String ANON_SEQUENCE_VAR = "zero_length_internal_seq";
4848

4949
private QueryBindingSet result;
5050

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+
}

0 commit comments

Comments
 (0)