Description
When using the ElementIdStrategy, if a traversal attempts to filter graph elements with multiple has steps and the id filter is not the first property to be filtered on, then the reference to the element's id is not replaced with the custom id property during the ElementIdStrategy's mutation of the traversal:
gremlin> graph = TinkerGraph.open() ==>tinkergraph[vertices:0 edges:0] gremlin> g = graph.traversal().withStrategies(ElementIdStrategy.build().create()) ==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard] gremlin> g.V().hasId("foo").has("name", "bar").explain() ==>Traversal Explanation =================================================================================================== Original Traversal [GraphStep(vertex,[]), HasStep([~id.eq(foo), name.eq(bar)])] ConnectiveStrategy [D] [GraphStep(vertex,[]), HasStep([~id.eq(foo), name.eq(bar)])] ElementIdStrategy [D] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] IdentityRemovalStrategy [O] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] MatchPredicateStrategy [O] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] FilterRankingStrategy [O] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] InlineFilterStrategy [O] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] IncidentToAdjacentStrategy [O] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] AdjacentToIncidentStrategy [O] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] EarlyLimitStrategy [O] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] ByModulatorOptimizationStrategy [O] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] RepeatUnrollStrategy [O] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] CountStrategy [O] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] PathRetractionStrategy [O] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] LazyBarrierStrategy [O] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] TinkerGraphCountStrategy [P] [GraphStep(vertex,[]), HasStep([__id.eq(foo), name.eq(bar)])] TinkerGraphStepStrategy [P] [TinkerGraphStep(vertex,[__id.eq(foo), name.eq(bar)])] TinkerMergeEVStepStrategy [P] [TinkerGraphStep(vertex,[__id.eq(foo), name.eq(bar)])] ProfileStrategy [F] [TinkerGraphStep(vertex,[__id.eq(foo), name.eq(bar)])] StandardVerificationStrategy [V] [TinkerGraphStep(vertex,[__id.eq(foo), name.eq(bar)])] Final Traversal [TinkerGraphStep(vertex,[__id.eq(foo), name.eq(bar)])] gremlin> g.V().has("name", "bar").hasId("foo").explain() ==>Traversal Explanation ================================================================================================== Original Traversal [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] ConnectiveStrategy [D] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] ElementIdStrategy [D] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] IdentityRemovalStrategy [O] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] MatchPredicateStrategy [O] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] FilterRankingStrategy [O] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] InlineFilterStrategy [O] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] IncidentToAdjacentStrategy [O] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] AdjacentToIncidentStrategy [O] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] EarlyLimitStrategy [O] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] ByModulatorOptimizationStrategy [O] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] RepeatUnrollStrategy [O] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] CountStrategy [O] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] PathRetractionStrategy [O] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] LazyBarrierStrategy [O] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] TinkerGraphCountStrategy [P] [GraphStep(vertex,[]), HasStep([name.eq(bar), ~id.eq(foo)])] TinkerGraphStepStrategy [P] [TinkerGraphStep(vertex,[foo],[name.eq(bar)])] TinkerMergeEVStepStrategy [P] [TinkerGraphStep(vertex,[foo],[name.eq(bar)])] ProfileStrategy [F] [TinkerGraphStep(vertex,[foo],[name.eq(bar)])] StandardVerificationStrategy [V] [TinkerGraphStep(vertex,[foo],[name.eq(bar)])] Final Traversal [TinkerGraphStep(vertex,[foo],[name.eq(bar)])]
In the above example, the first traversal shows the behavior when id filtering is done first, and the second traversal demonstrates the behavior when id filtering is not the first filtering step.
This was reproduced on both TinkerPop 3.6.1 and 3.4.0.
The current workaround is to ensure that when chaining has steps together that the first filter on id, if filtering on id is required.