[ https://issues.apache.org/jira/browse/TINKERPOP-2940?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Cole Greer updated TINKERPOP-2940: ---------------------------------- Description: The current implementation of [ternary boolean logic|https://tinkerpop.apache.org/docs/3.6.2/dev/provider/#_ternary_boolean_logics] in TinkerPop leads to inconsistent and unexpected behavior depending on strategy application. This stems from the binary reduction logic implemented [here|https://github.com/Bit-Quill/tinkerpop/blob/d653b2401271ff9eb8e2249f878344c27ac81418/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/FilterStep.java#L44]. `TraversalFilterStep` and `WhereStep` are currently special cases which will trigger early reduction of boolean error states to false. The issue is that some strategies such as `InlineFilterStrategy` will sometimes remove such steps to produce optimized traversals which are almost equivalent, but don't have this early reduction behavior. Here is a simple example of this in TinkerGraph 3.6.2: {code:bash} gremlin> g.withoutStrategies(InlineFilterStrategy).inject(1).not(where(is(lt(NaN)))) ==>1 gremlin> g.withoutStrategies(InlineFilterStrategy).inject(1).not(where(is(lt(NaN)))).explain() ==>Traversal Explanation ========================================================================================================== Original Traversal [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] ConnectiveStrategy [D] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] CountStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] IdentityRemovalStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] EarlyLimitStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] MatchPredicateStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] IncidentToAdjacentStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] AdjacentToIncidentStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] FilterRankingStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] ByModulatorOptimizationStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] RepeatUnrollStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] PathRetractionStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] LazyBarrierStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] TinkerGraphCountStrategy [P] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] TinkerGraphStepStrategy [P] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] ProfileStrategy [F] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] StandardVerificationStrategy [V] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] Final Traversal [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] gremlin> g.inject(1).not(where(is(lt(NaN)))) gremlin> g.inject(1).not(where(is(lt(NaN)))).explain() ==>Traversal Explanation ========================================================================================================== Original Traversal [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] ConnectiveStrategy [D] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] CountStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] IdentityRemovalStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] EarlyLimitStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] MatchPredicateStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] FilterRankingStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] InlineFilterStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] IncidentToAdjacentStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] AdjacentToIncidentStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] ByModulatorOptimizationStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] RepeatUnrollStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] PathRetractionStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] LazyBarrierStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] TinkerGraphCountStrategy [P] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] TinkerGraphStepStrategy [P] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] ProfileStrategy [F] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] StandardVerificationStrategy [V] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] Final Traversal [InjectStep([1]), NotStep([IsStep(lt(NaN))])] {code} In the first case, the final traversal contains `[InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])]`. In this example, the `error` from the `IsStep` get's reduced early to `false` by the `TraversalFilterStep`. Therefore it is evaluated to `not(false)` which is `true`. In the second case, the `TraversalFilterStep` is removed by the `InlineFilterStrategy` which leads to a final traversal of `[InjectStep([1]), NotStep([IsStep(lt(NaN))])]`. In this case there is no early reduction step, so it evaluates to `not(error)`, which produces the result `error`, which is then reduced to `false`. The interaction between the strategies and the early reduction behavior of the where step can lead to very unpredictable results. For example, here is a query which I would expect to behave in the same manner as the second traversal from above. {code:bash} gremlin> g.addV().property("test", 1) ==>v[2] gremlin> g.V().not(where(values('test').is(lt(NaN)))) ==>v[2] gremlin> g.V().not(where(values('test').is(lt(NaN)))).explain() ==>Traversal Explanation =================================================================================================================================================== Original Traversal [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] ConnectiveStrategy [D] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] CountStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] IdentityRemovalStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] EarlyLimitStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] MatchPredicateStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] FilterRankingStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] InlineFilterStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] IncidentToAdjacentStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] AdjacentToIncidentStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] ByModulatorOptimizationStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] RepeatUnrollStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] PathRetractionStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] LazyBarrierStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] TinkerGraphCountStrategy [P] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] TinkerGraphStepStrategy [P] [TinkerGraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] ProfileStrategy [F] [TinkerGraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] StandardVerificationStrategy [V] [TinkerGraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] Final Traversal [TinkerGraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] {code} This is essentially the same traversal as above, but in this case the TraversalFilterStep is preserved, leading to the early reduction of the `error`. was: The current implementation of [ternary boolean logic|https://tinkerpop.apache.org/docs/3.6.2/dev/provider/#_ternary_boolean_logics] in TinkerPop leads to inconsistent and unexpected behavior depending on strategy application. This stems from the binary reduction logic implemented [here|https://github.com/Bit-Quill/tinkerpop/blob/d653b2401271ff9eb8e2249f878344c27ac81418/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/FilterStep.java#L44]. `TraversalFilterStep` and `WhereStep` are currently special cases which will trigger early reduction of boolean error states to false. The issue is that some strategies such as `InlineFilterStrategy` will sometimes remove such steps to produce optimized traversals which are almost equivalent, but don't have this early reduction behavior. Here is a simple example of this in TinkerGraph 3.6.2: {code:bash} gremlin> g.withoutStrategies(InlineFilterStrategy).inject(1).not(where(is(lt(NaN)))) ==>1 gremlin> g.withoutStrategies(InlineFilterStrategy).inject(1).not(where(is(lt(NaN)))).explain() ==>Traversal Explanation ========================================================================================================== Original Traversal [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] ConnectiveStrategy [D] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] CountStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] IdentityRemovalStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] EarlyLimitStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] MatchPredicateStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] IncidentToAdjacentStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] AdjacentToIncidentStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] FilterRankingStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] ByModulatorOptimizationStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] RepeatUnrollStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] PathRetractionStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] LazyBarrierStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] TinkerGraphCountStrategy [P] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] TinkerGraphStepStrategy [P] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] ProfileStrategy [F] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] StandardVerificationStrategy [V] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] Final Traversal [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] gremlin> g.inject(1).not(where(is(lt(NaN)))) gremlin> g.inject(1).not(where(is(lt(NaN)))).explain() ==>Traversal Explanation ========================================================================================================== Original Traversal [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] ConnectiveStrategy [D] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] CountStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] IdentityRemovalStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] EarlyLimitStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] MatchPredicateStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] FilterRankingStrategy [O] [InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] InlineFilterStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] IncidentToAdjacentStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] AdjacentToIncidentStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] ByModulatorOptimizationStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] RepeatUnrollStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] PathRetractionStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] LazyBarrierStrategy [O] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] TinkerGraphCountStrategy [P] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] TinkerGraphStepStrategy [P] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] ProfileStrategy [F] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] StandardVerificationStrategy [V] [InjectStep([1]), NotStep([IsStep(lt(NaN))])] Final Traversal [InjectStep([1]), NotStep([IsStep(lt(NaN))])] {code} In the first case, the final traversal contains `[InjectStep([1]), NotStep([TraversalFilterStep([IsStep(lt(NaN))])])]`. In this example, the `error` from the `IsStep` get's reduced early to `false` by the `TraversalFilterStep`. Therefore it is evaluated to `not(false)` which is `true`. In the second case, the `TraversalFilterStep` is removed by the `InlineFilterStrategy` which leads to a final traversal of `[InjectStep([1]), NotStep([IsStep(lt(NaN))])]`. In this case there is no early reduction step, so it evaluates to `not(error)`, which produces the result `error`, which is then reduced to `false`. The interaction between the strategies and the early reduction behavior of the where step lead to very unpredictable results. For example, here is a query which I would expect to behave in the same manner as the second traversal from above. {code:bash} gremlin> g.addV().property("test", 1) ==>v[2] gremlin> g.V().not(where(values('test').is(lt(NaN)))) ==>v[2] gremlin> g.V().not(where(values('test').is(lt(NaN)))).explain() ==>Traversal Explanation =================================================================================================================================================== Original Traversal [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] ConnectiveStrategy [D] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] CountStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] IdentityRemovalStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] EarlyLimitStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] MatchPredicateStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] FilterRankingStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] InlineFilterStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] IncidentToAdjacentStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] AdjacentToIncidentStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] ByModulatorOptimizationStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] RepeatUnrollStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] PathRetractionStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] LazyBarrierStrategy [O] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] TinkerGraphCountStrategy [P] [GraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] TinkerGraphStepStrategy [P] [TinkerGraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] ProfileStrategy [F] [TinkerGraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] StandardVerificationStrategy [V] [TinkerGraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] Final Traversal [TinkerGraphStep(vertex,[]), NotStep([TraversalFilterStep([PropertiesStep([test],value), IsStep(lt(NaN))])])] {code} This is essentially the same traversal as above, but in this case the TraversalFilterStep is preserved, leading to the early reduction of the `error`. > Strategy Dependent Behavior of Ternary Boolean Logic > ---------------------------------------------------- > > Key: TINKERPOP-2940 > URL: https://issues.apache.org/jira/browse/TINKERPOP-2940 > Project: TinkerPop > Issue Type: Improvement > Components: process > Affects Versions: 3.6.2 > Reporter: Cole Greer > Priority: Major > > The current implementation of [ternary boolean > logic|https://tinkerpop.apache.org/docs/3.6.2/dev/provider/#_ternary_boolean_logics] > in TinkerPop leads to inconsistent and unexpected behavior depending on > strategy application. This stems from the binary reduction logic implemented > [here|https://github.com/Bit-Quill/tinkerpop/blob/d653b2401271ff9eb8e2249f878344c27ac81418/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/FilterStep.java#L44]. > `TraversalFilterStep` and `WhereStep` are currently special cases which will > trigger early reduction of boolean error states to false. The issue is that > some strategies such as `InlineFilterStrategy` will sometimes remove such > steps to produce optimized traversals which are almost equivalent, but don't > have this early reduction behavior. > Here is a simple example of this in TinkerGraph 3.6.2: > {code:bash} > gremlin> > g.withoutStrategies(InlineFilterStrategy).inject(1).not(where(is(lt(NaN)))) > ==>1 > gremlin> > g.withoutStrategies(InlineFilterStrategy).inject(1).not(where(is(lt(NaN)))).explain() > ==>Traversal Explanation > ========================================================================================================== > Original Traversal [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > ConnectiveStrategy [D] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > CountStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > IdentityRemovalStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > EarlyLimitStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > MatchPredicateStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > IncidentToAdjacentStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > AdjacentToIncidentStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > FilterRankingStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > ByModulatorOptimizationStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > RepeatUnrollStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > PathRetractionStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > LazyBarrierStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > TinkerGraphCountStrategy [P] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > TinkerGraphStepStrategy [P] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > ProfileStrategy [F] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > StandardVerificationStrategy [V] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > Final Traversal [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > gremlin> g.inject(1).not(where(is(lt(NaN)))) > gremlin> g.inject(1).not(where(is(lt(NaN)))).explain() > ==>Traversal Explanation > ========================================================================================================== > Original Traversal [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > ConnectiveStrategy [D] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > CountStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > IdentityRemovalStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > EarlyLimitStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > MatchPredicateStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > FilterRankingStrategy [O] [InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])] > InlineFilterStrategy [O] [InjectStep([1]), > NotStep([IsStep(lt(NaN))])] > IncidentToAdjacentStrategy [O] [InjectStep([1]), > NotStep([IsStep(lt(NaN))])] > AdjacentToIncidentStrategy [O] [InjectStep([1]), > NotStep([IsStep(lt(NaN))])] > ByModulatorOptimizationStrategy [O] [InjectStep([1]), > NotStep([IsStep(lt(NaN))])] > RepeatUnrollStrategy [O] [InjectStep([1]), > NotStep([IsStep(lt(NaN))])] > PathRetractionStrategy [O] [InjectStep([1]), > NotStep([IsStep(lt(NaN))])] > LazyBarrierStrategy [O] [InjectStep([1]), > NotStep([IsStep(lt(NaN))])] > TinkerGraphCountStrategy [P] [InjectStep([1]), > NotStep([IsStep(lt(NaN))])] > TinkerGraphStepStrategy [P] [InjectStep([1]), > NotStep([IsStep(lt(NaN))])] > ProfileStrategy [F] [InjectStep([1]), > NotStep([IsStep(lt(NaN))])] > StandardVerificationStrategy [V] [InjectStep([1]), > NotStep([IsStep(lt(NaN))])] > Final Traversal [InjectStep([1]), > NotStep([IsStep(lt(NaN))])] > {code} > > In the first case, the final traversal contains `[InjectStep([1]), > NotStep([TraversalFilterStep([IsStep(lt(NaN))])])]`. In this example, the > `error` from the `IsStep` get's reduced early to `false` by the > `TraversalFilterStep`. Therefore it is evaluated to `not(false)` which is > `true`. > In the second case, the `TraversalFilterStep` is removed by the > `InlineFilterStrategy` which leads to a final traversal of `[InjectStep([1]), > NotStep([IsStep(lt(NaN))])]`. In this case there is no early reduction step, > so it evaluates to `not(error)`, which produces the result `error`, which is > then reduced to `false`. > The interaction between the strategies and the early reduction behavior of > the where step can lead to very unpredictable results. For example, here is a > query which I would expect to behave in the same manner as the second > traversal from above. > {code:bash} > gremlin> g.addV().property("test", 1) > ==>v[2] > gremlin> g.V().not(where(values('test').is(lt(NaN)))) > ==>v[2] > gremlin> g.V().not(where(values('test').is(lt(NaN)))).explain() > ==>Traversal Explanation > =================================================================================================================================================== > Original Traversal [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > ConnectiveStrategy [D] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > CountStrategy [O] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > IdentityRemovalStrategy [O] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > EarlyLimitStrategy [O] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > MatchPredicateStrategy [O] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > FilterRankingStrategy [O] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > InlineFilterStrategy [O] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > IncidentToAdjacentStrategy [O] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > AdjacentToIncidentStrategy [O] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > ByModulatorOptimizationStrategy [O] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > RepeatUnrollStrategy [O] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > PathRetractionStrategy [O] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > LazyBarrierStrategy [O] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > TinkerGraphCountStrategy [P] [GraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > TinkerGraphStepStrategy [P] [TinkerGraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > ProfileStrategy [F] [TinkerGraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > StandardVerificationStrategy [V] [TinkerGraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > Final Traversal [TinkerGraphStep(vertex,[]), > NotStep([TraversalFilterStep([PropertiesStep([test],value), > IsStep(lt(NaN))])])] > {code} > This is essentially the same traversal as above, but in this case the > TraversalFilterStep is preserved, leading to the early reduction of the > `error`. -- This message was sent by Atlassian Jira (v8.20.10#820010)