blob: 59d2a3f7afcc179362ab5d196f017b054d2ab6b9 [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.atlas.repository.graph;
import org.apache.atlas.AtlasException;
import org.apache.atlas.gremlin.GremlinExpressionFactory;
import org.apache.atlas.gremlin.optimizer.GremlinQueryOptimizer;
import org.apache.atlas.gremlin.optimizer.RangeFinder;
import org.apache.atlas.groovy.AbstractFunctionExpression;
import org.apache.atlas.groovy.FunctionCallExpression;
import org.apache.atlas.groovy.GroovyExpression;
import org.apache.atlas.groovy.IdentifierExpression;
import org.apache.atlas.groovy.LiteralExpression;
import org.apache.atlas.groovy.TraversalStepType;
import org.apache.atlas.query.GraphPersistenceStrategies;
import org.apache.atlas.query.TypeUtils.FieldInfo;
import org.apache.atlas.repository.Constants;
import org.apache.atlas.repository.MetadataRepository;
import org.apache.atlas.repository.RepositoryException;
import org.apache.atlas.repository.graphdb.AtlasEdgeDirection;
import org.apache.atlas.repository.graphdb.AtlasGraph;
import org.apache.atlas.repository.graphdb.GremlinVersion;
import org.apache.atlas.typesystem.types.AttributeDefinition;
import org.apache.atlas.typesystem.types.AttributeInfo;
import org.apache.atlas.typesystem.types.DataTypes;
import org.apache.atlas.typesystem.types.IDataType;
import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.TypeSystem;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
public abstract class AbstractGremlinQueryOptimizerTest implements IAtlasGraphProvider {
protected abstract GremlinExpressionFactory getFactory();
private MetadataRepository repo;
private final GraphPersistenceStrategies STRATEGY = mock(GraphPersistenceStrategies.class);
@BeforeClass
public void setUp() {
GremlinQueryOptimizer.reset();
GremlinQueryOptimizer.setExpressionFactory(getFactory());
when(STRATEGY.typeAttributeName()).thenReturn(Constants.ENTITY_TYPE_PROPERTY_KEY);
when(STRATEGY.superTypeAttributeName()).thenReturn(Constants.SUPER_TYPES_PROPERTY_KEY);
repo = new GraphBackedMetadataRepository(this, new HardDeleteHandler(TypeSystem.getInstance()));
}
private FieldInfo getTestFieldInfo() throws AtlasException {
AttributeDefinition def = new AttributeDefinition("foo", DataTypes.STRING_TYPE.getName(), Multiplicity.REQUIRED, false, null);
AttributeInfo attrInfo = new AttributeInfo(TypeSystem.getInstance(), def, null);
return new FieldInfo(DataTypes.STRING_TYPE, attrInfo, null, null);
}
private GroovyExpression getVerticesExpression() {
IdentifierExpression g = new IdentifierExpression("g");
return new FunctionCallExpression(TraversalStepType.START, g, "V");
}
@Test
public void testPullHasExpressionsOutOfAnd() throws AtlasException {
GroovyExpression expr1 = makeOutExpression(null, "out1");
GroovyExpression expr2 = makeOutExpression(null, "out2");
GroovyExpression expr3 = makeHasExpression("prop1","Fred");
GroovyExpression expr4 = makeHasExpression("prop2","George");
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "and", Arrays.asList(expr1, expr2, expr3, expr4));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestPullHasExpressionsOutOfHas());
}
protected abstract String getExpectedGremlinForTestPullHasExpressionsOutOfHas();
@Test
public void testOrGrouping() throws AtlasException {
GroovyExpression expr1 = makeOutExpression(null, "out1");
GroovyExpression expr2 = makeOutExpression(null, "out2");
GroovyExpression expr3 = makeHasExpression("prop1","Fred");
GroovyExpression expr4 = makeHasExpression("prop2","George");
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "or", Arrays.asList(expr1, expr2, expr3, expr4));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestOrGrouping());
}
protected abstract String getExpectedGremlinForTestOrGrouping();
@Test
public void testAndOfOrs() throws AtlasException {
GroovyExpression or1Cond1 = makeHasExpression("p1","e1");
GroovyExpression or1Cond2 = makeHasExpression("p2","e2");
GroovyExpression or2Cond1 = makeHasExpression("p3","e3");
GroovyExpression or2Cond2 = makeHasExpression("p4","e4");
GroovyExpression or1 = getFactory().generateLogicalExpression(null, "or", Arrays.asList(or1Cond1, or1Cond2));
GroovyExpression or2 = getFactory().generateLogicalExpression(null, "or", Arrays.asList(or2Cond1, or2Cond2));
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "and", Arrays.asList(or1, or2));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestAndOfOrs());
}
protected abstract String getExpectedGremlinForTestAndOfOrs();
@Test
public void testAndWithMultiCallArguments() throws AtlasException {
GroovyExpression cond1 = makeHasExpression("p1","e1");
GroovyExpression cond2 = makeHasExpression(cond1, "p2","e2");
GroovyExpression cond3 = makeHasExpression("p3","e3");
GroovyExpression cond4 = makeHasExpression(cond3, "p4","e4");
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "and", Arrays.asList(cond2, cond4));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestAndWithMultiCallArguments());
}
protected abstract String getExpectedGremlinForTestAndWithMultiCallArguments();
@Test
public void testOrOfAnds() throws AtlasException {
GroovyExpression or1Cond1 = makeHasExpression("p1","e1");
GroovyExpression or1Cond2 = makeHasExpression("p2","e2");
GroovyExpression or2Cond1 = makeHasExpression("p3","e3");
GroovyExpression or2Cond2 = makeHasExpression("p4","e4");
GroovyExpression or1 = getFactory().generateLogicalExpression(null, "and", Arrays.asList(or1Cond1, or1Cond2));
GroovyExpression or2 = getFactory().generateLogicalExpression(null, "and", Arrays.asList(or2Cond1, or2Cond2));
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "or", Arrays.asList(or1, or2));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestOrOfAnds());
}
protected abstract String getExpectedGremlinForTestOrOfAnds();
@Test
public void testHasNotMovedToResult() throws AtlasException {
GroovyExpression toOptimize = getVerticesExpression();
GroovyExpression or1Cond1 = makeHasExpression("p1","e1");
GroovyExpression or1Cond2 = makeHasExpression("p2","e2");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(or1Cond1, or1Cond2));
toOptimize = makeHasExpression(toOptimize, "p3","e3");
toOptimize = getFactory().generateAliasExpression(toOptimize, "_src");
toOptimize = getFactory().generateSelectExpression(toOptimize, Collections.singletonList(new LiteralExpression("src1")), Collections.<GroovyExpression>singletonList(new IdentifierExpression("it")));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(),
getExpectedGremlinForTestHasNotMovedToResult());
}
protected abstract String getExpectedGremlinForTestHasNotMovedToResult();
@Test
public void testOptimizeLoopExpression() throws AtlasException {
GroovyExpression input = getVerticesExpression();
input = getFactory().generateTypeTestExpression(STRATEGY, input, "DataSet", TestIntSequence.INSTANCE).get(0);
input = makeHasExpression(input, "name","Fred");
input = getFactory().generateAliasExpression(input, "label");
GroovyExpression loopExpr = getFactory().getLoopExpressionParent(input);
loopExpr = getFactory().generateAdjacentVerticesExpression(loopExpr, AtlasEdgeDirection.IN, "inputTables");
loopExpr = getFactory().generateAdjacentVerticesExpression(loopExpr, AtlasEdgeDirection.OUT, "outputTables");
GroovyExpression result = getFactory().generateLoopExpression(input, STRATEGY, DataTypes.STRING_TYPE, loopExpr, "label", null);
result = getFactory().generateToListExpression(result);
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(result);
assertEquals(optimized.toString(), getExpectedGremlinForOptimizeLoopExpression());
}
protected abstract String getExpectedGremlinForOptimizeLoopExpression();
@Test
public void testLongStringEndingWithOr() throws AtlasException {
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = makeHasExpression(toOptimize, "name","Fred");
toOptimize = makeHasExpression(toOptimize, "age","13");
toOptimize = makeOutExpression(toOptimize, "livesIn");
toOptimize = makeHasExpression(toOptimize, "state","Massachusetts");
GroovyExpression or1cond1 = makeHasExpression("p1", "e1");
GroovyExpression or1cond2 = makeHasExpression("p2", "e2");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(or1cond1, or1cond2));
GroovyExpression or2cond1 = makeHasExpression("p3", "e3");
GroovyExpression or2cond2 = makeHasExpression("p4", "e4");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(or2cond1, or2cond2));
toOptimize = makeHasExpression(toOptimize, "p5","e5");
toOptimize = makeHasExpression(toOptimize, "p6","e6");
GroovyExpression or3cond1 = makeHasExpression("p7", "e7");
GroovyExpression or3cond2 = makeHasExpression("p8", "e8");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(or3cond1, or3cond2));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestLongStringEndingWithOr());
}
protected abstract String getExpectedGremlinForTestLongStringEndingWithOr();
@Test
public void testLongStringNotEndingWithOr() throws AtlasException {
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = makeHasExpression(toOptimize, "name","Fred");
toOptimize = makeHasExpression(toOptimize, "age","13");
toOptimize = makeOutExpression(toOptimize, "livesIn");
toOptimize = makeHasExpression(toOptimize, "state","Massachusetts");
GroovyExpression or1cond1 = makeHasExpression("p1", "e1");
GroovyExpression or1cond2 = makeHasExpression("p2", "e2");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(or1cond1, or1cond2));
GroovyExpression or2cond1 = makeHasExpression("p3", "e3");
GroovyExpression or2cond2 = makeHasExpression("p4", "e4");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(or2cond1, or2cond2));
toOptimize = makeHasExpression(toOptimize, "p5","e5");
toOptimize = makeHasExpression(toOptimize, "p6","e6");
GroovyExpression or3cond1 = makeHasExpression("p7", "e7");
GroovyExpression or3cond2 = makeHasExpression("p8", "e8");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(or3cond1, or3cond2));
toOptimize = makeHasExpression(toOptimize, "p9","e9");
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestLongStringNotEndingWithOr());
}
protected abstract String getExpectedGremlinForTestLongStringNotEndingWithOr();
@Test
public void testToListConversion() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("prop1","Fred");
GroovyExpression expr2 = makeHasExpression("prop2","George");
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "or", Arrays.asList(expr1, expr2));
toOptimize = new FunctionCallExpression(TraversalStepType.END, toOptimize,"toList");
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestToListConversion());
}
protected abstract String getExpectedGremlinForTestToListConversion();
@Test
public void testToListWithExtraStuff() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("prop1","Fred");
GroovyExpression expr2 = makeHasExpression("prop2","George");
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "or", Arrays.asList(expr1, expr2));
toOptimize = new FunctionCallExpression(TraversalStepType.END, toOptimize,"toList");
toOptimize = new FunctionCallExpression(toOptimize,"size");
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestToListWithExtraStuff());
}
protected abstract String getExpectedGremlinForTestToListWithExtraStuff();
public void testAddClosureWithExitExpressionDifferentFromExpr() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("prop1","Fred");
GroovyExpression expr2 = makeHasExpression("prop2","George");
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "or", Arrays.asList(expr1, expr2));
toOptimize = makeOutExpression(toOptimize, "knows");
toOptimize = makeOutExpression(toOptimize, "livesIn");
toOptimize = new FunctionCallExpression(TraversalStepType.END, toOptimize,"toList");
toOptimize = new FunctionCallExpression(toOptimize,"size");
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestAddClosureWithExitExpressionDifferentFromExpr());
}
protected abstract String getExpectedGremlinForTestAddClosureWithExitExpressionDifferentFromExpr();
@Test
public void testAddClosureNoExitExpression() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("prop1","Fred");
GroovyExpression expr2 = makeHasExpression("prop2","George");
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "or", Arrays.asList(expr1, expr2));
toOptimize = makeOutExpression(toOptimize, "knows");
toOptimize = makeOutExpression(toOptimize, "livesIn");
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestAddClosureNoExitExpression());
}
protected abstract String getExpectedGremlinForTestAddClosureNoExitExpression();
private GroovyExpression makeOutExpression(GroovyExpression parent, String label) {
return getFactory().generateAdjacentVerticesExpression(parent, AtlasEdgeDirection.OUT, label);
}
@Test
public void testAddClosureWithExitExpressionEqualToExpr() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("prop1","Fred");
GroovyExpression expr2 = makeHasExpression("prop2","George");
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "or", Arrays.asList(expr1, expr2));
toOptimize = makeOutExpression(toOptimize, "knows");
toOptimize = makeOutExpression(toOptimize, "livesIn");
toOptimize = new FunctionCallExpression(TraversalStepType.END, toOptimize,"toList");
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestAddClosureWithExitExpressionEqualToExpr());
}
protected abstract String getExpectedGremlinForTestAddClosureWithExitExpressionEqualToExpr();
@Test
public void testClosureNotCreatedWhenNoOrs() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("prop1","Fred");
GroovyExpression expr2 = makeHasExpression("prop2","George");
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "and", Arrays.asList(expr1, expr2));
toOptimize = makeOutExpression(toOptimize, "knows");
toOptimize = makeOutExpression(toOptimize, "livesIn");
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestClosureNotCreatedWhenNoOrs());
}
protected abstract String getExpectedGremlinForTestClosureNotCreatedWhenNoOrs();
private GroovyExpression makeHasExpression(String name, String value) throws AtlasException {
return makeHasExpression(null, name, value);
}
private GroovyExpression makeHasExpression(GroovyExpression parent, String name, String value) throws AtlasException {
return getFactory().generateHasExpression(STRATEGY, parent, name, "=", new LiteralExpression(value), getTestFieldInfo());
}
private GroovyExpression makeFieldExpression(GroovyExpression parent, String fieldName) throws AtlasException {
return getFactory().generateFieldExpression(parent, getTestFieldInfo(), fieldName, false);
}
@Test
public void testOrFollowedByAnd() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("name","Fred");
GroovyExpression expr2 = makeHasExpression("name","George");
GroovyExpression expr3 = makeHasExpression("age","13");
GroovyExpression expr4 = makeHasExpression("age","14");
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "or", Arrays.asList(expr1,expr2));
toOptimize = getFactory().generateLogicalExpression(toOptimize, "and", Arrays.asList(expr3, expr4));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestOrFollowedByAnd());
}
protected abstract String getExpectedGremlinForTestOrFollowedByAnd();
@Test
public void testOrFollowedByOr() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("name","Fred");
GroovyExpression expr2 = makeHasExpression("name","George");
GroovyExpression expr3 = makeHasExpression("age","13");
GroovyExpression expr4 = makeHasExpression("age","14");
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "or", Arrays.asList(expr1,expr2));
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr3, expr4));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestOrFollowedByOr());
}
protected abstract String getExpectedGremlinForTestOrFollowedByOr();
@Test
public void testMassiveOrExpansion() throws AtlasException {
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = makeHasExpression(toOptimize, "h1","h2");
toOptimize = makeHasExpression(toOptimize, "h3","h4");
for(int i = 0; i < 5; i++) {
GroovyExpression expr1 = makeHasExpression("p1" + i,"e1" + i);
GroovyExpression expr2 = makeHasExpression("p2" + i,"e2" + i);
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr1,expr2));
toOptimize = makeHasExpression(toOptimize, "ha" + i,"hb" + i);
toOptimize = makeHasExpression(toOptimize, "hc" + i,"hd" + i);
}
toOptimize = makeHasExpression(toOptimize, "h5","h6");
toOptimize = makeHasExpression(toOptimize, "h7","h8");
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestMassiveOrExpansion());
}
protected abstract String getExpectedGremlinForTestMassiveOrExpansion();
@Test
public void testAndFollowedByAnd() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("name","Fred");
GroovyExpression expr2 = makeHasExpression("name","George");
GroovyExpression expr3 = makeHasExpression("age","13");
GroovyExpression expr4 = makeHasExpression("age","14");
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "and", Arrays.asList(expr1,expr2));
toOptimize = getFactory().generateLogicalExpression(toOptimize, "and", Arrays.asList(expr3, expr4));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestAndFollowedByAnd());
}
protected abstract String getExpectedGremlinForTestAndFollowedByAnd();
@Test
public void testAndFollowedByOr() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("name","Fred");
GroovyExpression expr2 = makeHasExpression("name","George");
GroovyExpression expr3 = makeHasExpression("age","13");
GroovyExpression expr4 = makeHasExpression("age","14");
GroovyExpression toOptimize = getFactory().generateLogicalExpression(getVerticesExpression(), "and", Arrays.asList(expr1,expr2));
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr3, expr4));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestAndFollowedByOr());
}
protected abstract String getExpectedGremlinForTestAndFollowedByOr();
@Test
public void testInitialAlias() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("name","Fred");
GroovyExpression expr2 = makeHasExpression("name","George");
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = getFactory().generateAliasExpression(toOptimize, "x");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr1, expr2));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestInitialAlias());
}
protected abstract String getExpectedGremlinForTestInitialAlias();
@Test
public void testFinalAlias() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("name","Fred");
GroovyExpression expr2 = makeHasExpression("name","George");
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr1, expr2));
toOptimize = getFactory().generateAliasExpression(toOptimize, "x");
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestFinalAlias());
}
protected abstract String getExpectedGremlinForTestFinalAlias();
@Test
public void testAliasInMiddle() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("name","Fred");
GroovyExpression expr2 = makeHasExpression("name","George");
GroovyExpression expr3 = makeHasExpression("age","13");
GroovyExpression expr4 = makeHasExpression("age","14");
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr1, expr2));
toOptimize = getFactory().generateAliasExpression(toOptimize, "x");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr3, expr4));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestAliasInMiddle());
}
protected abstract String getExpectedGremlinForTestAliasInMiddle();
@Test
public void testMultipleAliases() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("name","Fred");
GroovyExpression expr2 = makeHasExpression("name","George");
GroovyExpression expr3 = makeHasExpression("age","13");
GroovyExpression expr4 = makeHasExpression("age","14");
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr1, expr2));
toOptimize = getFactory().generateAliasExpression(toOptimize, "x");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr3, expr4));
toOptimize = getFactory().generateAliasExpression(toOptimize, "y");
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGreminForTestMultipleAliases());
}
protected abstract String getExpectedGreminForTestMultipleAliases();
@Test
public void testAliasInOrExpr() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("name","Fred");
GroovyExpression expr2 = getFactory().generateAliasExpression(makeHasExpression("name","George"), "george");
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr1, expr2));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestAliasInOrExpr());
}
protected abstract String getExpectedGremlinForTestAliasInOrExpr();
@Test
public void testAliasInAndExpr() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("name","Fred");
GroovyExpression expr2 = getFactory().generateAliasExpression(makeHasExpression("name","George"), "george");
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = getFactory().generateLogicalExpression(toOptimize, "and", Arrays.asList(expr1, expr2));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
//expression with alias cannot currently be pulled out of the and
assertEquals(optimized.toString(), getExpectedGremlinForTestAliasInAndExpr());
}
protected abstract String getExpectedGremlinForTestAliasInAndExpr();
@Test
public void testFlatMapExprInAnd() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("name","Fred");
GroovyExpression expr2 = makeHasExpression(makeOutExpression(null,"knows"), "name","George");
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = getFactory().generateLogicalExpression(toOptimize, "and", Arrays.asList(expr1, expr2));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestFlatMapExprInAnd());
}
protected abstract String getExpectedGremlinForTestFlatMapExprInAnd();
@Test
public void testFlatMapExprInOr() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("name","Fred");
GroovyExpression expr2 = makeHasExpression(makeOutExpression(null,"knows"), "name","George");
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr1, expr2));
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestFlatMapExprInOr());
}
protected abstract String getExpectedGremlinForTestFlatMapExprInOr();
@Test
public void testFieldExpressionPushedToResultExpression() throws AtlasException {
GroovyExpression expr1 = makeHasExpression("name","Fred");
GroovyExpression expr2 = makeHasExpression(makeOutExpression(null,"knows"), "name","George");
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr1, expr2));
toOptimize = makeFieldExpression(toOptimize, "name");
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestFieldExpressionPushedToResultExpression());
}
protected abstract String getExpectedGremlinForTestFieldExpressionPushedToResultExpression();
@Test
public void testOrWithNoChildren() throws AtlasException {
GroovyExpression toOptimize = getVerticesExpression();
GroovyExpression expr1 = makeHasExpression(toOptimize, "name","Fred");
toOptimize = getFactory().generateLogicalExpression(expr1, "or", Collections.<GroovyExpression>emptyList());
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
//or with no children matches no vertices
assertEquals(optimized.toString(), getExpectedGremlinFortestOrWithNoChildren());
}
protected abstract String getExpectedGremlinFortestOrWithNoChildren();
@Test
public void testFinalAliasNeeded() throws AtlasException {
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = makeHasExpression(toOptimize, "name", "Fred");
toOptimize = getFactory().generateAliasExpression(toOptimize, "person");
toOptimize = makeOutExpression(toOptimize, "livesIn");
GroovyExpression isChicago = makeHasExpression(null, "name", "Chicago");
GroovyExpression isBoston = makeHasExpression(null, "name", "Boston");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(isChicago, isBoston));
toOptimize = getFactory().generateAliasExpression(toOptimize, "city");
toOptimize = makeOutExpression(toOptimize, "state");
toOptimize = makeHasExpression(toOptimize, "name", "Massachusetts");
toOptimize = getFactory().generatePathExpression(toOptimize);
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestFinalAliasNeeded());
}
protected abstract String getExpectedGremlinForTestFinalAliasNeeded();
@Test
public void testSimpleRangeExpression() throws AtlasException {
GroovyExpression expr1 = makeHasExpression(null, "name","Fred");
GroovyExpression expr2 = makeHasExpression(null, "name","George");
GroovyExpression expr3 = makeHasExpression(null, "age","34");
GroovyExpression expr4 = makeHasExpression(null, "size","small");
GroovyExpression toOptimize = getVerticesExpression();
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr1, expr2));
toOptimize = getFactory().generateLogicalExpression(toOptimize, "and", Collections.singletonList(expr3));
toOptimize = getFactory().generateAdjacentVerticesExpression(toOptimize, AtlasEdgeDirection.OUT, "eats");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "and", Collections.singletonList(expr4));
toOptimize = makeHasExpression(toOptimize, "color","blue");
toOptimize = getFactory().generateRangeExpression(toOptimize, 0, 10);
toOptimize = new FunctionCallExpression(TraversalStepType.END, toOptimize, "toList");
toOptimize = new FunctionCallExpression(toOptimize, "size");
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestSimpleRangeExpression());
}
protected abstract String getExpectedGremlinForTestSimpleRangeExpression();
@Test
public void testRangeWithNonZeroOffset() throws Exception {
// g.V().or(has('__typeName','OMAS_OMRSAsset'),has('__superTypeNames','OMAS_OMRSAsset')).range(5,10).as('inst').select('inst')
GroovyExpression toOptimize = getVerticesExpression();
GroovyExpression expr0 = makeHasExpression("__typeName", "OMAS_OMRSAsset");
GroovyExpression expr1 = makeHasExpression("__superTypeNames", "OMAS_OMRSAsset");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr0, expr1));
toOptimize = getFactory().generateRangeExpression(toOptimize, 5, 10);
toOptimize = getFactory().generateAliasExpression(toOptimize, "inst");
toOptimize = getFactory().generateSelectExpression(toOptimize, Collections.singletonList(new LiteralExpression("inst")), Collections.<GroovyExpression>emptyList());
RangeFinder visitor = new RangeFinder(getFactory());
GremlinQueryOptimizer.visitCallHierarchy(toOptimize, visitor);
List<AbstractFunctionExpression> rangeExpressions = visitor.getRangeExpressions();
assertEquals(rangeExpressions.size(), 1);
int[] rangeParameters = getFactory().getRangeParameters(rangeExpressions.get(0));
assertNotNull(rangeParameters);
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
// The range optimization is not supported with a non-zero start index, so the optimizer should not add range expressions
// to the expanded or's.
assertEquals(optimized.toString(), getExpectedGremlinForTestRangeWithNonZeroOffset());
}
protected abstract String getExpectedGremlinForTestRangeWithNonZeroOffset();
@Test
public void testRangeWithOrderBy() throws Exception {
// The range optimization is not supported with order, so the optimizer should not add range expressions
// to the expanded or's.
GroovyExpression toOptimize = getVerticesExpression();
GroovyExpression expr0 = makeHasExpression("__typeName", "OMAS_OMRSAsset");
GroovyExpression expr1 = makeHasExpression("__superTypeNames", "OMAS_OMRSAsset");
toOptimize = getFactory().generateLogicalExpression(toOptimize, "or", Arrays.asList(expr0, expr1));
toOptimize = getFactory().generateRangeExpression(toOptimize, 5, 10);
toOptimize = getFactory().generateAliasExpression(toOptimize, "inst");
//toOptimize = getFactory().generateSelectExpression(toOptimize, Collections.singletonList(new LiteralExpression("inst")), Collections.<GroovyExpression>emptyList());
GroovyExpression orderFielda = makeFieldExpression(getFactory().getCurrentTraverserObject(getFactory().getClosureArgumentValue()), "name");
GroovyExpression orderFieldb = makeFieldExpression(getFactory().getCurrentTraverserObject(getFactory().getClosureArgumentValue()), "name");
toOptimize = getFactory().generateOrderByExpression(toOptimize,Arrays.asList(orderFielda, orderFieldb), true);
RangeFinder visitor = new RangeFinder(getFactory());
GremlinQueryOptimizer.visitCallHierarchy(toOptimize, visitor);
List<AbstractFunctionExpression> rangeExpressions = visitor.getRangeExpressions();
assertEquals(rangeExpressions.size(), 1);
int[] rangeParameters = getFactory().getRangeParameters(rangeExpressions.get(0));
assertNotNull(rangeParameters);
GroovyExpression optimized = GremlinQueryOptimizer.getInstance().optimize(toOptimize);
assertEquals(optimized.toString(), getExpectedGremlinForTestRangeWithOrderBy());
}
protected abstract String getExpectedGremlinForTestRangeWithOrderBy();
@Override
public AtlasGraph get() throws RepositoryException {
AtlasGraph graph = mock(AtlasGraph.class);
when(graph.getSupportedGremlinVersion()).thenReturn(GremlinVersion.THREE);
when(graph.isPropertyValueConversionNeeded(any(IDataType.class))).thenReturn(false);
return graph;
}
}