http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/62a05c97/repository/src/test/java/org/apache/atlas/repository/graph/AbstractGremlinQueryOptimizerTest.java ---------------------------------------------------------------------- diff --git a/repository/src/test/java/org/apache/atlas/repository/graph/AbstractGremlinQueryOptimizerTest.java b/repository/src/test/java/org/apache/atlas/repository/graph/AbstractGremlinQueryOptimizerTest.java new file mode 100644 index 0000000..2dda853 --- /dev/null +++ b/repository/src/test/java/org/apache/atlas/repository/graph/AbstractGremlinQueryOptimizerTest.java @@ -0,0 +1,705 @@ +/** + * 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 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; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +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; + + +public abstract class AbstractGremlinQueryOptimizerTest implements IAtlasGraphProvider { + + protected abstract GremlinExpressionFactory getFactory(); + + private MetadataRepository repo = new GraphBackedMetadataRepository(this, new HardDeleteHandler(TypeSystem.getInstance())); + 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); + } + + 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; + } +}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/62a05c97/repository/src/test/java/org/apache/atlas/repository/graph/Gremlin2QueryOptimizerTest.java ---------------------------------------------------------------------- diff --git a/repository/src/test/java/org/apache/atlas/repository/graph/Gremlin2QueryOptimizerTest.java b/repository/src/test/java/org/apache/atlas/repository/graph/Gremlin2QueryOptimizerTest.java new file mode 100644 index 0000000..b857255 --- /dev/null +++ b/repository/src/test/java/org/apache/atlas/repository/graph/Gremlin2QueryOptimizerTest.java @@ -0,0 +1,363 @@ +/** + * 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.gremlin.Gremlin2ExpressionFactory; +import org.apache.atlas.gremlin.GremlinExpressionFactory; +import org.testng.annotations.Test; + + +@Test +public class Gremlin2QueryOptimizerTest extends AbstractGremlinQueryOptimizerTest { + + + private static final GremlinExpressionFactory FACTORY = new Gremlin2ExpressionFactory(); + + @Override + protected GremlinExpressionFactory getFactory() { + return FACTORY; + } + + @Override + protected String getExpectedGremlinForTestPullHasExpressionsOutOfHas() { + return "g.V().has('prop1',T.'eq','Fred').has('prop2',T.'eq','George').and(out('out1'),out('out2'))"; + } + + @Override + protected String getExpectedGremlinForTestOrGrouping() { + return "def r=(([]) as Set);" + + "g.V().has('prop1',T.'eq','Fred').fill(r);" + + "g.V().has('prop2',T.'eq','George').fill(r);" + + "g.V().or(out('out1'),out('out2')).fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestAndOfOrs() { + return "def r=(([]) as Set);" + + "g.V().has('p1',T.'eq','e1').has('p3',T.'eq','e3').fill(r);" + + "g.V().has('p1',T.'eq','e1').has('p4',T.'eq','e4').fill(r);" + + "g.V().has('p2',T.'eq','e2').has('p3',T.'eq','e3').fill(r);" + + "g.V().has('p2',T.'eq','e2').has('p4',T.'eq','e4').fill(r);" + + "r"; + } + + + @Override + protected String getExpectedGremlinForTestAndWithMultiCallArguments() { + return "g.V().has('p1',T.'eq','e1').has('p2',T.'eq','e2').has('p3',T.'eq','e3').has('p4',T.'eq','e4')"; + } + + @Override + protected String getExpectedGremlinForTestOrOfAnds() { + + return "def r=(([]) as Set);" + + "g.V().has('p1',T.'eq','e1').has('p2',T.'eq','e2').fill(r);" + + "g.V().has('p3',T.'eq','e3').has('p4',T.'eq','e4').fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestHasNotMovedToResult() { + return "def r=(([]) as Set);" + + "def f1={GremlinPipeline x->x.has('p3',T.'eq','e3').as('_src').select(['_src']).fill(r)};" + + "f1(g.V().has('p1',T.'eq','e1'));" + + "f1(g.V().has('p2',T.'eq','e2'));" + + "r._().transform({((Row)it).getColumn('_src')}).as('_src').select(['src1'],{it})"; + } + + @Override + protected String getExpectedGremlinForOptimizeLoopExpression() { + return "def r=(([]) as Set);" + + "g.V().has('__typeName','DataSet').has('name',T.'eq','Fred').fill(r);" + + "g.V().has('__superTypeNames','DataSet').has('name',T.'eq','Fred').fill(r);" + + "r._().as('label').in('inputTables').out('outputTables').loop('label',{((it.'path'.contains(it.'object'))?(false):(true))},{it.'object'.'__typeName' == 'string' || ((it.'object'.'__superTypeNames')?(it.'object'.'__superTypeNames'.contains('string')):(false))}).enablePath().toList()"; + } + + + @Override + protected String getExpectedGremlinForTestLongStringEndingWithOr() { + return "def r=(([]) as Set);" + + "def f1={g.V().has('name',T.'eq','Fred').has('age',T.'eq','13').out('livesIn').has('state',T.'eq','Massachusetts')};" + + "def f2={GremlinPipeline x->x.has('p5',T.'eq','e5').has('p6',T.'eq','e6')};" + + "f2(f1().has('p1',T.'eq','e1').has('p3',T.'eq','e3')).has('p7',T.'eq','e7').fill(r);" + + "f2(f1().has('p1',T.'eq','e1').has('p3',T.'eq','e3')).has('p8',T.'eq','e8').fill(r);" + + "f2(f1().has('p1',T.'eq','e1').has('p4',T.'eq','e4')).has('p7',T.'eq','e7').fill(r);" + + "f2(f1().has('p1',T.'eq','e1').has('p4',T.'eq','e4')).has('p8',T.'eq','e8').fill(r);" + + "f2(f1().has('p2',T.'eq','e2').has('p3',T.'eq','e3')).has('p7',T.'eq','e7').fill(r);" + + "f2(f1().has('p2',T.'eq','e2').has('p3',T.'eq','e3')).has('p8',T.'eq','e8').fill(r);" + + "f2(f1().has('p2',T.'eq','e2').has('p4',T.'eq','e4')).has('p7',T.'eq','e7').fill(r);" + + "f2(f1().has('p2',T.'eq','e2').has('p4',T.'eq','e4')).has('p8',T.'eq','e8').fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestLongStringNotEndingWithOr() { + return "def r=(([]) as Set);" + + "def f1={g.V().has('name',T.'eq','Fred').has('age',T.'eq','13').out('livesIn').has('state',T.'eq','Massachusetts')};" + + "def f2={GremlinPipeline x->x.has('p5',T.'eq','e5').has('p6',T.'eq','e6')};" + + "def f3={GremlinPipeline x->x.has('p9',T.'eq','e9').fill(r)};" + + "f3(f2(f1().has('p1',T.'eq','e1').has('p3',T.'eq','e3')).has('p7',T.'eq','e7'));" + + "f3(f2(f1().has('p1',T.'eq','e1').has('p3',T.'eq','e3')).has('p8',T.'eq','e8'));" + + "f3(f2(f1().has('p1',T.'eq','e1').has('p4',T.'eq','e4')).has('p7',T.'eq','e7'));" + + "f3(f2(f1().has('p1',T.'eq','e1').has('p4',T.'eq','e4')).has('p8',T.'eq','e8'));" + + "f3(f2(f1().has('p2',T.'eq','e2').has('p3',T.'eq','e3')).has('p7',T.'eq','e7'));" + + "f3(f2(f1().has('p2',T.'eq','e2').has('p3',T.'eq','e3')).has('p8',T.'eq','e8'));" + + "f3(f2(f1().has('p2',T.'eq','e2').has('p4',T.'eq','e4')).has('p7',T.'eq','e7'));" + + "f3(f2(f1().has('p2',T.'eq','e2').has('p4',T.'eq','e4')).has('p8',T.'eq','e8'));" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestToListConversion() { + return "def r=(([]) as Set);" + + "g.V().has('prop1',T.'eq','Fred').fill(r);" + + "g.V().has('prop2',T.'eq','George').fill(r);" + + "r._().toList()"; + } + + @Override + protected String getExpectedGremlinForTestToListWithExtraStuff() { + return "def r=(([]) as Set);" + + "g.V().has('prop1',T.'eq','Fred').fill(r);" + + "g.V().has('prop2',T.'eq','George').fill(r);" + + "r._().toList().size()"; + } + + + @Override + protected String getExpectedGremlinForTestAddClosureWithExitExpressionDifferentFromExpr() { + return "def r=(([]) as Set);" + + "g.V().has('prop1',T.'eq','Fred').out('knows').out('livesIn').fill(r);" + + "g.V().has('prop2',T.'eq','George').out('knows').out('livesIn').fill(r);" + + "r._().toList().size()"; + } + + @Override + protected String getExpectedGremlinForTestAddClosureNoExitExpression() { + return "def r=(([]) as Set);" + + "g.V().has('prop1',T.'eq','Fred').out('knows').out('livesIn').fill(r);" + + "g.V().has('prop2',T.'eq','George').out('knows').out('livesIn').fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestAddClosureWithExitExpressionEqualToExpr() { + return "def r=(([]) as Set);" + + "g.V().has('prop1',T.'eq','Fred').out('knows').out('livesIn').fill(r);" + + "g.V().has('prop2',T.'eq','George').out('knows').out('livesIn').fill(r);" + + "r._().toList()"; + } + + @Override + protected String getExpectedGremlinForTestClosureNotCreatedWhenNoOrs() { + return "g.V().has('prop1',T.'eq','Fred').has('prop2',T.'eq','George').out('knows').out('livesIn')"; + } + + @Override + protected String getExpectedGremlinForTestOrFollowedByAnd() { + return "def r=(([]) as Set);" + + "def f1={GremlinPipeline x->x.has('age',T.'eq','13').has('age',T.'eq','14').fill(r)};" + + "f1(g.V().has('name',T.'eq','Fred'));" + + "f1(g.V().has('name',T.'eq','George'));" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestOrFollowedByOr() { + return "def r=(([]) as Set);" + + "g.V().has('name',T.'eq','Fred').has('age',T.'eq','13').fill(r);" + + "g.V().has('name',T.'eq','Fred').has('age',T.'eq','14').fill(r);" + + "g.V().has('name',T.'eq','George').has('age',T.'eq','13').fill(r);" + + "g.V().has('name',T.'eq','George').has('age',T.'eq','14').fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestMassiveOrExpansion() { + return "def r=(([]) as Set);" + + "def f1={g.V().has('h1',T.'eq','h2').has('h3',T.'eq','h4')};" + + "def f2={GremlinPipeline x->x.has('ha0',T.'eq','hb0').has('hc0',T.'eq','hd0')};" + + "def f3={GremlinPipeline x->x.has('ha1',T.'eq','hb1').has('hc1',T.'eq','hd1')};" + + "def f4={GremlinPipeline x->x.has('ha2',T.'eq','hb2').has('hc2',T.'eq','hd2')};" + + "def f5={GremlinPipeline x->x.has('ha3',T.'eq','hb3').has('hc3',T.'eq','hd3')};" + + "def f6={GremlinPipeline x->x.has('ha4',T.'eq','hb4').has('hc4',T.'eq','hd4').has('h5',T.'eq','h6').has('h7',T.'eq','h8').fill(r)};" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p11',T.'eq','e11')).has('p12',T.'eq','e12')).has('p13',T.'eq','e13')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p11',T.'eq','e11')).has('p12',T.'eq','e12')).has('p13',T.'eq','e13')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p11',T.'eq','e11')).has('p12',T.'eq','e12')).has('p23',T.'eq','e23')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p11',T.'eq','e11')).has('p12',T.'eq','e12')).has('p23',T.'eq','e23')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p11',T.'eq','e11')).has('p22',T.'eq','e22')).has('p13',T.'eq','e13')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p11',T.'eq','e11')).has('p22',T.'eq','e22')).has('p13',T.'eq','e13')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p11',T.'eq','e11')).has('p22',T.'eq','e22')).has('p23',T.'eq','e23')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p11',T.'eq','e11')).has('p22',T.'eq','e22')).has('p23',T.'eq','e23')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p21',T.'eq','e21')).has('p12',T.'eq','e12')).has('p13',T.'eq','e13')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p21',T.'eq','e21')).has('p12',T.'eq','e12')).has('p13',T.'eq','e13')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p21',T.'eq','e21')).has('p12',T.'eq','e12')).has('p23',T.'eq','e23')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p21',T.'eq','e21')).has('p12',T.'eq','e12')).has('p23',T.'eq','e23')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p21',T.'eq','e21')).has('p22',T.'eq','e22')).has('p13',T.'eq','e13')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p21',T.'eq','e21')).has('p22',T.'eq','e22')).has('p13',T.'eq','e13')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p21',T.'eq','e21')).has('p22',T.'eq','e22')).has('p23',T.'eq','e23')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p10',T.'eq','e10')).has('p21',T.'eq','e21')).has('p22',T.'eq','e22')).has('p23',T.'eq','e23')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p11',T.'eq','e11')).has('p12',T.'eq','e12')).has('p13',T.'eq','e13')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p11',T.'eq','e11')).has('p12',T.'eq','e12')).has('p13',T.'eq','e13')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p11',T.'eq','e11')).has('p12',T.'eq','e12')).has('p23',T.'eq','e23')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p11',T.'eq','e11')).has('p12',T.'eq','e12')).has('p23',T.'eq','e23')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p11',T.'eq','e11')).has('p22',T.'eq','e22')).has('p13',T.'eq','e13')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p11',T.'eq','e11')).has('p22',T.'eq','e22')).has('p13',T.'eq','e13')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p11',T.'eq','e11')).has('p22',T.'eq','e22')).has('p23',T.'eq','e23')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p11',T.'eq','e11')).has('p22',T.'eq','e22')).has('p23',T.'eq','e23')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p21',T.'eq','e21')).has('p12',T.'eq','e12')).has('p13',T.'eq','e13')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p21',T.'eq','e21')).has('p12',T.'eq','e12')).has('p13',T.'eq','e13')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p21',T.'eq','e21')).has('p12',T.'eq','e12')).has('p23',T.'eq','e23')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p21',T.'eq','e21')).has('p12',T.'eq','e12')).has('p23',T.'eq','e23')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p21',T.'eq','e21')).has('p22',T.'eq','e22')).has('p13',T.'eq','e13')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p21',T.'eq','e21')).has('p22',T.'eq','e22')).has('p13',T.'eq','e13')).has('p24',T.'eq','e24'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p21',T.'eq','e21')).has('p22',T.'eq','e22')).has('p23',T.'eq','e23')).has('p14',T.'eq','e14'));" + + "f6(f5(f4(f3(f2(f1().has('p20',T.'eq','e20')).has('p21',T.'eq','e21')).has('p22',T.'eq','e22')).has('p23',T.'eq','e23')).has('p24',T.'eq','e24'));" + + "r"; + + } + + @Override + protected String getExpectedGremlinForTestAndFollowedByAnd() { + return "g.V().has('name',T.'eq','Fred').has('name',T.'eq','George').has('age',T.'eq','13').has('age',T.'eq','14')"; + + } + + @Override + protected String getExpectedGremlinForTestAndFollowedByOr() { + return "def r=(([]) as Set);" + + "def f1={g.V().has('name',T.'eq','Fred').has('name',T.'eq','George')};f1().has('age',T.'eq','13').fill(r);" + + "f1().has('age',T.'eq','14').fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestInitialAlias() { + return "def r=(([]) as Set);" + + "g.V().as('x').has('name',T.'eq','Fred').fill(r);" + + "g.V().as('x').has('name',T.'eq','George').fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestFinalAlias() { + return "def r=(([]) as Set);" + + "g.V().has('name',T.'eq','Fred').as('x').fill(r);" + + "g.V().has('name',T.'eq','George').as('x').fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestAliasInMiddle() { + return "def r=(([]) as Set);" + + "g.V().has('name',T.'eq','Fred').as('x').has('age',T.'eq','13').fill(r);" + + "g.V().has('name',T.'eq','Fred').as('x').has('age',T.'eq','14').fill(r);" + + "g.V().has('name',T.'eq','George').as('x').has('age',T.'eq','13').fill(r);" + + "g.V().has('name',T.'eq','George').as('x').has('age',T.'eq','14').fill(r);" + + "r"; + } + + @Override + protected String getExpectedGreminForTestMultipleAliases() { + return "def r=(([]) as Set);" + + "def f1={GremlinPipeline x->x.as('y').fill(r)};" + + "f1(g.V().has('name',T.'eq','Fred').as('x').has('age',T.'eq','13'));" + + "f1(g.V().has('name',T.'eq','Fred').as('x').has('age',T.'eq','14'));" + + "f1(g.V().has('name',T.'eq','George').as('x').has('age',T.'eq','13'));" + + "f1(g.V().has('name',T.'eq','George').as('x').has('age',T.'eq','14'));" + + "r"; + } + + + @Override + protected String getExpectedGremlinForTestAliasInOrExpr() { + return "def r=(([]) as Set);" + + "g.V().has('name',T.'eq','Fred').fill(r);" + + "g.V().or(has('name',T.'eq','George').as('george')).fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestAliasInAndExpr() { + return "g.V().has('name',T.'eq','Fred').and(has('name',T.'eq','George').as('george'))"; + } + @Override + protected String getExpectedGremlinForTestFlatMapExprInAnd() { + return "g.V().has('name',T.'eq','Fred').and(out('knows').has('name',T.'eq','George'))"; + } + + @Override + protected String getExpectedGremlinForTestFlatMapExprInOr() { + return "def r=(([]) as Set);" + + "g.V().has('name',T.'eq','Fred').fill(r);" + + "g.V().or(out('knows').has('name',T.'eq','George')).fill(r);" + + "r"; + } + + + @Override + protected String getExpectedGremlinForTestFieldExpressionPushedToResultExpression() { + return "def r=(([]) as Set);" + + "g.V().has('name',T.'eq','Fred').fill(r);" + + "g.V().or(out('knows').has('name',T.'eq','George')).fill(r);" + + "r._().'name'"; + } + + @Override + protected String getExpectedGremlinFortestOrWithNoChildren() { + return "def r=(([]) as Set);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestFinalAliasNeeded() { + return "def r=(([]) as Set);" + + "def f1={g.V().has('name',T.'eq','Fred').as('person').out('livesIn')};" + + "def f2={GremlinPipeline x->x.as('city').out('state').has('name',T.'eq','Massachusetts').as('__res').select(['person', 'city', '__res']).fill(r)};" + + "f2(f1().has('name',T.'eq','Chicago'));" + + "f2(f1().has('name',T.'eq','Boston'));" + + "r._().as('__tmp').transform({((Row)it).getColumn('person')}).as('person').back('__tmp').transform({((Row)it).getColumn('city')}).as('city').back('__tmp').transform({((Row)it).getColumn('__res')}).as('__res').path().toList().collect({it.tail()})"; + } + + @Override + protected String getExpectedGremlinForTestSimpleRangeExpression() { + return "def r=(([]) as Set);" + + "def f1={GremlinPipeline x->x.has('age',T.'eq','34').out('eats').has('size',T.'eq','small').has('color',T.'eq','blue') [0..<10].fill(r)};" + + "f1(g.V().has('name',T.'eq','Fred'));" + + "f1(g.V().has('name',T.'eq','George'));" + + "r._() [0..<10].toList().size()"; + } + + @Override + protected String getExpectedGremlinForTestRangeWithNonZeroOffset() { + return "def r=(([]) as Set);" + + "g.V().has('__typeName',T.'eq','OMAS_OMRSAsset').fill(r);" + + "g.V().has('__superTypeNames',T.'eq','OMAS_OMRSAsset').fill(r);" + + "r._() [5..<10].as('inst').select(['inst'])"; + } + + @Override + protected String getExpectedGremlinForTestRangeWithOrderBy() { + return "def r=(([]) as Set);" + + "g.V().has('__typeName',T.'eq','OMAS_OMRSAsset').fill(r);" + + "g.V().has('__superTypeNames',T.'eq','OMAS_OMRSAsset').fill(r);" + + "r._() [5..<10].as('inst').order({((it.'name' != null)?(it.'name'.toLowerCase()):(it.'name')) <=> ((it.'name' != null)?(it.'name'.toLowerCase()):(it.'name'))})"; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/62a05c97/repository/src/test/java/org/apache/atlas/repository/graph/Gremlin3QueryOptimizerTest.java ---------------------------------------------------------------------- diff --git a/repository/src/test/java/org/apache/atlas/repository/graph/Gremlin3QueryOptimizerTest.java b/repository/src/test/java/org/apache/atlas/repository/graph/Gremlin3QueryOptimizerTest.java new file mode 100644 index 0000000..4045a4f --- /dev/null +++ b/repository/src/test/java/org/apache/atlas/repository/graph/Gremlin3QueryOptimizerTest.java @@ -0,0 +1,364 @@ +/** + * 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.gremlin.Gremlin3ExpressionFactory; +import org.apache.atlas.gremlin.GremlinExpressionFactory; +import org.testng.annotations.Test; + + +@Test +public class Gremlin3QueryOptimizerTest extends AbstractGremlinQueryOptimizerTest { + + public static final GremlinExpressionFactory FACTORY = new Gremlin3ExpressionFactory(); + + @Override + protected GremlinExpressionFactory getFactory() { + return FACTORY; + } + + @Override + protected String getExpectedGremlinForTestPullHasExpressionsOutOfHas() { + return "g.V().has('prop1',eq('Fred')).has('prop2',eq('George')).and(out('out1'),out('out2'))"; + } + + @Override + protected String getExpectedGremlinForTestOrGrouping() { + return "def r=(([]) as Set);" + + "g.V().has('prop1',eq('Fred')).fill(r);" + + "g.V().has('prop2',eq('George')).fill(r);" + + "g.V().or(out('out1'),out('out2')).fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestAndOfOrs() { + + return "def r=(([]) as Set);" + + "g.V().has('p1',eq('e1')).has('p3',eq('e3')).fill(r);" + + "g.V().has('p1',eq('e1')).has('p4',eq('e4')).fill(r);" + + "g.V().has('p2',eq('e2')).has('p3',eq('e3')).fill(r);" + + "g.V().has('p2',eq('e2')).has('p4',eq('e4')).fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestAndWithMultiCallArguments() { + + return "g.V().has('p1',eq('e1')).has('p2',eq('e2')).has('p3',eq('e3')).has('p4',eq('e4'))"; + } + + @Override + protected String getExpectedGremlinForTestOrOfAnds() { + return "def r=(([]) as Set);" + + "g.V().has('p1',eq('e1')).has('p2',eq('e2')).fill(r);" + + "g.V().has('p3',eq('e3')).has('p4',eq('e4')).fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestHasNotMovedToResult() { + return "def r=(([]) as Set);" + + "def f1={GraphTraversal x->x.has('p3',eq('e3')).as('_src').select('_src').fill(r)};" + + "f1(g.V().has('p1',eq('e1')));f1(g.V().has('p2',eq('e2')));" + + "g.V('').inject(((r) as Vertex[])).as('_src').select('src1').by((({it}) as Function))"; + } + + + @Override + protected String getExpectedGremlinForTestLongStringEndingWithOr() { + return "def r=(([]) as Set);" + + "def f1={g.V().has('name',eq('Fred')).has('age',eq('13')).out('livesIn').has('state',eq('Massachusetts'))};" + + "def f2={GraphTraversal x->x.has('p5',eq('e5')).has('p6',eq('e6'))};" + + "f2(f1().has('p1',eq('e1')).has('p3',eq('e3'))).has('p7',eq('e7')).fill(r);" + + "f2(f1().has('p1',eq('e1')).has('p3',eq('e3'))).has('p8',eq('e8')).fill(r);" + + "f2(f1().has('p1',eq('e1')).has('p4',eq('e4'))).has('p7',eq('e7')).fill(r);" + + "f2(f1().has('p1',eq('e1')).has('p4',eq('e4'))).has('p8',eq('e8')).fill(r);" + + "f2(f1().has('p2',eq('e2')).has('p3',eq('e3'))).has('p7',eq('e7')).fill(r);" + + "f2(f1().has('p2',eq('e2')).has('p3',eq('e3'))).has('p8',eq('e8')).fill(r);" + + "f2(f1().has('p2',eq('e2')).has('p4',eq('e4'))).has('p7',eq('e7')).fill(r);" + + "f2(f1().has('p2',eq('e2')).has('p4',eq('e4'))).has('p8',eq('e8')).fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestLongStringNotEndingWithOr() { + return "def r=(([]) as Set);" + + "def f1={g.V().has('name',eq('Fred')).has('age',eq('13')).out('livesIn').has('state',eq('Massachusetts'))};" + + "def f2={GraphTraversal x->x.has('p5',eq('e5')).has('p6',eq('e6'))};" + + "def f3={GraphTraversal x->x.has('p9',eq('e9')).fill(r)};" + + "f3(f2(f1().has('p1',eq('e1')).has('p3',eq('e3'))).has('p7',eq('e7')));" + + "f3(f2(f1().has('p1',eq('e1')).has('p3',eq('e3'))).has('p8',eq('e8')));" + + "f3(f2(f1().has('p1',eq('e1')).has('p4',eq('e4'))).has('p7',eq('e7')));" + + "f3(f2(f1().has('p1',eq('e1')).has('p4',eq('e4'))).has('p8',eq('e8')));" + + "f3(f2(f1().has('p2',eq('e2')).has('p3',eq('e3'))).has('p7',eq('e7')));" + + "f3(f2(f1().has('p2',eq('e2')).has('p3',eq('e3'))).has('p8',eq('e8')));" + + "f3(f2(f1().has('p2',eq('e2')).has('p4',eq('e4'))).has('p7',eq('e7')));" + + "f3(f2(f1().has('p2',eq('e2')).has('p4',eq('e4'))).has('p8',eq('e8')));" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestToListConversion() { + + return "def r=(([]) as Set);" + + "g.V().has('prop1',eq('Fred')).fill(r);" + + "g.V().has('prop2',eq('George')).fill(r);" + + "g.V('').inject(((r) as Vertex[])).toList()"; + } + + + @Override + protected String getExpectedGremlinForTestToListWithExtraStuff() { + return "def r=(([]) as Set);" + + "g.V().has('prop1',eq('Fred')).fill(r);" + + "g.V().has('prop2',eq('George')).fill(r);" + + "g.V('').inject(((r) as Vertex[])).toList().size()"; + } + + + @Override + protected String getExpectedGremlinForTestAddClosureWithExitExpressionDifferentFromExpr() { + return "def r=(([]) as Set);" + + "g.V().has('prop1',eq('Fred')).out('knows').out('livesIn').fill(r);" + + "g.V().has('prop2',eq('George')).out('knows').out('livesIn').fill(r);" + + "g.V('').inject(((r) as Vertex[])).toList().size()"; + } + + @Override + protected String getExpectedGremlinForTestAddClosureNoExitExpression() { + return "def r=(([]) as Set);" + + "g.V().has('prop1',eq('Fred')).out('knows').out('livesIn').fill(r);" + + "g.V().has('prop2',eq('George')).out('knows').out('livesIn').fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestAddClosureWithExitExpressionEqualToExpr() { + return "def r=(([]) as Set);" + + "g.V().has('prop1',eq('Fred')).out('knows').out('livesIn').fill(r);" + + "g.V().has('prop2',eq('George')).out('knows').out('livesIn').fill(r);" + + "g.V('').inject(((r) as Vertex[])).toList()"; + } + + @Override + protected String getExpectedGremlinForTestClosureNotCreatedWhenNoOrs() { + return "g.V().has('prop1',eq('Fred')).has('prop2',eq('George')).out('knows').out('livesIn')"; + } + + @Override + protected String getExpectedGremlinForTestOrFollowedByAnd() { + return "def r=(([]) as Set);" + + "def f1={GraphTraversal x->x.has('age',eq('13')).has('age',eq('14')).fill(r)};" + + "f1(g.V().has('name',eq('Fred')));" + + "f1(g.V().has('name',eq('George')));" + + "r"; + } + + + @Override + protected String getExpectedGremlinForTestOrFollowedByOr() { + return "def r=(([]) as Set);" + + "g.V().has('name',eq('Fred')).has('age',eq('13')).fill(r);" + + "g.V().has('name',eq('Fred')).has('age',eq('14')).fill(r);" + + "g.V().has('name',eq('George')).has('age',eq('13')).fill(r);" + + "g.V().has('name',eq('George')).has('age',eq('14')).fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestMassiveOrExpansion() { + return "def r=(([]) as Set);" + + "def f1={g.V().has('h1',eq('h2')).has('h3',eq('h4'))};" + + "def f2={GraphTraversal x->x.has('ha0',eq('hb0')).has('hc0',eq('hd0'))};" + + "def f3={GraphTraversal x->x.has('ha1',eq('hb1')).has('hc1',eq('hd1'))};" + + "def f4={GraphTraversal x->x.has('ha2',eq('hb2')).has('hc2',eq('hd2'))};" + + "def f5={GraphTraversal x->x.has('ha3',eq('hb3')).has('hc3',eq('hd3'))};" + + "def f6={GraphTraversal x->x.has('ha4',eq('hb4')).has('hc4',eq('hd4')).has('h5',eq('h6')).has('h7',eq('h8')).fill(r)};" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p11',eq('e11'))).has('p12',eq('e12'))).has('p13',eq('e13'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p11',eq('e11'))).has('p12',eq('e12'))).has('p13',eq('e13'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p11',eq('e11'))).has('p12',eq('e12'))).has('p23',eq('e23'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p11',eq('e11'))).has('p12',eq('e12'))).has('p23',eq('e23'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p11',eq('e11'))).has('p22',eq('e22'))).has('p13',eq('e13'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p11',eq('e11'))).has('p22',eq('e22'))).has('p13',eq('e13'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p11',eq('e11'))).has('p22',eq('e22'))).has('p23',eq('e23'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p11',eq('e11'))).has('p22',eq('e22'))).has('p23',eq('e23'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p21',eq('e21'))).has('p12',eq('e12'))).has('p13',eq('e13'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p21',eq('e21'))).has('p12',eq('e12'))).has('p13',eq('e13'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p21',eq('e21'))).has('p12',eq('e12'))).has('p23',eq('e23'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p21',eq('e21'))).has('p12',eq('e12'))).has('p23',eq('e23'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p21',eq('e21'))).has('p22',eq('e22'))).has('p13',eq('e13'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p21',eq('e21'))).has('p22',eq('e22'))).has('p13',eq('e13'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p21',eq('e21'))).has('p22',eq('e22'))).has('p23',eq('e23'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p10',eq('e10'))).has('p21',eq('e21'))).has('p22',eq('e22'))).has('p23',eq('e23'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p11',eq('e11'))).has('p12',eq('e12'))).has('p13',eq('e13'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p11',eq('e11'))).has('p12',eq('e12'))).has('p13',eq('e13'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p11',eq('e11'))).has('p12',eq('e12'))).has('p23',eq('e23'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p11',eq('e11'))).has('p12',eq('e12'))).has('p23',eq('e23'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p11',eq('e11'))).has('p22',eq('e22'))).has('p13',eq('e13'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p11',eq('e11'))).has('p22',eq('e22'))).has('p13',eq('e13'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p11',eq('e11'))).has('p22',eq('e22'))).has('p23',eq('e23'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p11',eq('e11'))).has('p22',eq('e22'))).has('p23',eq('e23'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p21',eq('e21'))).has('p12',eq('e12'))).has('p13',eq('e13'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p21',eq('e21'))).has('p12',eq('e12'))).has('p13',eq('e13'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p21',eq('e21'))).has('p12',eq('e12'))).has('p23',eq('e23'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p21',eq('e21'))).has('p12',eq('e12'))).has('p23',eq('e23'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p21',eq('e21'))).has('p22',eq('e22'))).has('p13',eq('e13'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p21',eq('e21'))).has('p22',eq('e22'))).has('p13',eq('e13'))).has('p24',eq('e24')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p21',eq('e21'))).has('p22',eq('e22'))).has('p23',eq('e23'))).has('p14',eq('e14')));" + + "f6(f5(f4(f3(f2(f1().has('p20',eq('e20'))).has('p21',eq('e21'))).has('p22',eq('e22'))).has('p23',eq('e23'))).has('p24',eq('e24')));" + + "r"; + + } + + @Override + protected String getExpectedGremlinForTestAndFollowedByAnd() { + return "g.V().has('name',eq('Fred')).has('name',eq('George')).has('age',eq('13')).has('age',eq('14'))"; + } + + + @Override + protected String getExpectedGremlinForTestAndFollowedByOr() { + return "def r=(([]) as Set);" + + "def f1={g.V().has('name',eq('Fred')).has('name',eq('George'))};" + + "f1().has('age',eq('13')).fill(r);" + + "f1().has('age',eq('14')).fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestInitialAlias() { + return "def r=(([]) as Set);" + + "g.V().as('x').has('name',eq('Fred')).fill(r);" + + "g.V().as('x').has('name',eq('George')).fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestFinalAlias() { + return "def r=(([]) as Set);" + + "g.V().has('name',eq('Fred')).as('x').fill(r);" + + "g.V().has('name',eq('George')).as('x').fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestAliasInMiddle() { + return "def r=(([]) as Set);" + + "g.V().has('name',eq('Fred')).as('x').has('age',eq('13')).fill(r);" + + "g.V().has('name',eq('Fred')).as('x').has('age',eq('14')).fill(r);" + + "g.V().has('name',eq('George')).as('x').has('age',eq('13')).fill(r);" + + "g.V().has('name',eq('George')).as('x').has('age',eq('14')).fill(r);" + + "r"; + } + + @Override + protected String getExpectedGreminForTestMultipleAliases() { + return "def r=(([]) as Set);" + + "def f1={GraphTraversal x->x.as('y').fill(r)};" + + "f1(g.V().has('name',eq('Fred')).as('x').has('age',eq('13')));" + + "f1(g.V().has('name',eq('Fred')).as('x').has('age',eq('14')));" + + "f1(g.V().has('name',eq('George')).as('x').has('age',eq('13')));" + + "f1(g.V().has('name',eq('George')).as('x').has('age',eq('14')));" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestAliasInOrExpr() { + return "def r=(([]) as Set);" + + "g.V().has('name',eq('Fred')).fill(r);" + + "g.V().or(has('name',eq('George')).as('george')).fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestAliasInAndExpr() { + return "g.V().has('name',eq('Fred')).and(has('name',eq('George')).as('george'))"; + } + + @Override + protected String getExpectedGremlinForTestFlatMapExprInAnd() { + return "g.V().has('name',eq('Fred')).and(out('knows').has('name',eq('George')))"; + } + + @Override + protected String getExpectedGremlinForTestFlatMapExprInOr() { + return "def r=(([]) as Set);" + + "g.V().has('name',eq('Fred')).fill(r);" + + "g.V().or(out('knows').has('name',eq('George'))).fill(r);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestFieldExpressionPushedToResultExpression() { + + return "def r=(([]) as Set);" + + "g.V().has('name',eq('Fred')).fill(r);" + + "g.V().or(out('knows').has('name',eq('George'))).fill(r);" + + "g.V('').inject(((r) as Vertex[])).values('name')"; + } + + @Override + protected String getExpectedGremlinFortestOrWithNoChildren() { + return "def r=(([]) as Set);" + + "r"; + } + + @Override + protected String getExpectedGremlinForTestFinalAliasNeeded() { + return "def r=(([]) as Set);" + + "def f1={g.V().has('name',eq('Fred')).as('person').out('livesIn')};" + + "def f2={GraphTraversal x->x.as('city').out('state').has('name',eq('Massachusetts')).as('__res').select('person','city','__res').fill(r)};" + + "f2(f1().has('name',eq('Chicago')));f2(f1().has('name',eq('Boston')));" + + "__(((r) as Map[])).as('__tmp').map({((Map)it.get()).get('person')}).as('person').select('__tmp').map({((Map)it.get()).get('city')}).as('city').select('__tmp').map({((Map)it.get()).get('__res')}).as('__res').path().toList().collect({it.tail()})"; + } + + @Override + protected String getExpectedGremlinForTestSimpleRangeExpression() { + return "def r=(([]) as Set);" + + "def f1={GraphTraversal x->x.has('age',eq('34')).out('eats').has('size',eq('small')).has('color',eq('blue')).range(0,10).fill(r)};" + + "f1(g.V().has('name',eq('Fred')));" + + "f1(g.V().has('name',eq('George')));" + + "g.V('').inject(((r) as Vertex[])).range(0,10).toList().size()"; + } + + @Override + protected String getExpectedGremlinForOptimizeLoopExpression() { + return "def r=(([]) as Set);def f1={GraphTraversal x->x.has('name',eq('Fred')).as('label').select('label').fill(r)};" + + "f1(g.V().has('__typeName','DataSet'));" + + "f1(g.V().has('__superTypeNames','DataSet'));" + + "g.V('').inject(((r) as Vertex[])).as('label').repeat(__.in('inputTables').out('outputTables')).emit(has('__typeName',eq('string')).or().has('__superTypeNames',eq('string'))).toList()"; + } + + @Override + protected String getExpectedGremlinForTestRangeWithNonZeroOffset() { + return "def r=(([]) as Set);" + + "g.V().has('__typeName',eq('OMAS_OMRSAsset')).fill(r);" + + "g.V().has('__superTypeNames',eq('OMAS_OMRSAsset')).fill(r);" + + "g.V('').inject(((r) as Vertex[])).range(5,10).as('inst').select('inst')"; + } + + @Override + protected String getExpectedGremlinForTestRangeWithOrderBy() { + return "def r=(([]) as Set);" + + "g.V().has('__typeName',eq('OMAS_OMRSAsset')).fill(r);" + + "g.V().has('__superTypeNames',eq('OMAS_OMRSAsset')).fill(r);" + + "g.V('').inject(((r) as Vertex[])).range(5,10).as('inst').order().by((({it.get().values('name')}) as Function),{a, b->a.toString().toLowerCase() <=> b.toString().toLowerCase()})"; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/62a05c97/repository/src/test/java/org/apache/atlas/repository/graph/TestIntSequence.java ---------------------------------------------------------------------- diff --git a/repository/src/test/java/org/apache/atlas/repository/graph/TestIntSequence.java b/repository/src/test/java/org/apache/atlas/repository/graph/TestIntSequence.java new file mode 100644 index 0000000..b8eefca --- /dev/null +++ b/repository/src/test/java/org/apache/atlas/repository/graph/TestIntSequence.java @@ -0,0 +1,35 @@ +/** + * 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.query.IntSequence; + +/** + * IntSequence for use in unit tests. + * + */ +public class TestIntSequence implements IntSequence { + + public static final IntSequence INSTANCE = new TestIntSequence(); + private TestIntSequence() { + } + @Override + public int next() { + return 0; + } +} \ No newline at end of file
