blob: 3a389237de83e5b8dceeb050b248c4a0bad0788c [file] [log] [blame]
/*
* 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.rya.indexing.mongo;
import java.util.List;
import org.apache.rya.api.domain.RyaType;
import org.apache.rya.api.domain.RyaURI;
import org.apache.rya.indexing.entity.EntityIndexOptimizer;
import org.apache.rya.indexing.entity.model.Entity;
import org.apache.rya.indexing.entity.model.Property;
import org.apache.rya.indexing.entity.model.Type;
import org.apache.rya.indexing.entity.query.EntityQueryNode;
import org.apache.rya.indexing.entity.storage.EntityStorage;
import org.apache.rya.indexing.entity.storage.TypeStorage;
import org.apache.rya.mongodb.MongoITBase;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.query.MalformedQueryException;
import org.eclipse.rdf4j.query.algebra.QueryModelNode;
import org.eclipse.rdf4j.query.algebra.StatementPattern;
import org.eclipse.rdf4j.query.algebra.TupleExpr;
import org.eclipse.rdf4j.query.algebra.helpers.AbstractQueryModelVisitor;
import org.eclipse.rdf4j.query.algebra.helpers.StatementPatternCollector;
import org.eclipse.rdf4j.query.parser.sparql.SPARQLParser;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.google.common.collect.ImmutableSet;
public class MongoEntityIndex2IT extends MongoITBase {
private static final Type PERSON_TYPE =
new Type(new RyaURI("urn:person"),
ImmutableSet.<RyaURI>builder()
.add(new RyaURI("urn:name"))
.add(new RyaURI("urn:age"))
.add(new RyaURI("urn:eye"))
.build());
private static final RyaURI RYA_PERSON_TYPE = new RyaURI("urn:person");
private EntityIndexOptimizer optimizer;
private EntityStorage entityStorage;
@Before
public void beforeClass() throws Exception {
optimizer = new EntityIndexOptimizer();
optimizer.setConf(conf);
final TypeStorage typeStorage = optimizer.getTypeStorage();
typeStorage.create(PERSON_TYPE);
final Entity entity = Entity.builder()
.setSubject(new RyaURI("urn:SSN:111-11-1111"))
.setExplicitType(RYA_PERSON_TYPE)
.setProperty(RYA_PERSON_TYPE, new Property(new RyaURI("urn:age"), new RyaType("25")))
.setProperty(RYA_PERSON_TYPE, new Property(new RyaURI("urn:eye"), new RyaType("blue")))
.setProperty(RYA_PERSON_TYPE, new Property(new RyaURI("urn:name"), new RyaType("bob")))
.build();
entityStorage = optimizer.getEntityStorage();
entityStorage.create(entity);
}
@Test()
public void queryIsFullEntity() throws Exception {
// A pattern that has two different subjects.
final String query = "SELECT * WHERE { " +
"<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
"<urn:SSN:111-11-1111> <urn:age> ?age . " +
"<urn:SSN:111-11-1111> <urn:name> ?name . " +
"<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
"}";
final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(query), entityStorage);
assertOptimizer(query, expected);
}
@Test()
public void queryIsPartEntity() throws Exception {
// A pattern that has two different subjects.
final String query = "SELECT * WHERE { " +
"<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
"<urn:SSN:111-11-1111> <urn:age> ?age . " +
"}";
final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(query), entityStorage);
assertOptimizer(query, expected);
}
@Test()
public void queryIsPartEntityandExtra() throws Exception {
// A pattern that has two different subjects.
final String query = "SELECT * WHERE { " +
"<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
"<urn:SSN:111-11-1111> <urn:age> ?age . " +
"<urn:SSN:222-22-2222> <urn:age> ?age . " +
"<urn:SSN:222-22-2222> <urn:eye> ?eye . " +
"<urn:SSN:222-22-2222> <urn:name> ?name . " +
"}";
final String expectedQuery = "SELECT * WHERE { " +
"<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
"<urn:SSN:111-11-1111> <urn:age> ?age . " +
"}";
final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(expectedQuery), entityStorage);
assertOptimizer(query, expected);
}
@Test()
public void queryIsFullEntityWithExtra() throws Exception {
// A pattern that has two different subjects.
final String query = "SELECT * WHERE { " +
"<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
"<urn:SSN:111-11-1111> <urn:age> ?age . " +
"<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
"<urn:SSN:111-11-1111> <urn:name> ?name . " +
"<urn:SSN:222-22-2222> <urn:age> ?age . " +
"<urn:SSN:222-22-2222> <urn:eye> ?eye . " +
"<urn:SSN:222-22-2222> <urn:name> ?name . " +
"}";
final String expectedQuery = "SELECT * WHERE { " +
"<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
"<urn:SSN:111-11-1111> <urn:age> ?age . " +
"<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
"<urn:SSN:111-11-1111> <urn:name> ?name . " +
"}";
final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(expectedQuery), entityStorage);
assertOptimizer(query, expected);
}
@Test()
public void queryIsFullEntityWithOptional() throws Exception {
// A pattern that has two different subjects.
final String query = "SELECT * WHERE { " +
"<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
"<urn:SSN:111-11-1111> <urn:age> ?age . " +
"<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
"<urn:SSN:111-11-1111> <urn:name> ?name . " +
" OPTIONAL{" +
" <urn:SSN:222-22-2222> <urn:age> ?age . " +
" <urn:SSN:222-22-2222> <urn:eye> ?eye . " +
" <urn:SSN:222-22-2222> <urn:name> ?name . " +
" } . " +
"}";
final String expectedQuery = "SELECT * WHERE { " +
"<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
"<urn:SSN:111-11-1111> <urn:age> ?age . " +
"<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
"<urn:SSN:111-11-1111> <urn:name> ?name . " +
"}";
final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(expectedQuery), entityStorage);
assertOptimizer(query, expected);
}
@Test()
public void queryIsSplitEntityWithOptional() throws Exception {
// A pattern that has two different subjects.
final String query = "SELECT * WHERE { " +
"<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
"<urn:SSN:111-11-1111> <urn:age> ?age . " +
"<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
" OPTIONAL{" +
" <urn:SSN:111-11-1111> <urn:name> ?name . " +
" } . " +
"}";
final String expectedQuery = "SELECT * WHERE { " +
"<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
"<urn:SSN:111-11-1111> <urn:age> ?age . " +
"<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
"}";
final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(expectedQuery), entityStorage);
assertOptimizer(query, expected);
}
@Test()
public void queryEntityInOptional() throws Exception {
// A pattern that has two different subjects.
final String query = "SELECT * WHERE { " +
"<urn:SSN:111-11-1111> <urn:age> ?age . " +
"<urn:SSN:111-11-1111> <urn:eye> ?eye . " +
" OPTIONAL{" +
" <urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
" <urn:SSN:111-11-1111> <urn:name> ?name . " +
" } . " +
"}";
final String expectedQuery = "SELECT * WHERE { " +
"<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+
"<urn:SSN:111-11-1111> <urn:name> ?name . " +
"}";
final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(expectedQuery), entityStorage);
assertOptimizer(query, expected);
}
private static List<StatementPattern> getSPs(final String sparql) throws MalformedQueryException {
final StatementPatternCollector spCollector = new StatementPatternCollector();
new SPARQLParser().parseQuery(sparql, null).getTupleExpr().visit(spCollector);
return spCollector.getStatementPatterns();
}
private void assertOptimizer(final String query, final EntityQueryNode expected) throws Exception {
final SPARQLParser parser = new SPARQLParser();
final TupleExpr expr = parser.parseQuery(query, null).getTupleExpr();
optimizer.optimize(expr, null, null);
expr.visit(new EntityFetchingAsserterVisitor(expected));
}
private class EntityFetchingAsserterVisitor extends AbstractQueryModelVisitor<Exception> {
private final EntityQueryNode expected;
public EntityFetchingAsserterVisitor(final EntityQueryNode expected) {
this.expected = expected;
}
@Override
protected void meetNode(final QueryModelNode node) throws Exception {
if(node instanceof EntityQueryNode) {
Assert.assertEquals(expected, node);
} else {
super.meetNode(node);
}
}
}
}