vertices); - @Override Q adjacent(Vertex vertex); @@ -156,7 +155,8 @@ public interface JanusGraphMultiVertexQuery> drop(); + } diff --git a/janusgraph-core/src/main/java/org/janusgraph/core/TransactionBuilder.java b/janusgraph-core/src/main/java/org/janusgraph/core/TransactionBuilder.java index 6fb041070f..8c6426d5d4 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/core/TransactionBuilder.java +++ b/janusgraph-core/src/main/java/org/janusgraph/core/TransactionBuilder.java @@ -15,6 +15,7 @@ package org.janusgraph.core; import org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration; +import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryDropStepStrategyMode; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryHasStepStrategyMode; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryLabelStepStrategyMode; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryPropertiesStrategyMode; @@ -186,6 +187,15 @@ public interface TransactionBuilder { */ TransactionBuilder setLabelsStepStrategyMode(MultiQueryLabelStepStrategyMode labelStepStrategyMode); + /** + * Sets `drop` step strategy mode. + *+ * Doesn't have any effect if multi-query was disabled via config `query.batch.enabled = false`. + * + * @return Object with the set drop strategy mode settings + */ + TransactionBuilder setDropStepStrategyMode(MultiQueryDropStepStrategyMode dropStepStrategyMode); + /** * Sets the group name for this transaction which provides a way for gathering * reporting on multiple transactions into one group. diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/configuration/GraphDatabaseConfiguration.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/configuration/GraphDatabaseConfiguration.java index 2e95b0d2a7..8237e3a9d0 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/graphdb/configuration/GraphDatabaseConfiguration.java +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/configuration/GraphDatabaseConfiguration.java @@ -61,6 +61,7 @@ import org.janusgraph.graphdb.query.index.BruteForceIndexSelectionStrategy; import org.janusgraph.graphdb.query.index.IndexSelectionStrategy; import org.janusgraph.graphdb.query.index.ThresholdBasedIndexSelectionStrategy; +import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryDropStepStrategyMode; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryLabelStepStrategyMode; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryPropertiesStrategyMode; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryStrategyRepeatStepMode; @@ -390,6 +391,15 @@ public class GraphDatabaseConfiguration { MultiQueryLabelStepStrategyMode.NONE.getConfigName()), ConfigOption.Type.MASKABLE, MultiQueryLabelStepStrategyMode.ALL.getConfigName()); + public static final ConfigOption
DROP_STEP_BATCH_MODE = new ConfigOption<>(QUERY_BATCH_NS,"drop-step-mode", + String.format("Batching mode for `drop()` step. Used only when `"+USE_MULTIQUERY.toStringWithoutRoot()+"` is `true`.
" + + "Supported modes:
" + + "- `%s` - Drops all vertices in a batch.
" + + "- `%s` - Skips drop batching optimization.
", + MultiQueryDropStepStrategyMode.ALL.getConfigName(), + MultiQueryDropStepStrategyMode.NONE.getConfigName()), + ConfigOption.Type.MASKABLE, MultiQueryDropStepStrategyMode.ALL.getConfigName()); + // ################ SCHEMA ####################### // ################################################ @@ -1444,6 +1454,7 @@ public boolean apply(@Nullable String s) { private MultiQueryHasStepStrategyMode hasStepStrategyMode; private MultiQueryPropertiesStrategyMode propertiesStrategyMode; private MultiQueryLabelStepStrategyMode labelStepStrategyMode; + private MultiQueryDropStepStrategyMode dropStepStrategyMode; private String schemaInitStrategy; private boolean dropSchemaBeforeInit; private String schemaInitJsonFile; @@ -1579,6 +1590,10 @@ public MultiQueryLabelStepStrategyMode labelStepStrategyMode() { return labelStepStrategyMode; } + public MultiQueryDropStepStrategyMode dropStepStrategyMode() { + return dropStepStrategyMode; + } + public boolean adjustQueryLimit() { return adjustQueryLimit; } @@ -1745,6 +1760,7 @@ private void preLoadConfiguration() { hasStepStrategyMode = selectExactConfig(HAS_STEP_BATCH_MODE, MultiQueryHasStepStrategyMode.values()); propertiesStrategyMode = selectExactConfig(PROPERTIES_BATCH_MODE, MultiQueryPropertiesStrategyMode.values()); labelStepStrategyMode = selectExactConfig(LABEL_STEP_BATCH_MODE, MultiQueryLabelStepStrategyMode.values()); + dropStepStrategyMode = selectExactConfig(DROP_STEP_BATCH_MODE, MultiQueryDropStepStrategyMode.values()); indexSelectionStrategy = Backend.getImplementationClass(configuration, configuration.get(INDEX_SELECT_STRATEGY), REGISTERED_INDEX_SELECTION_STRATEGIES); diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/query/vertex/MultiVertexCentricQueryBuilder.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/query/vertex/MultiVertexCentricQueryBuilder.java index c461f41852..7e6420a52d 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/graphdb/query/vertex/MultiVertexCentricQueryBuilder.java +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/query/vertex/MultiVertexCentricQueryBuilder.java @@ -203,9 +203,9 @@ public MapvertexIds() { } @Override - public Integer drop() { + public Map > drop() { Map > allRelations = this.noPartitionRestriction().all().relations(); allRelations.forEach((vertex, relations) -> ((InternalVertex) vertex).remove(relations)); - return allRelations.size(); + return allRelations; } } diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/JanusGraphDropStep.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/JanusGraphDropStep.java new file mode 100644 index 0000000000..f55596cd47 --- /dev/null +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/JanusGraphDropStep.java @@ -0,0 +1,146 @@ +// Copyright 2024 JanusGraph Authors +// +// Licensed 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.janusgraph.graphdb.tinkerpop.optimize.step; + +import org.apache.tinkerpop.gremlin.process.traversal.Traverser; +import org.apache.tinkerpop.gremlin.process.traversal.step.Profiling; +import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DropStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.CallbackRegistry; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.Event; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.EventCallback; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.EventUtil; +import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy; +import org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics; +import org.apache.tinkerpop.gremlin.structure.Element; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.janusgraph.core.BaseVertexQuery; +import org.janusgraph.graphdb.query.profile.QueryProfiler; +import org.janusgraph.graphdb.query.vertex.BasicVertexCentricQueryBuilder; +import org.janusgraph.graphdb.tinkerpop.optimize.step.fetcher.DropStepBatchFetcher; +import org.janusgraph.graphdb.tinkerpop.profile.TP3ProfileWrapper; +import org.janusgraph.graphdb.util.CopyStepUtil; +import org.janusgraph.graphdb.util.JanusGraphTraverserUtil; + +import java.util.List; + +/** + * This class extends the default TinkerPop's {@link DropStep} and adds vertices multi-query optimization to this step. + * + * Before this step is evaluated it usually receives multiple future vertices which might be processed next with this step. + * This step stores all these vertices which might be needed later for evaluation and whenever this step receives the + * vertex for evaluation which wasn't evaluated previously it sends multi-query for a batch of vertices to drop them. + *
+ * This step optimizes only drop of Vertices and skips optimization for any other Element. + */ +public class JanusGraphDropStep
extends DropStepimplements Profiling, MultiQueriable{ + + private boolean useMultiQuery = false; + private QueryProfiler queryProfiler = QueryProfiler.NO_OP; + private int batchSize = Integer.MAX_VALUE; + private DropStepBatchFetcher dropStepBatchFetcher; + + public JanusGraphDropStep(DropSteporiginalStep){ + super(originalStep.getTraversal()); + CopyStepUtil.copyAbstractStepModifiableFields(originalStep, this); + + CallbackRegistrycallbackRegistry = getMutatingCallbackRegistry(); + for(EventCallback callback : originalStep.getMutatingCallbackRegistry().getCallbacks()){ + callbackRegistry.addCallback(callback); + } + + if (originalStep instanceof JanusGraphDropStep) { + JanusGraphDropStep originalJanusGraphLabelStep = (JanusGraphDropStep) originalStep; + setBatchSize(originalJanusGraphLabelStep.batchSize); + setUseMultiQuery(originalJanusGraphLabelStep.useMultiQuery); + } + } + + @Override + protected boolean filter(final Traverser.Admin traverser) { + if (useMultiQuery && traverser.get() instanceof Vertex) { + dropStepBatchFetcher.fetchData(getTraversal(), (Vertex) traverser.get(), JanusGraphTraverserUtil.getLoops(traverser)); + return false; + } else { + return super.filter(traverser); + } + } + + @Override + public void setUseMultiQuery(boolean useMultiQuery) { + this.useMultiQuery = useMultiQuery; + if(this.useMultiQuery && dropStepBatchFetcher == null){ + dropStepBatchFetcher = new DropStepBatchFetcher(this::makeLabelsQuery, batchSize, (batchVertices, requiredVertex) -> { + List> callbacksForRemovalEvents = getMutatingCallbackRegistry().getCallbacks(); + if(!callbacksForRemovalEvents.isEmpty()){ + final EventStrategy eventStrategy = EventUtil.forceGetEventStrategy(traversal); + produceRemovedEvent(eventStrategy, callbacksForRemovalEvents, requiredVertex); + for(Vertex vertexInBatch : batchVertices){ + if(vertexInBatch != requiredVertex){ + produceRemovedEvent(eventStrategy, callbacksForRemovalEvents, vertexInBatch); + } + } + } + }); + } + } + + private static void produceRemovedEvent(EventStrategy eventStrategy, + List > callbacksForRemovalEvents, + Vertex vertex){ + final Event removeEvent = new Event.VertexRemovedEvent(eventStrategy.detach(vertex)); + for(EventCallback callback : callbacksForRemovalEvents){ + callback.accept(removeEvent); + } + } + + private Q makeLabelsQuery(Q query) { + ((BasicVertexCentricQueryBuilder) query).profiler(queryProfiler); + return query; + } + + @Override + public void setBatchSize(int batchSize) { + this.batchSize = batchSize; + if(dropStepBatchFetcher != null){ + dropStepBatchFetcher.setBatchSize(batchSize); + } + } + + @Override + public void registerFirstNewLoopFutureVertexForPrefetching(Vertex futureVertex, int futureVertexTraverserLoop) { + if(useMultiQuery){ + dropStepBatchFetcher.registerFirstNewLoopFutureVertexForPrefetching(futureVertex); + } + } + + @Override + public void registerSameLoopFutureVertexForPrefetching(Vertex futureVertex, int futureVertexTraverserLoop) { + if(useMultiQuery){ + dropStepBatchFetcher.registerCurrentLoopFutureVertexForPrefetching(futureVertex, futureVertexTraverserLoop); + } + } + + @Override + public void registerNextLoopFutureVertexForPrefetching(Vertex futureVertex, int futureVertexTraverserLoop) { + if(useMultiQuery){ + dropStepBatchFetcher.registerNextLoopFutureVertexForPrefetching(futureVertex, futureVertexTraverserLoop); + } + } + + @Override + public void setMetrics(MutableMetrics metrics) { + queryProfiler = new TP3ProfileWrapper(metrics); + } +} diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/JanusGraphNoOpBarrierVertexOnlyStep.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/JanusGraphNoOpBarrierVertexOnlyStep.java new file mode 100644 index 0000000000..2810c6f38a --- /dev/null +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/JanusGraphNoOpBarrierVertexOnlyStep.java @@ -0,0 +1,64 @@ +// Copyright 2024 JanusGraph Authors +// +// Licensed 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.janusgraph.graphdb.tinkerpop.optimize.step; + +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.Traverser; +import org.apache.tinkerpop.gremlin.process.traversal.step.map.NoOpBarrierStep; +import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +/** + * This implementation overwrites the standard NoOpBarrierStep with the same logic except that anytime we receive non-Vertex + * element during `processAllStarts` process we stop barrier fetching of more data into the barrier until that non-Vertex + * element is out from this barrier step. + * It means that for non-Vertex elements this barrier acts like it has size of `1`. For Vertex elements it acts + * same as normal `NoOpBarrierStep`. + */ +public class JanusGraphNoOpBarrierVertexOnlyStepextends NoOpBarrierStep{ + + public JanusGraphNoOpBarrierVertexOnlyStep(final Traversal.Admin traversal) { + super(traversal); + } + + public JanusGraphNoOpBarrierVertexOnlyStep(final Traversal.Admin traversal, final int maxBarrierSize) { + super(traversal, maxBarrierSize); + } + + public JanusGraphNoOpBarrierVertexOnlyStep(final Traversal.Admin traversal, final int maxBarrierSize, TraverserSetbarrier) { + super(traversal, maxBarrierSize, barrier); + } + + @Override + public void processAllStarts() { + if(!this.barrier.isEmpty()){ + return; + } + while ((this.maxBarrierSize == Integer.MAX_VALUE || this.barrier.size() < this.maxBarrierSize) && this.starts.hasNext()) { + final Traverser.Admintraverser = this.starts.next(); + traverser.setStepId(this.getNextStep().getId()); // when barrier is reloaded, the traversers should be at the next step + this.barrier.add(traverser); + if(!(traverser.get() instanceof Vertex)){ + break; + } + } + } + + @Override + public JanusGraphNoOpBarrierVertexOnlyStepclone() { + return (JanusGraphNoOpBarrierVertexOnlyStep) super.clone(); + } + +} diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/fetcher/DropStepBatchFetcher.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/fetcher/DropStepBatchFetcher.java new file mode 100644 index 0000000000..fb9c088a08 --- /dev/null +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/fetcher/DropStepBatchFetcher.java @@ -0,0 +1,38 @@ +// Copyright 2024 JanusGraph Authors +// +// Licensed 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.janusgraph.graphdb.tinkerpop.optimize.step.fetcher; + +import org.janusgraph.core.JanusGraphMultiVertexQuery; +import org.janusgraph.core.JanusGraphRelation; +import org.janusgraph.core.JanusGraphVertex; + +import java.util.Map; + +public class DropStepBatchFetcher extends MultiQueriableStepBatchFetcher>{ + + private final FetchQueryBuildFunction fetchQueryBuildFunction; + + public DropStepBatchFetcher(FetchQueryBuildFunction fetchQueryBuildFunction, int batchSize, + TriggeredBatchConsumer batchConsumerBeforeQuery) { + super(batchSize, batchConsumerBeforeQuery); + this.fetchQueryBuildFunction = fetchQueryBuildFunction; + } + + @Override + protected Map > makeQueryAndExecute(JanusGraphMultiVertexQuery multiQuery) { + multiQuery = fetchQueryBuildFunction.makeQuery(multiQuery); + return multiQuery.drop(); + } +} diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/fetcher/MultiQueriableStepBatchFetcher.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/fetcher/MultiQueriableStepBatchFetcher.java index 00fd7587d0..e4a25136c5 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/fetcher/MultiQueriableStepBatchFetcher.java +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/fetcher/MultiQueriableStepBatchFetcher.java @@ -31,17 +31,25 @@ */ public abstract class MultiQueriableStepBatchFetcher { + private static final TriggeredBatchConsumer EMPTY_BATCH_CONSUMER = (b, t) -> {}; + private Map multiQueryResults = null; private int batchSize; private int currentLoops = 0; private BatchProcessingQueue firstLoopBatchProcessingQueue; private BatchProcessingQueue currentLoopBatchProcessingQueue; private BatchProcessingQueue nextLoopBatchProcessingQueue; + private final TriggeredBatchConsumer batchConsumerBeforeQuery; public MultiQueriableStepBatchFetcher(int batchSize){ + this(batchSize, EMPTY_BATCH_CONSUMER); + } + + public MultiQueriableStepBatchFetcher(int batchSize, TriggeredBatchConsumer batchConsumerBeforeQuery){ this.batchSize = batchSize; this.currentLoopBatchProcessingQueue = generateNewBatchProcessingQueue(); this.nextLoopBatchProcessingQueue = generateNewBatchProcessingQueue(); + this.batchConsumerBeforeQuery = batchConsumerBeforeQuery; } public void registerCurrentLoopFutureVertexForPrefetching(Vertex forGeneralVertex, int traverserLoops) { @@ -105,9 +113,10 @@ private boolean hasNoFetchedData(Vertex forVertex){ } protected Map prefetchNextBatch(final Traversal.Admin, ?> traversal, JanusGraphVertex requiredFetchVertex){ - final JanusGraphMultiVertexQuery multiQuery = JanusGraphTraversalUtil.getTx(traversal) - .multiQuery(nextBatch()); + Collection batch = nextBatch(); + final JanusGraphMultiVertexQuery multiQuery = JanusGraphTraversalUtil.getTx(traversal).multiQuery(batch); multiQuery.addVertex(requiredFetchVertex); + batchConsumerBeforeQuery.consume(batch, requiredFetchVertex); try { return makeQueryAndExecute(multiQuery); } catch (JanusGraphException janusGraphException) { diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/fetcher/TriggeredBatchConsumer.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/fetcher/TriggeredBatchConsumer.java new file mode 100644 index 0000000000..7d6bfd2949 --- /dev/null +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/step/fetcher/TriggeredBatchConsumer.java @@ -0,0 +1,23 @@ +// Copyright 2024 JanusGraph Authors +// +// Licensed 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.janusgraph.graphdb.tinkerpop.optimize.step.fetcher; + +import java.util.Collection; + +public interface TriggeredBatchConsumer { + + void consume(Collection batch, E triggeringElement); + +} diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/strategy/JanusGraphLocalQueryOptimizerStrategy.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/strategy/JanusGraphLocalQueryOptimizerStrategy.java index 8e3a56dc03..e1ba04c03a 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/strategy/JanusGraphLocalQueryOptimizerStrategy.java +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/strategy/JanusGraphLocalQueryOptimizerStrategy.java @@ -18,6 +18,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; import org.apache.tinkerpop.gremlin.process.traversal.step.branch.LocalStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DropStep; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeGlobalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.ElementMapStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.LabelStep; @@ -31,6 +32,7 @@ import org.janusgraph.graphdb.query.QueryUtil; import org.janusgraph.graphdb.tinkerpop.optimize.JanusGraphTraversalUtil; import org.janusgraph.graphdb.tinkerpop.optimize.step.HasStepFolder; +import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphDropStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphElementMapStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphLabelStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphPropertiesStep; @@ -70,6 +72,7 @@ public void apply(final Traversal.Admin, ?> traversal) { final Optional tx = JanusGraphTraversalUtil.getJanusGraphTx(traversal); final MultiQueryPropertiesStrategyMode propertiesStrategyMode; final MultiQueryLabelStepStrategyMode labelStepStrategyMode; + final MultiQueryDropStepStrategyMode dropStepStrategyMode; final int txVertexCacheSize; if(tx.isPresent()){ @@ -77,16 +80,19 @@ public void apply(final Traversal.Admin, ?> traversal) { txVertexCacheSize = txConfig.getVertexCacheSize(); propertiesStrategyMode = txConfig.getPropertiesStrategyMode(); labelStepStrategyMode = txConfig.getLabelStepStrategyMode(); + dropStepStrategyMode = txConfig.getDropStepStrategyMode(); } else { GraphDatabaseConfiguration graphConfig = janusGraph.getConfiguration(); txVertexCacheSize = graphConfig.getTxVertexCacheSize(); propertiesStrategyMode = graphConfig.propertiesStrategyMode(); labelStepStrategyMode = graphConfig.labelStepStrategyMode(); + dropStepStrategyMode = graphConfig.dropStepStrategyMode(); } applyJanusGraphVertexSteps(traversal); applyJanusGraphPropertiesSteps(traversal, txVertexCacheSize, propertiesStrategyMode); applyJanusGraphLabelSteps(traversal, labelStepStrategyMode); + applyJanusGraphDropSteps(traversal, dropStepStrategyMode); inspectLocalTraversals(traversal, txVertexCacheSize, propertiesStrategyMode); } @@ -203,6 +209,19 @@ private void applyJanusGraphLabelSteps(Traversal.Admin, ?> traversal, MultiQue }); } + private void applyJanusGraphDropSteps(Traversal.Admin, ?> traversal, MultiQueryDropStepStrategyMode dropStepStrategyMode){ + if(MultiQueryDropStepStrategyMode.NONE.equals(dropStepStrategyMode)){ + return; + } + TraversalHelper.getStepsOfAssignableClass(DropStep.class, traversal).forEach(originalStep -> { + if(originalStep instanceof JanusGraphDropStep){ + return; + } + final JanusGraphDropStep janusGraphDropStep = new JanusGraphDropStep(originalStep); + TraversalHelper.replaceStep(originalStep, janusGraphDropStep, originalStep.getTraversal()); + }); + } + private static void unfoldLocalTraversal(final Traversal.Admin, ?> traversal, LocalStep, ?> localStep, Traversal.Admin localTraversal, MultiQueriable vertexStep) { diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/strategy/JanusGraphMultiQueryStrategy.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/strategy/JanusGraphMultiQueryStrategy.java index 85329a6ba4..d8adfcffce 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/strategy/JanusGraphMultiQueryStrategy.java +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/strategy/JanusGraphMultiQueryStrategy.java @@ -20,7 +20,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; import org.apache.tinkerpop.gremlin.process.traversal.step.branch.RepeatStep; -import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DropStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.NoOpBarrierStep; import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; @@ -30,6 +29,7 @@ import org.janusgraph.graphdb.tinkerpop.optimize.MultiQueryPositions; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphMultiQueryStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.MultiQueriable; +import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphNoOpBarrierVertexOnlyStep; import org.janusgraph.graphdb.transaction.StandardJanusGraphTx; import java.util.Arrays; @@ -55,11 +55,7 @@ private JanusGraphMultiQueryStrategy() { @Override public void apply(final Admin, ?> traversal) { - if (!traversal.getGraph().isPresent() - || TraversalHelper.onGraphComputer(traversal) - // The LazyBarrierStrategy is not allowed to run on traversals which use drop(). As a precaution, - // this strategy should not run on those traversals either, because it can also insert barrier(). - || !TraversalHelper.getStepsOfAssignableClassRecursively(DropStep.class, traversal).isEmpty()) { + if (!traversal.getGraph().isPresent() || TraversalHelper.onGraphComputer(traversal)) { return; } @@ -129,7 +125,7 @@ private void insertMultiQueryStep(Step position, boolean limitedBatch, int limit multiQueryStep = new JanusGraphMultiQueryStep(traversal, limitedBatch, ((NoOpBarrierStep) position).getMaxBarrierSize()); } else { - NoOpBarrierStep barrier = new NoOpBarrierStep(traversal, limitedBatchSize); + NoOpBarrierStep barrier = new JanusGraphNoOpBarrierVertexOnlyStep(traversal, limitedBatchSize); TraversalHelper.insertBeforeStep(barrier, position, traversal); position = barrier; multiQueryStep = new JanusGraphMultiQueryStep(traversal, limitedBatch, barrier); diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/strategy/MultiQueryDropStepStrategyMode.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/strategy/MultiQueryDropStepStrategyMode.java new file mode 100644 index 0000000000..3ee6a1a90b --- /dev/null +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/tinkerpop/optimize/strategy/MultiQueryDropStepStrategyMode.java @@ -0,0 +1,42 @@ +// Copyright 2024 JanusGraph Authors +// +// Licensed 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.janusgraph.graphdb.tinkerpop.optimize.strategy; + +import org.janusgraph.graphdb.configuration.ConfigName; + +public enum MultiQueryDropStepStrategyMode implements ConfigName { + + /** + * Prefetch labels for all vertices in a batch. + */ + ALL("all"), + + /** + * Skips `label` step pre-fetch optimization. + */ + NONE("none") + ; + + private final String configurationOptionName; + + MultiQueryDropStepStrategyMode(String configurationOptionName){ + this.configurationOptionName = configurationOptionName; + } + + @Override + public String getConfigName() { + return configurationOptionName; + } +} diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/transaction/StandardTransactionBuilder.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/transaction/StandardTransactionBuilder.java index 18285ee8d5..8c79cd6784 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/graphdb/transaction/StandardTransactionBuilder.java +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/transaction/StandardTransactionBuilder.java @@ -28,6 +28,7 @@ import org.janusgraph.diskstorage.util.time.TimestampProvider; import org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration; import org.janusgraph.graphdb.database.StandardJanusGraph; +import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryDropStepStrategyMode; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryHasStepStrategyMode; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryLabelStepStrategyMode; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryPropertiesStrategyMode; @@ -91,9 +92,9 @@ public class StandardTransactionBuilder implements TransactionConfiguration, Tra private boolean isLazyLoadRelations; private MultiQueryHasStepStrategyMode hasStepStrategyMode; - private MultiQueryPropertiesStrategyMode propertiesStrategyMode; private MultiQueryLabelStepStrategyMode labelStepStrategyMode; + private MultiQueryDropStepStrategyMode dropStepStrategyMode; private final boolean forceIndexUsage; @@ -120,6 +121,7 @@ private StandardTransactionBuilder(GraphDatabaseConfiguration graphConfig, Stand this.hasStepStrategyMode = graphConfig.hasStepStrategyMode(); this.propertiesStrategyMode = graphConfig.propertiesStrategyMode(); this.labelStepStrategyMode = graphConfig.labelStepStrategyMode(); + this.dropStepStrategyMode = graphConfig.dropStepStrategyMode(); this.writableCustomOptions = writableCustomOptions; if(customOptions == null){ this.customOptions = new MergedConfiguration(writableCustomOptions, graphConfig.getConfiguration()); @@ -260,6 +262,12 @@ public TransactionBuilder setLabelsStepStrategyMode(MultiQueryLabelStepStrategyM return this; } + @Override + public TransactionBuilder setDropStepStrategyMode(MultiQueryDropStepStrategyMode dropStepStrategyMode) { + this.dropStepStrategyMode = dropStepStrategyMode; + return this; + } + @Override public void setCommitTime(Instant time) { throw new UnsupportedOperationException("Use setCommitTime(long,TimeUnit)"); @@ -307,7 +315,7 @@ propertyPrefetching, multiQuery, singleThreaded, threadBound, getTimestampProvid indexCacheWeight, getVertexCacheSize(), getDirtyVertexSize(), logIdentifier, restrictedPartitions, groupName, defaultSchemaMaker, hasDisabledSchemaConstraints, skipDBCacheRead, isLazyLoadRelations, hasStepStrategyMode, propertiesStrategyMode, - labelStepStrategyMode, customOptions); + labelStepStrategyMode, dropStepStrategyMode, customOptions); return graph.newTransaction(immutable); } @@ -444,6 +452,11 @@ public MultiQueryLabelStepStrategyMode getLabelStepStrategyMode() { return labelStepStrategyMode; } + @Override + public MultiQueryDropStepStrategyMode getDropStepStrategyMode() { + return dropStepStrategyMode; + } + @Override public String getGroupName() { return groupName; @@ -508,6 +521,7 @@ private static class ImmutableTxCfg implements TransactionConfiguration { private MultiQueryHasStepStrategyMode hasStepStrategyMode; private MultiQueryPropertiesStrategyMode propertiesStrategyMode; private MultiQueryLabelStepStrategyMode labelStepStrategyMode; + private MultiQueryDropStepStrategyMode dropStepStrategyMode; private final BaseTransactionConfig handleConfig; @@ -531,6 +545,7 @@ public ImmutableTxCfg(boolean isReadOnly, MultiQueryHasStepStrategyMode hasStepStrategyMode, MultiQueryPropertiesStrategyMode propertiesStrategyMode, MultiQueryLabelStepStrategyMode labelStepStrategyMode, + MultiQueryDropStepStrategyMode dropStepStrategyMode, Configuration customOptions) { this.isReadOnly = isReadOnly; this.hasEnabledBatchLoading = hasEnabledBatchLoading; @@ -557,6 +572,7 @@ public ImmutableTxCfg(boolean isReadOnly, this.hasStepStrategyMode = hasStepStrategyMode; this.propertiesStrategyMode = propertiesStrategyMode; this.labelStepStrategyMode = labelStepStrategyMode; + this.dropStepStrategyMode = dropStepStrategyMode; this.handleConfig = new StandardBaseTransactionConfig.Builder() .commitTime(commitTime) .timestampProvider(times) @@ -694,6 +710,11 @@ public MultiQueryLabelStepStrategyMode getLabelStepStrategyMode() { return labelStepStrategyMode; } + @Override + public MultiQueryDropStepStrategyMode getDropStepStrategyMode() { + return dropStepStrategyMode; + } + @Override public Instant getCommitTime() { return handleConfig.getCommitTime(); diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/transaction/TransactionConfiguration.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/transaction/TransactionConfiguration.java index 9f2aed3122..7373765fe7 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/graphdb/transaction/TransactionConfiguration.java +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/transaction/TransactionConfiguration.java @@ -16,6 +16,7 @@ import org.janusgraph.core.schema.DefaultSchemaMaker; import org.janusgraph.diskstorage.BaseTransactionConfig; +import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryDropStepStrategyMode; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryHasStepStrategyMode; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryLabelStepStrategyMode; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryPropertiesStrategyMode; @@ -220,4 +221,9 @@ public interface TransactionConfiguration extends BaseTransactionConfig { */ MultiQueryLabelStepStrategyMode getLabelStepStrategyMode(); + /** + * @return Drop step strategy mode used for the transaction. Can be configured via config `query.batch.drop-step-mode`. + */ + MultiQueryDropStepStrategyMode getDropStepStrategyMode(); + } diff --git a/janusgraph-inmemory/src/test/java/org/janusgraph/graphdb/inmemory/InMemoryGraphTest.java b/janusgraph-inmemory/src/test/java/org/janusgraph/graphdb/inmemory/InMemoryGraphTest.java index a37c4cb9d9..a9c3b8a6d4 100644 --- a/janusgraph-inmemory/src/test/java/org/janusgraph/graphdb/inmemory/InMemoryGraphTest.java +++ b/janusgraph-inmemory/src/test/java/org/janusgraph/graphdb/inmemory/InMemoryGraphTest.java @@ -134,4 +134,14 @@ public void testSupportDirectCommitOfSchemaChangesForConnection() {} @Override @Test @Disabled public void testSupportDirectCommitOfSchemaChangesForEdgeProperties() {} + + @Override @Test @Disabled + public void testMultiQueryDropsStrategyModes() {} + + @Override @Test @Disabled + public void testMetaPropertiesDrop() {} + + @Override @Test @Disabled + public void testEdgePropertiesDrop() {} + } diff --git a/janusgraph-inmemory/src/test/java/org/janusgraph/graphdb/inmemory/InMemoryLazyLoadGraphTest.java b/janusgraph-inmemory/src/test/java/org/janusgraph/graphdb/inmemory/InMemoryLazyLoadGraphTest.java index b91b2482ba..acc112fe83 100644 --- a/janusgraph-inmemory/src/test/java/org/janusgraph/graphdb/inmemory/InMemoryLazyLoadGraphTest.java +++ b/janusgraph-inmemory/src/test/java/org/janusgraph/graphdb/inmemory/InMemoryLazyLoadGraphTest.java @@ -50,4 +50,5 @@ public void testPropertyIdAccessInDifferentTransaction() { Exception exception = assertThrows(IllegalStateException.class, p::id); assertEquals(exception.getMessage(), "Any lazy load operation is not supported when transaction is already closed."); } + } diff --git a/janusgraph-test/src/test/java/org/janusgraph/graphdb/tinkerpop/optimize/AdjacentVertexHasUniquePropertyOptimizerStrategyTest.java b/janusgraph-test/src/test/java/org/janusgraph/graphdb/tinkerpop/optimize/AdjacentVertexHasUniquePropertyOptimizerStrategyTest.java index 19b2085aef..d91ca8f67e 100644 --- a/janusgraph-test/src/test/java/org/janusgraph/graphdb/tinkerpop/optimize/AdjacentVertexHasUniquePropertyOptimizerStrategyTest.java +++ b/janusgraph-test/src/test/java/org/janusgraph/graphdb/tinkerpop/optimize/AdjacentVertexHasUniquePropertyOptimizerStrategyTest.java @@ -18,6 +18,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.NoOpBarrierStep; import org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphHasStep; +import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphNoOpBarrierVertexOnlyStep; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.AdjacentVertexHasUniquePropertyOptimizerStrategy; import org.junit.jupiter.api.Test; @@ -43,11 +44,11 @@ public void testWithBackendAccess() { // AdjacentVertexHasUniquePropertyOptimizer assertNumStep(1, 0, g.V(sv[0]).out().has("uniqueId", 0), JanusGraphHasStep.class); - assertNumStep(1, 1, g.V(sv[0]).out().barrier(2500).has("uniqueId", 0), NoOpBarrierStep.class); - assertNumStep(1, 1, g.V(sv[0]).outE().inV().has("uniqueId", 0), NoOpBarrierStep.class); + assertNumStep(1, 1, g.V(sv[0]).out().barrier(2500).has("uniqueId", 0), JanusGraphNoOpBarrierVertexOnlyStep.class); + assertNumStep(1, 1, g.V(sv[0]).outE().inV().has("uniqueId", 0), JanusGraphNoOpBarrierVertexOnlyStep.class); assertNumStep(1, 0, g.V(sv[0]).outE().inV().has("uniqueId", 0), JanusGraphHasStep.class); - assertNumStep(1, 1, g.V(sv[0]).outE().inV().barrier(2500).has("uniqueId", 0), NoOpBarrierStep.class); - assertNumStep(1, 1, g.V(sv[0]).outE().barrier(2500).inV().has("uniqueId", 0), NoOpBarrierStep.class); + assertNumStep(1, 1, g.V(sv[0]).outE().inV().barrier(2500).has("uniqueId", 0), JanusGraphNoOpBarrierVertexOnlyStep.class); + assertNumStep(1, 1, g.V(sv[0]).outE().barrier(2500).inV().has("uniqueId", 0), JanusGraphNoOpBarrierVertexOnlyStep.class); assertNumStep(1, 1, g.V(sv[0]).barrier(2500).out().barrier(2500).has("uniqueId", 0), NoOpBarrierStep.class); assertNumStep(1, 0, g.V(sv[0]).out().barrier(2500).has("uniqueId", 0), JanusGraphHasStep.class); assertNumStep(1, 1, g.V(sv[0]).out().has("id", 0), JanusGraphHasStep.class); @@ -67,10 +68,12 @@ public void testWithoutBackendAccess() { // AdjacentVertexHasUniquePropertyOptimizer assertNumStep(1, 1, g.V(sv[0]).out().has("uniqueId", 0), JanusGraphHasStep.class); - assertNumStep(1, 2, g.V(sv[0]).outE().inV().has("uniqueId", 0), NoOpBarrierStep.class); + assertNumStep(1, 2, g.V(sv[0]).outE().inV().has("uniqueId", 0), JanusGraphNoOpBarrierVertexOnlyStep.class); assertNumStep(1, 1, g.V(sv[0]).outE().inV().has("uniqueId", 0), JanusGraphHasStep.class); - assertNumStep(1, 2, g.V(sv[0]).outE().inV().barrier(2500).has("uniqueId", 0), NoOpBarrierStep.class); - assertNumStep(1, 3, g.V(sv[0]).outE().barrier(2500).inV().has("uniqueId", 0), NoOpBarrierStep.class); + assertNumStep(1, 1, g.V(sv[0]).outE().inV().barrier(2500).has("uniqueId", 0), NoOpBarrierStep.class); + assertNumStep(1, 1, g.V(sv[0]).outE().inV().barrier(2500).has("uniqueId", 0), JanusGraphNoOpBarrierVertexOnlyStep.class); + assertNumStep(1, 1, g.V(sv[0]).outE().barrier(2500).inV().has("uniqueId", 0), NoOpBarrierStep.class); + assertNumStep(1, 2, g.V(sv[0]).outE().barrier(2500).inV().has("uniqueId", 0), JanusGraphNoOpBarrierVertexOnlyStep.class); assertNumStep(1, 2, g.V(sv[0]).barrier(2500).out().barrier(2500).has("uniqueId", 0), NoOpBarrierStep.class); assertNumStep(1, 1, g.V(sv[0]).out().barrier(2500).has("uniqueId", 0), JanusGraphHasStep.class); assertNumStep(1, 1, g.V(sv[0]).out().has("id", 0), JanusGraphHasStep.class); diff --git a/janusgraph-test/src/test/java/org/janusgraph/graphdb/tinkerpop/optimize/JanusGraphMultiQueryStrategyTest.java b/janusgraph-test/src/test/java/org/janusgraph/graphdb/tinkerpop/optimize/JanusGraphMultiQueryStrategyTest.java index ad3f389630..104143030e 100644 --- a/janusgraph-test/src/test/java/org/janusgraph/graphdb/tinkerpop/optimize/JanusGraphMultiQueryStrategyTest.java +++ b/janusgraph-test/src/test/java/org/janusgraph/graphdb/tinkerpop/optimize/JanusGraphMultiQueryStrategyTest.java @@ -31,6 +31,7 @@ import org.apache.tinkerpop.gremlin.structure.Edge; import org.janusgraph.graphdb.query.profile.QueryProfiler; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphMultiQueryStep; +import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphNoOpBarrierVertexOnlyStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphPropertiesStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphVertexStep; @@ -85,7 +86,7 @@ public void testNoOpBarrierStepInsertedIfNotPresentAndLimitBatchSize() { makeSampleGraph(); final GraphTraversal,?> traversalWithoutExplicitBarrier = g.V(sv[0]).outE().inV(); - assertNumStep(numV, 1, traversalWithoutExplicitBarrier, NoOpBarrierStep.class); + assertNumStep(numV, 1, traversalWithoutExplicitBarrier, JanusGraphNoOpBarrierVertexOnlyStep.class); final GraphTraversal,?> traversalWithExplicitBarrier = g.V(sv[0]).barrier(1).outE().inV(); assertNumStep(numV, 1, traversalWithExplicitBarrier, NoOpBarrierStep.class); @@ -96,11 +97,11 @@ public void testNoOpBarrierStepNotInsertedLimitBatchSizeDisabled() { clopen(option(USE_MULTIQUERY), true, option(LIMITED_BATCH), false); makeSampleGraph(); - final GraphTraversal,?> traversalWithoutExplicitBarrier = g.V(sv[0]).outE().inV(); - assertNumStep(numV, 0, traversalWithoutExplicitBarrier, NoOpBarrierStep.class); + assertNumStep(numV, 0, g.V(sv[0]).outE().inV(), JanusGraphNoOpBarrierVertexOnlyStep.class); + assertNumStep(numV, 0, g.V(sv[0]).outE().inV(), NoOpBarrierStep.class); - final GraphTraversal,?> traversalWithExplicitBarrier = g.V(sv[0]).barrier(1).outE().inV(); - assertNumStep(numV, 1, traversalWithExplicitBarrier, NoOpBarrierStep.class); + assertNumStep(numV, 1, g.V(sv[0]).barrier(1).outE().inV(), NoOpBarrierStep.class); + assertNumStep(numV, 0, g.V(sv[0]).barrier(1).outE().inV(), JanusGraphNoOpBarrierVertexOnlyStep.class); } @Test @@ -176,8 +177,8 @@ public void testNonNecessaryMultiQueryUnused(){ makeSampleGraph(); TraversalMetrics traversalMetricsWithStrategy = graph.traversal() - .V().id() - .choose(__.is(P.gte(5000L)), __.constant(12345L), __.identity()) + .V() + .choose(__.id().is(P.gte(5000L)), __.constant(12345L), __.id()) .limit(3).profile().next(); Long graphStepTraversalsCount = traversalMetricsWithStrategy.getMetrics().stream().filter(metrics -> metrics.getName().startsWith(JanusGraphStep.class.getSimpleName())) @@ -188,8 +189,8 @@ public void testNonNecessaryMultiQueryUnused(){ assertTrue(graphStepTraversalsCount < 5L); TraversalMetrics traversalMetricsWithoutStrategy = graph.traversal().withoutStrategies(JanusGraphUnusedMultiQueryRemovalStrategy.class) - .V().id() - .choose(__.is(P.gte(5000L)), __.constant(12345L), __.identity()) + .V() + .choose(__.id().is(P.gte(5000L)), __.constant(12345L), __.id()) .limit(3).profile().next(); graphStepTraversalsCount = traversalMetricsWithoutStrategy.getMetrics().stream().filter(metrics -> metrics.getName().startsWith(JanusGraphStep.class.getSimpleName())) diff --git a/janusgraph-test/src/test/java/org/janusgraph/graphdb/tinkerpop/optimize/JanusGraphStepStrategyTest.java b/janusgraph-test/src/test/java/org/janusgraph/graphdb/tinkerpop/optimize/JanusGraphStepStrategyTest.java index 8316af3fdd..cd4b04a317 100644 --- a/janusgraph-test/src/test/java/org/janusgraph/graphdb/tinkerpop/optimize/JanusGraphStepStrategyTest.java +++ b/janusgraph-test/src/test/java/org/janusgraph/graphdb/tinkerpop/optimize/JanusGraphStepStrategyTest.java @@ -24,6 +24,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DropStep; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.IsStep; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.OrStep; @@ -55,10 +56,12 @@ import org.janusgraph.graphdb.predicate.ConnectiveJanusPredicate; import org.janusgraph.graphdb.query.JanusGraphPredicateUtils; import org.janusgraph.graphdb.tinkerpop.optimize.step.HasStepFolder; +import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphDropStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphElementMapStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphHasStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphLabelStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphMultiQueryStep; +import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphNoOpBarrierVertexOnlyStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphPropertiesStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphPropertyMapStep; import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphStep; @@ -68,6 +71,7 @@ import org.janusgraph.graphdb.tinkerpop.optimize.strategy.JanusGraphMultiQueryStrategy; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.JanusGraphStepStrategy; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.JanusGraphUnusedMultiQueryRemovalStrategy; +import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryDropStepStrategyMode; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.MultiQueryStrategyRepeatStepMode; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -91,6 +95,8 @@ import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.not; import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.properties; import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.values; +import static org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.DROP_STEP_BATCH_MODE; +import static org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.LIMITED_BATCH_SIZE; import static org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.REPEAT_STEP_BATCH_MODE; import static org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.USE_MULTIQUERY; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -175,6 +181,8 @@ private void applyMultiQueryTraversalSteps(Traversal.Admin,?> traversal) { Object expectedStep = isStep.getPredicate().getValue(); if (expectedStep.equals(JanusGraphMultiQueryStep.class.getSimpleName())) { TraversalHelper.replaceStep(isStep, new JanusGraphMultiQueryStep(isStep.getTraversal(), false), isStep.getTraversal()); + } else if (expectedStep.equals(JanusGraphNoOpBarrierVertexOnlyStep.class.getSimpleName())) { + TraversalHelper.replaceStep(isStep, new JanusGraphNoOpBarrierVertexOnlyStep(isStep.getTraversal(), LIMITED_BATCH_SIZE.getDefaultValue()), isStep.getTraversal()); } }); TraversalHelper.getStepsOfAssignableClassRecursively(HasStep.class, traversal).forEach(hasStep -> { @@ -193,6 +201,10 @@ private void applyMultiQueryTraversalSteps(Traversal.Admin,?> traversal) { JanusGraphLabelStep janusGraphLabelStep = new JanusGraphLabelStep<>(labelStep); TraversalHelper.replaceStep(labelStep, janusGraphLabelStep, labelStep.getTraversal()); }); + TraversalHelper.getStepsOfAssignableClassRecursively(DropStep.class, traversal).forEach(dropStep -> { + JanusGraphDropStep janusGraphDropStep = new JanusGraphDropStep<>(dropStep); + TraversalHelper.replaceStep(dropStep, janusGraphDropStep, dropStep.getTraversal()); + }); } @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -321,7 +333,9 @@ private static Stream generateTestParameters() { } private static Stream generateMultiQueryTestParameters() { - final StandardJanusGraph generalGraph = (StandardJanusGraph) StorageSetup.getInMemoryGraphWithMultiQuery(); + final StandardJanusGraph generalGraph = (StandardJanusGraph) JanusGraphFactory.open( + StorageSetup.getInMemoryConfiguration().set(USE_MULTIQUERY, true) + .set(DROP_STEP_BATCH_MODE, MultiQueryDropStepStrategyMode.ALL.getConfigName()));; final StandardJanusGraph graphWithRepeatClosestParent = (StandardJanusGraph) JanusGraphFactory.open( StorageSetup.getInMemoryConfiguration().set(USE_MULTIQUERY, true) .set(REPEAT_STEP_BATCH_MODE, MultiQueryStrategyRepeatStepMode.CLOSEST_REPEAT_PARENT.getConfigName())); @@ -350,6 +364,7 @@ private static Stream generateMultiQueryTestParameters() { // String constant for expected JanusGraphMultiQueryStep final String MQ_STEP = JanusGraphMultiQueryStep.class.getSimpleName(); + final String NO_OP_B_V_STEP = JanusGraphNoOpBarrierVertexOnlyStep.class.getSimpleName(); List otherStrategies = new ArrayList<>(4); otherStrategies.add(JanusGraphLocalQueryOptimizerStrategy.instance()); @@ -360,120 +375,123 @@ private static Stream generateMultiQueryTestParameters() { return Arrays.stream(new Arguments[]{ arguments(g.V().in("knows").out("knows"), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).in("knows").is(MQ_STEP).barrier(defaultBarrierSize).out("knows"), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).in("knows").is(MQ_STEP).is(NO_OP_B_V_STEP).out("knows"), otherStrategies), arguments(g.V().in("knows").values("weight"), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).in("knows").is(MQ_STEP).barrier(defaultBarrierSize).values("weight"), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).in("knows").is(MQ_STEP).is(NO_OP_B_V_STEP).values("weight"), otherStrategies), // Need two JanusGraphMultiQuerySteps, one for each sub query because caches are flushed when queried arguments(g.V().choose(__.inE("knows").has("weight", 0),__.inE("knows").has("weight", 1)), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).choose(__.inE("knows").has("weight", 0),__.inE("knows").has("weight", 1)), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).choose(__.inE("knows").has("weight", 0),__.inE("knows").has("weight", 1)), otherStrategies), arguments(g.V().union(__.inE("knows").has("weight", 0),__.inE("knows").has("weight", 1)), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).union(__.inE("knows").has("weight", 0),__.inE("knows").has("weight", 1)), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).union(__.inE("knows").has("weight", 0),__.inE("knows").has("weight", 1)), otherStrategies), arguments(g.V().outE().optional(__.inE("knows").has("weight", 0)), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).outE().is(MQ_STEP).barrier(defaultBarrierSize).optional(__.inE("knows").has("weight", 0)), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).outE().is(MQ_STEP).is(NO_OP_B_V_STEP).optional(__.inE("knows").has("weight", 0)), otherStrategies), arguments(g.V().outE().filter(__.inE("knows").has("weight", 0)), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).outE().is(MQ_STEP).barrier(defaultBarrierSize).filter(__.inE("knows").has("weight", 0)), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).outE().is(MQ_STEP).is(NO_OP_B_V_STEP).filter(__.inE("knows").has("weight", 0)), otherStrategies), // An additional JanusGraphMultiQueryStep for repeat goes before the RepeatEndStep allowing it to feed its starts to the next iteration arguments(g.V().outE("knows").inV().repeat(__.outE("knows").inV().has("weight", 0)).times(10), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).outE("knows").inV().is(MQ_STEP).barrier(defaultBarrierSize).repeat(__.outE("knows").inV().is(MQ_STEP).barrier(defaultBarrierSize).has("weight", 0).is(MQ_STEP).barrier(defaultBarrierSize)).times(10), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).outE("knows").inV().is(MQ_STEP).is(NO_OP_B_V_STEP).repeat(__.outE("knows").inV().is(MQ_STEP).is(NO_OP_B_V_STEP).has("weight", 0).is(MQ_STEP).is(NO_OP_B_V_STEP)).times(10), otherStrategies), // Choose does not have a child traversal of JanusGraphVertexStep so won't benefit from JanusGraphMultiQueryStep(ChooseStep) arguments(g.V().choose(has("weight", lt(3)), __.union(__.inE("knows").has("weight", 0),__.inE("knows").has("weight", 1))), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).choose(has("weight", lt(3)), __.union(__.inE("knows").has("weight", 0),__.inE("knows").has("weight", 1))), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).choose(has("weight", lt(3)), __.union(__.inE("knows").has("weight", 0),__.inE("knows").has("weight", 1))), otherStrategies), // Choose now has a child traversal of JanusGraphVertexStep and so will benefit from JanusGraphMultiQueryStep(ChooseStep) arguments(g.V().choose(__.union(__.inE("knows").has("weight", 0),__.inE("knows").has("weight", 1)),__.inE("knows").has("weight", gt(2))), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).choose(__.union(__.inE("knows").has("weight", 0),__.inE("knows").has("weight", 1)),__.inE("knows").has("weight", gt(2))), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).choose(__.union(__.inE("knows").has("weight", 0),__.inE("knows").has("weight", 1)),__.inE("knows").has("weight", gt(2))), otherStrategies), // There are 'as' side effect steps preceding the JanusGraphVertexStep arguments(g.V().choose(has("weight", 0),__.as("true").inE("knows"),__.as("false").inE("knows")), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).choose(has("weight", 0),__.as("true").inE("knows"),__.as("false").inE("knows")), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).choose(has("weight", 0),__.as("true").inE("knows"),__.as("false").inE("knows")), otherStrategies), // There are 'sideEffect' and 'as' steps preceding the JanusGraphVertexStep arguments(g.V().choose(has("weight", 0),__.as("true").sideEffect(i -> {}).inE("knows"),__.as("false").sideEffect(i -> {}).inE("knows")), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).choose(has("weight", 0),__.as("true").sideEffect(i -> {}).inE("knows"),__.as("false").sideEffect(i -> {}).inE("knows")), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).choose(has("weight", 0),__.as("true").sideEffect(i -> {}).inE("knows"),__.as("false").sideEffect(i -> {}).inE("knows")), otherStrategies), // Only the most outer eligible `JanusGraphMultiQueryStep` should be used for MultiQueryCompatible start steps arguments(g.V().and(__.inE("knows"), __.outE("knows")), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).and(__.inE("knows"), __.outE("knows")), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).and(__.inE("knows"), __.outE("knows")), otherStrategies), // `JanusGraphMultiQueryStep` should be used for filter step when at least one child is registered as a client of `JanusGraphMultiQueryStep`. arguments(g.V().where(__.out("knows").count().is(P.gte(5))), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).where(__.out("knows").count().is(P.gte(5))), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).where(__.out("knows").count().is(P.gte(5))), otherStrategies), // `JanusGraphMultiQueryStep` should not be used for filter step when none of children is registered as a client of `JanusGraphMultiQueryStep`. arguments(g.V().where(__.count().is(P.gte(5))), g_V().where(__.count().is(P.gte(5))), otherStrategies), // Should include barrier steps with the default configured size by `LIMITED_BATCH_SIZE` option arguments(g.V().out().repeat(__.out()).emit(), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).out().is(MQ_STEP).barrier(defaultBarrierSize).repeat(__.out().is(MQ_STEP).barrier(defaultBarrierSize)).emit(), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).out().is(MQ_STEP).is(NO_OP_B_V_STEP).repeat(__.out().is(MQ_STEP).is(NO_OP_B_V_STEP)).emit(), otherStrategies), // Should not use `JanusGraphMultiQueryStep` at the beginning of repeat child traversals when `emit` is used. arguments(g.V().out().emit().repeat(__.out()), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).out().is(MQ_STEP).barrier(defaultBarrierSize).emit().repeat(__.out().is(MQ_STEP).barrier(defaultBarrierSize)), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).out().is(MQ_STEP).is(NO_OP_B_V_STEP).emit().repeat(__.out().is(MQ_STEP).is(NO_OP_B_V_STEP)), otherStrategies), // Should not use `JanusGraphMultiQueryStep` at the beginning of repeat child traversals when non-true `emit` is used after `repeat`. arguments(g.V().out().repeat(__.out()).emit(__.in("knows")), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).out().is(MQ_STEP).barrier(defaultBarrierSize).repeat(__.out().is(MQ_STEP).barrier(defaultBarrierSize)).emit( __.in("knows")), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).out().is(MQ_STEP).is(NO_OP_B_V_STEP).repeat(__.out().is(MQ_STEP).is(NO_OP_B_V_STEP)).emit( __.in("knows")), otherStrategies), // Should not use `JanusGraphMultiQueryStep` at the beginning of repeat child traversals when non-true `emit` is used before `repeat`. arguments(g.V().out().emit(__.in("knows")).repeat(__.out()), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).out().is(MQ_STEP).barrier(defaultBarrierSize).emit( __.in("knows")).repeat(__.out().is(MQ_STEP).barrier(defaultBarrierSize)), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).out().is(MQ_STEP).is(NO_OP_B_V_STEP).emit( __.in("knows")).repeat(__.out().is(MQ_STEP).is(NO_OP_B_V_STEP)), otherStrategies), // Should not use `JanusGraphMultiQueryStep` at the beginning of repeat child traversals when `until` is used after `repeat`. arguments(g.V().out().repeat(__.out()).until(__.in("knows").count().is(P.gte(5))), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).out().is(MQ_STEP).barrier(defaultBarrierSize).repeat(__.out().is(MQ_STEP).barrier(defaultBarrierSize)).until(__.in("knows").count().is(P.gte(5))), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).out().is(MQ_STEP).is(NO_OP_B_V_STEP).repeat(__.out().is(MQ_STEP).is(NO_OP_B_V_STEP)).until(__.in("knows").count().is(P.gte(5))), otherStrategies), // Should not use `JanusGraphMultiQueryStep` at the beginning of repeat child traversals when `until` is used before `repeat`. arguments(g.V().out().until(__.in("knows").count().is(P.gte(5))).repeat(__.out()), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).out().is(MQ_STEP).barrier(defaultBarrierSize).until(__.in("knows").count().is(P.gte(5))).repeat(__.out().is(MQ_STEP).barrier(defaultBarrierSize)), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).out().is(MQ_STEP).is(NO_OP_B_V_STEP).until(__.in("knows").count().is(P.gte(5))).repeat(__.out().is(MQ_STEP).is(NO_OP_B_V_STEP)), otherStrategies), // Should not use `JanusGraphMultiQueryStep` at the beginning of repeat child traversals when `emit` is used before `repeat` and `until` is used after `repeat`. arguments(g.V().out().emit(__.in("knows")).repeat(__.out()).until(__.in("knows").count().is(P.gte(5))), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).out().is(MQ_STEP).barrier(defaultBarrierSize).emit(__.in("knows")).repeat(__.out().is(MQ_STEP).barrier(defaultBarrierSize)).until(__.in("knows").count().is(P.gte(5))), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).out().is(MQ_STEP).is(NO_OP_B_V_STEP).emit(__.in("knows")).repeat(__.out().is(MQ_STEP).is(NO_OP_B_V_STEP)).until(__.in("knows").count().is(P.gte(5))), otherStrategies), // Should not use `JanusGraphMultiQueryStep` at the repeat child traversals when `emit` is used after `repeat` and `until` is used after `repeat`. arguments(g.V().out().repeat(__.out()).emit(__.in("knows")).until(__.in("knows").count().is(P.gte(5))), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).out().is(MQ_STEP).barrier(defaultBarrierSize).repeat(__.out().is(MQ_STEP).barrier(defaultBarrierSize)).emit(__.in("knows")).until(__.in("knows").count().is(P.gte(5))), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).out().is(MQ_STEP).is(NO_OP_B_V_STEP).repeat(__.out().is(MQ_STEP).is(NO_OP_B_V_STEP)).emit(__.in("knows")).until(__.in("knows").count().is(P.gte(5))), otherStrategies), // Should not use `JanusGraphMultiQueryStep` at the beginning of repeat child traversals when `emit` is used after `repeat` and `until` is used before `repeat`. arguments(g.V().out().until(__.in("knows").count().is(P.gte(5))).repeat(__.out()).emit(__.in("knows")), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).out().is(MQ_STEP).barrier(defaultBarrierSize).until(__.in("knows").count().is(P.gte(5))).repeat(__.out().is(MQ_STEP).barrier(defaultBarrierSize)).emit(__.in("knows")), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).out().is(MQ_STEP).is(NO_OP_B_V_STEP).until(__.in("knows").count().is(P.gte(5))).repeat(__.out().is(MQ_STEP).is(NO_OP_B_V_STEP)).emit(__.in("knows")), otherStrategies), // Should not use `JanusGraphMultiQueryStep` at the repeat child traversals when `emit` is used before `repeat` and `until` is used before `repeat`. arguments(g.V().out().until(__.in("knows").count().is(P.gte(5))).emit(__.in("knows")).repeat(__.out()), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).out().is(MQ_STEP).barrier(defaultBarrierSize).until(__.in("knows").count().is(P.gte(5))).emit(__.in("knows")).repeat(__.out().is(MQ_STEP).barrier(defaultBarrierSize)), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).out().is(MQ_STEP).is(NO_OP_B_V_STEP).until(__.in("knows").count().is(P.gte(5))).emit(__.in("knows")).repeat(__.out().is(MQ_STEP).is(NO_OP_B_V_STEP)), otherStrategies), // Should not use `JanusGraphMultiQueryStep` at the beginning of repeat child traversals, but should use it for any other steps after the fist step. arguments(g.V().out().until(__.in("knows").in("knows").count().is(P.gte(5))).repeat(__.out().out()).emit(__.in("knows").in("knows")), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).out().is(MQ_STEP).barrier(defaultBarrierSize).until(__.in("knows").is(MQ_STEP).barrier(defaultBarrierSize).in("knows").count().is(P.gte(5))).repeat(__.out().is(MQ_STEP).barrier(defaultBarrierSize).out().is(MQ_STEP).barrier(defaultBarrierSize)).emit(__.in("knows").is(MQ_STEP).barrier(defaultBarrierSize).in("knows")), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).out().is(MQ_STEP).is(NO_OP_B_V_STEP).until(__.in("knows").is(MQ_STEP).is(NO_OP_B_V_STEP).in("knows").count().is(P.gte(5))).repeat(__.out().is(MQ_STEP).is(NO_OP_B_V_STEP).out().is(MQ_STEP).is(NO_OP_B_V_STEP)).emit(__.in("knows").is(MQ_STEP).is(NO_OP_B_V_STEP).in("knows")), otherStrategies), // Should not use `JanusGraphMultiQueryStep` at the end of repeat child traversal and before repeat step if none of repeat child starts are MultiQueriable steps arguments(g.V().out().until(__.map(Traverser::get).in("knows").count().is(P.gte(5))).repeat(__.map(Traverser::get).out()).emit(__.map(Traverser::get).in("knows")), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).out().until(__.map(Traverser::get).is(MQ_STEP).barrier(defaultBarrierSize).in("knows").count().is(P.gte(5))).repeat(__.map(Traverser::get).is(MQ_STEP).barrier(defaultBarrierSize).out()).emit(__.map(Traverser::get).is(MQ_STEP).barrier(defaultBarrierSize).in("knows")), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).out().until(__.map(Traverser::get).is(MQ_STEP).is(NO_OP_B_V_STEP).in("knows").count().is(P.gte(5))).repeat(__.map(Traverser::get).is(MQ_STEP).is(NO_OP_B_V_STEP).out()).emit(__.map(Traverser::get).is(MQ_STEP).is(NO_OP_B_V_STEP).in("knows")), otherStrategies), // Needs one JanusGraphMultiQueryStep before executing `and` step with `MultiQueriable` steps arguments(g.V().and(__.inE("knows"), __.inE("knows")), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).and(__.inE("knows"), __.inE("knows")), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).and(__.inE("knows"), __.inE("knows")), otherStrategies), // Needs one JanusGraphMultiQueryStep before executing `or` step with `MultiQueriable` steps arguments(g.V().or(__.inE("knows"), __.inE("knows")), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).or(__.inE("knows"), __.inE("knows")), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).or(__.inE("knows"), __.inE("knows")), otherStrategies), // Should use start of the last outer parent step after the first repeat step as JanusGraphMultiQueryStep. arguments(g.V().union(__.repeat(__.out("knows")).emit()), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).union(__.repeat(__.out("knows").is(MQ_STEP).barrier(defaultBarrierSize)).emit()), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).union(__.repeat(__.out("knows").is(MQ_STEP).is(NO_OP_B_V_STEP)).emit()), otherStrategies), // Repeat step mode: CLOSEST_REPEAT_PARENT. Should use start of the closest outer parent step after the first repeat step as JanusGraphMultiQueryStep, but not the last outer start step of the most outer repeat step. arguments(gRepeatClosestParent.V().repeat(__.union(__.repeat(__.out("knows")).emit())).emit(), - ((GraphTraversal ) g_V()).repeat(__.is(MQ_STEP).barrier(defaultBarrierSize).union(__.repeat(__.out("knows").is(MQ_STEP).barrier(defaultBarrierSize)).emit())).emit(), otherStrategies), + ((GraphTraversal ) g_V()).repeat(__.is(MQ_STEP).is(NO_OP_B_V_STEP).union(__.repeat(__.out("knows").is(MQ_STEP).is(NO_OP_B_V_STEP)).emit())).emit(), otherStrategies), // Repeat step mode: ALL_REPEAT_PARENTS. Should use starts and ends of all parent repeat steps as JanusGraphMultiQueryStep arguments(gRepeatAllParents.V().repeat(__.union(__.repeat(__.out("knows")).emit())).emit(), - ((GraphTraversal ) g_V()).is(MQ_STEP).barrier(defaultBarrierSize).repeat(__.is(MQ_STEP).barrier(defaultBarrierSize).union(__.repeat(__.out("knows").is(MQ_STEP).barrier(defaultBarrierSize)).emit()).is(MQ_STEP).barrier(defaultBarrierSize)).emit(), otherStrategies), + ((GraphTraversal ) g_V()).is(MQ_STEP).is(NO_OP_B_V_STEP).repeat(__.is(MQ_STEP).is(NO_OP_B_V_STEP).union(__.repeat(__.out("knows").is(MQ_STEP).is(NO_OP_B_V_STEP)).emit()).is(MQ_STEP).is(NO_OP_B_V_STEP)).emit(), otherStrategies), // Repeat step mode: STARTS_ONLY_OF_ALL_REPEAT_PARENTS. Should use starts of all parent repeat steps as JanusGraphMultiQueryStep arguments(gRepeatStartsOnlyOfAllParents.V().repeat(__.union(__.repeat(__.out("knows")).emit())).emit(), - ((GraphTraversal ) g_V()).is(MQ_STEP).barrier(defaultBarrierSize).repeat(__.is(MQ_STEP).barrier(defaultBarrierSize).union(__.repeat(__.out("knows").is(MQ_STEP).barrier(defaultBarrierSize)).emit())).emit(), otherStrategies), + ((GraphTraversal ) g_V()).is(MQ_STEP).is(NO_OP_B_V_STEP).repeat(__.is(MQ_STEP).is(NO_OP_B_V_STEP).union(__.repeat(__.out("knows").is(MQ_STEP).is(NO_OP_B_V_STEP)).emit())).emit(), otherStrategies), // Need `JanusGraphMultiQuerySteps` before `has` step (we use `map` step here just to not fold has step containers into JanusGraphStep arguments(g.V().map(Traverser::get).has("weight", 0), - g_V().map(Traverser::get).is(MQ_STEP).barrier(defaultBarrierSize).has("weight", 0), otherStrategies), + g_V().map(Traverser::get).is(MQ_STEP).is(NO_OP_B_V_STEP).has("weight", 0), otherStrategies), // Need `JanusGraphMultiQuerySteps` before `has` step which is used after other steps arguments(g.V().out().has("weight", 0), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).out().is(MQ_STEP).barrier(defaultBarrierSize).has("weight", 0), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).out().is(MQ_STEP).is(NO_OP_B_V_STEP).has("weight", 0), otherStrategies), // Need `JanusGraphMultiQuerySteps` before `valueMap` step which is used after other steps arguments(g.V().valueMap("weight"), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).valueMap("weight"), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).valueMap("weight"), otherStrategies), // Need `JanusGraphMultiQuerySteps` before `propertyMap` step which is used after other steps arguments(g.V().propertyMap("weight"), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).propertyMap("weight"), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).propertyMap("weight"), otherStrategies), // Need `JanusGraphMultiQuerySteps` before `elementMap` step which is used after other steps arguments(g.V().elementMap("weight"), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).elementMap("weight"), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).elementMap("weight"), otherStrategies), // Need `JanusGraphMultiQuerySteps` before `values` step which is used after other steps arguments(g.V().values("weight"), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).values("weight"), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).values("weight"), otherStrategies), // Need `JanusGraphMultiQuerySteps` before `properties` step which is used after other steps arguments(g.V().properties("weight"), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).properties("weight"), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).properties("weight"), otherStrategies), // Need `JanusGraphLabelStep` to use instead of `LabelStep` arguments(g.V().label(), - g_V().is(MQ_STEP).barrier(defaultBarrierSize).label(), otherStrategies), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).label(), otherStrategies), + // Need `JanusGraphDropStep` to use instead of `DropStep` + arguments(g.V().drop(), + g_V().is(MQ_STEP).is(NO_OP_B_V_STEP).drop(), otherStrategies), }); } }