Skip to content

Commit

Permalink
added ExplainStrategy
Browse files Browse the repository at this point in the history
  • Loading branch information
Valentyn Kahamlyk authored and Valentyn Kahamlyk committed Nov 29, 2023
1 parent a9ff025 commit 61c1efe
Show file tree
Hide file tree
Showing 21 changed files with 234 additions and 8 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ limitations under the License.
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/images/gremlin-victorian.png[width=185]
[[release-3-6-7]]
=== TinkerPop 3.6.7 (NOT OFFICIALLY RELEASED YET)
* Added ExplainStrategy which allows to get traversal explanation for remote traversals and GLV's.
[[release-3-6-6]]
=== TinkerPop 3.6.6 (November 20, 2023)
Expand Down
11 changes: 11 additions & 0 deletions docs/src/reference/the-traversal.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -5097,6 +5097,17 @@ new transaction immediately following the `commit()` that raises the events. The
may also not behave as "snapshots" at the time of their creation as they are "live" references to actual database
elements.
=== ExplainStrategy
`ExplainStrategy` allows to get traversal explanation for remote traversals and GLV's.
Produces string representation of `TraversalExplanation` similar to <<explain-step,`explain()`>>-step.
[gremlin-groovy]
----
g = TinkerFactory.createModern().traversal()
g.withStrategies(ExplainStrategy).V().limit(1).count().is(0)
----
[[partitionstrategy]]
=== PartitionStrategy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.HaltedTraverserStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SeedStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.ExplainStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.ReferenceElementStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.MatchAlgorithmStrategy;
Expand Down Expand Up @@ -266,6 +267,7 @@ public final class CoreImports {
CLASS_IMPORTS.add(IncidentToAdjacentStrategy.class);
CLASS_IMPORTS.add(MatchPredicateStrategy.class);
CLASS_IMPORTS.add(EarlyLimitStrategy.class);
CLASS_IMPORTS.add(ExplainStrategy.class);
CLASS_IMPORTS.add(OrderLimitStrategy.class);
CLASS_IMPORTS.add(PathProcessorStrategy.class);
CLASS_IMPORTS.add(ComputerVerificationStrategy.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SeedStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.ExplainStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.ProductiveByStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.AbstractWarningVerificationStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.EdgeLabelVerificationStrategy;
Expand Down Expand Up @@ -50,6 +51,8 @@ public TraversalStrategy visitTraversalStrategy(final GremlinParser.TraversalStr
return ReadOnlyStrategy.instance();
else if (strategyName.equals(ProductiveByStrategy.class.getSimpleName()))
return ProductiveByStrategy.instance();
else if (strategyName.equals(ExplainStrategy.class.getSimpleName()))
return ExplainStrategy.instance();
} else if (ctx.getChild(0).getText().equals("new")) {
final String strategyName = ctx.getChild(1).getText();
if (strategyName.equals(PartitionStrategy.class.getSimpleName()))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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.tinkerpop.gremlin.process.traversal.strategy.finalization;

import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectStep;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalExplanation;

/**
* @author Valentyn Kahamlyk
*/
public final class ExplainStrategy extends AbstractTraversalStrategy<TraversalStrategy.FinalizationStrategy> implements TraversalStrategy.FinalizationStrategy {

private static final ExplainStrategy INSTANCE = new ExplainStrategy();

private ExplainStrategy() {
}

@Override
public void apply(final Traversal.Admin<?, ?> traversal) {
final TraversalExplanation explanation = new TraversalExplanation(traversal.asAdmin());

for (int i = traversal.asAdmin().getSteps().size() - 1; i >= 0; i--) {
traversal.asAdmin().removeStep(i);
}

traversal.asAdmin().addStep(new InjectStep<>(traversal.asAdmin(), explanation.toString()));
}

public static ExplainStrategy instance() {
return INSTANCE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.ExplainStrategy;
import org.javatuples.Pair;
import org.javatuples.Triplet;

Expand Down Expand Up @@ -53,6 +54,8 @@ public TraversalExplanation(final Traversal.Admin<?, ?> traversal) {
this.traversal = traversal.clone();
final TraversalStrategies mutatingStrategies = new DefaultTraversalStrategies();
for (final TraversalStrategy strategy : this.traversal.getStrategies()) {
if (strategy instanceof ExplainStrategy) continue;

final Traversal.Admin<?, ?> mutatingTraversal = this.traversal.clone();
mutatingStrategies.addStrategies(strategy);
mutatingTraversal.setStrategies(mutatingStrategies);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SeedStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.ExplainStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.MatchAlgorithmStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.AdjacentToIncidentStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.ByModulatorOptimizationStrategy;
Expand Down Expand Up @@ -209,6 +210,7 @@ static final class GraphSONModuleV3d0 extends GraphSONModule {
RepeatUnrollStrategy.class,
ComputerVerificationStrategy.class,
LambdaRestrictionStrategy.class,
ExplainStrategy.class,
ReadOnlyStrategy.class,
StandardVerificationStrategy.class,
EarlyLimitStrategy.class,
Expand Down Expand Up @@ -340,6 +342,7 @@ protected GraphSONModuleV3d0(final boolean normalize) {
RepeatUnrollStrategy.class,
ComputerVerificationStrategy.class,
LambdaRestrictionStrategy.class,
ExplainStrategy.class,
ReadOnlyStrategy.class,
StandardVerificationStrategy.class,
EarlyLimitStrategy.class,
Expand Down Expand Up @@ -450,6 +453,7 @@ static final class GraphSONModuleV2d0 extends GraphSONModule {
RepeatUnrollStrategy.class,
ComputerVerificationStrategy.class,
LambdaRestrictionStrategy.class,
ExplainStrategy.class,
ReadOnlyStrategy.class,
StandardVerificationStrategy.class,
EarlyLimitStrategy.class,
Expand Down Expand Up @@ -571,6 +575,7 @@ protected GraphSONModuleV2d0(final boolean normalize) {
RepeatUnrollStrategy.class,
ComputerVerificationStrategy.class,
LambdaRestrictionStrategy.class,
ExplainStrategy.class,
ReadOnlyStrategy.class,
StandardVerificationStrategy.class,
EarlyLimitStrategy.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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.tinkerpop.gremlin.process.traversal.strategy.finalization;

import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectStep;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.CountStrategy;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
import org.junit.Test;

import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
import static org.junit.Assert.assertTrue;

public class ExplainStrategyTest {

private static final GraphTraversalSource g = traversal().withEmbedded(EmptyGraph.instance()).
withStrategies(CountStrategy.instance(), ReferenceElementStrategy.instance());

@Test
public void shouldModifyTraversal() {
final Traversal<Vertex, ?> t = g.withStrategies(ExplainStrategy.instance()).V().limit(1).count().is(0);

final String explanation = (String) t.next();

// GraphStep removed
assertTrue(t.asAdmin().getSteps().stream().noneMatch(s -> s instanceof GraphStep));
// InjectStep added
assertTrue(t.asAdmin().getSteps().stream().anyMatch(s -> s instanceof InjectStep));
assertTrue(explanation.startsWith("Traversal Explanation"));
}
}
1 change: 1 addition & 0 deletions gremlin-dotnet/build/generate.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ radishGremlinFile.withWriter('UTF-8') { Writer writer ->
'using System.Collections.Generic;\n' +
'using Gremlin.Net.Structure;\n' +
'using Gremlin.Net.Process.Traversal;\n' +
'using Gremlin.Net.Process.Traversal.Strategy.Finalization;\n' +
'using Gremlin.Net.Process.Traversal.Strategy.Optimization;\n' +
'using Gremlin.Net.Process.Traversal.Strategy.Verification;\n' +
'using Gremlin.Net.Process.Traversal.Strategy.Decoration;\n')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#region License

/*
* 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.
*/

#endregion

namespace Gremlin.Net.Process.Traversal.Strategy.Finalization
{
/// <summary>
/// Produces traversal explanation.
/// </summary>
public class ExplainStrategy : AbstractTraversalStrategy
{
private const string JavaFqcn = FinalizationNamespace + nameof(ExplainStrategy);

/// <summary>
/// Initializes a new instance of the <see cref="ExplainStrategy" /> class.
/// </summary>
public ExplainStrategy() : base(JavaFqcn)
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
using System.Collections.Generic;
using Gremlin.Net.Structure;
using Gremlin.Net.Process.Traversal;
using Gremlin.Net.Process.Traversal.Strategy.Finalization;
using Gremlin.Net.Process.Traversal.Strategy.Optimization;
using Gremlin.Net.Process.Traversal.Strategy.Verification;
using Gremlin.Net.Process.Traversal.Strategy.Decoration;
Expand Down Expand Up @@ -354,6 +355,7 @@ private static IDictionary<string, List<Func<GraphTraversalSource, IDictionary<s
{"g_withStrategiesXProductiveByStrategyX_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new ProductiveByStrategy(productiveKeys: new List<object> {})).V(p["vid3"]).As("a").In().Out().As("b").Where("a",P.Eq("b")).By("age").Values<object>("name")}},
{"g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("n").Where(__.Or(__.HasLabel("software"),__.HasLabel("person"))).Select<object>("n").By("name")}},
{"g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("n").Where(__.Or(__.Select<object>("n").HasLabel("software"),__.Select<object>("n").HasLabel("person"))).Select<object>("n").By("name")}},
{"g_withStrategiesXExplainStrategyX_V", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new ExplainStrategy()).V()}},
{"g_V_coworker", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Filter(__.OutE("created")).Aggregate("p").As("p1").Values<object>("name").As("p1n").Select<object>("p").Unfold<object>().Where(P.Neq("p1")).As("p2").Values<object>("name").As("p2n").Select<object>("p2").Out("created").Choose<object>(__.In("created").Where(P.Eq("p1")),__.Values<object>("name"),__.Constant<object>(p["xx1"])).Group<object,object>().By(__.Select<object>("p1n")).By(__.Group<object,object>().By(__.Select<object>("p2n")).By(__.Unfold<object>().Fold().Project<object>("numCoCreated","coCreated").By(__.Count(Scope.Local)).By())).Unfold<object>()}},
{"g_V_coworker_with_midV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Filter(__.OutE("created")).As("p1").V().HasLabel("person").Where(P.Neq("p1")).Filter(__.OutE("created")).As("p2").Map<object>(__.Out("created").Where(__.In("created").As("p1")).Values<object>("name").Fold()).Group<object,object>().By(__.Select<object>("p1").By("name")).By(__.Group<object,object>().By(__.Select<object>("p2").By("name")).By(__.Project<object>("numCoCreated","coCreated").By(__.Count(Scope.Local)).By())).Unfold<object>()}},
{"g_withStrategiesXPartitionStrategyXwrite_a_read_aXX_V_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("_partition","a").Property("name","alice").AddV("person").Property("_partition","b").Property("name","bob"), (g,p) =>g.WithStrategies(new PartitionStrategy(includeMetaProperties: false, partitionKey: "_partition", readPartitions: new HashSet<string> {"a"}, writePartition: "a")).V().Values<object>("name")}},
Expand Down
Loading

0 comments on commit 61c1efe

Please sign in to comment.