This is an automated email from the ASF dual-hosted git repository. spmallette pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit ceb0404b88f000be7232cd6f8096d67162b2f549 Merge: 1ac7e014a7 b75c29d797 Author: Stephen Mallette <[email protected]> AuthorDate: Wed Jul 29 15:08:51 2026 -0400 Merge branch '3.7-dev' into 3.8-dev bin/process-docs.sh | 64 ++- bin/publish-docs.sh | 32 ++ bin/validate-llms-txt.sh | 177 +++++++ docs/src/dev/developer/contributing.asciidoc | 4 + .../dev/developer/development-environment.asciidoc | 64 ++- docs/src/dev/developer/for-committers.asciidoc | 2 + docs/src/dev/developer/index.asciidoc | 1 + docs/src/dev/developer/meetings.asciidoc | 1 + docs/src/dev/developer/release.asciidoc | 1 + docs/src/dev/future/index.asciidoc | 1 + docs/src/dev/io/graphson.asciidoc | 6 + docs/src/dev/io/index.asciidoc | 1 + docs/src/dev/provider/gremlin-semantics.asciidoc | 33 ++ docs/src/dev/provider/index.asciidoc | 6 + docs/src/docinfo-footer.html | 19 + docs/src/recipes/between-vertices.asciidoc | 1 + docs/src/recipes/centrality.asciidoc | 1 + docs/src/recipes/collections.asciidoc | 1 + docs/src/recipes/connected-components.asciidoc | 1 + docs/src/recipes/cycle-detection.asciidoc | 1 + docs/src/recipes/duplicate-edge.asciidoc | 1 + docs/src/recipes/duplicate-vertex.asciidoc | 1 + docs/src/recipes/edge-move.asciidoc | 1 + docs/src/recipes/element-existence.asciidoc | 1 + docs/src/recipes/if-then-based-grouping.asciidoc | 1 + docs/src/recipes/index.asciidoc | 3 + docs/src/recipes/looping.asciidoc | 1 + docs/src/recipes/olap-spark-yarn.asciidoc | 1 + .../recipes/operating-on-dropped-elements.asciidoc | 1 + docs/src/recipes/pagination.asciidoc | 1 + docs/src/recipes/recommendation.asciidoc | 1 + docs/src/recipes/shortest-path.asciidoc | 1 + docs/src/recipes/traversal-induced-values.asciidoc | 1 + docs/src/recipes/tree.asciidoc | 1 + docs/src/reference/compilers.asciidoc | 1 + docs/src/reference/gremlin-applications.asciidoc | 6 + docs/src/reference/gremlin-variants.asciidoc | 7 + .../implementations-hadoop-start.asciidoc | 1 + docs/src/reference/implementations-intro.asciidoc | 1 + docs/src/reference/intro.asciidoc | 1 + docs/src/reference/preface.asciidoc | 1 + docs/src/reference/the-graph.asciidoc | 1 + docs/src/reference/the-graphcomputer.asciidoc | 1 + docs/src/reference/the-traversal.asciidoc | 130 +++++ docs/src/tutorials/getting-started/index.asciidoc | 1 + .../gremlin-language-variants/index.asciidoc | 3 + docs/src/tutorials/gremlins-anatomy/index.asciidoc | 1 + .../tutorials/the-gremlin-console/index.asciidoc | 1 + docs/src/upgrade/index.asciidoc | 1 + docs/src/upgrade/release-3.0.x-incubating.asciidoc | 1 + docs/src/upgrade/release-3.1.x-incubating.asciidoc | 1 + docs/src/upgrade/release-3.2.x-incubating.asciidoc | 3 + docs/src/upgrade/release-3.3.x.asciidoc | 2 + docs/src/upgrade/release-3.4.x.asciidoc | 2 + docs/src/upgrade/release-3.5.x.asciidoc | 3 + docs/src/upgrade/release-3.6.x.asciidoc | 1 + docs/src/upgrade/release-3.7.x.asciidoc | 2 + docs/tinkeradoc-extension/README.md | 14 + .../tinkeradoc/GremlinDocsConverterRegistry.java | 36 ++ .../tinkeradoc/GremlinExecutionCache.java | 94 ++++ .../tinkerpop/tinkeradoc/GremlinHighlighter.java | 117 +++++ .../tinkerpop/tinkeradoc/GremlinPostprocessor.java | 37 +- .../tinkerpop/tinkeradoc/GremlinTreeprocessor.java | 213 +++++---- .../tinkerpop/tinkeradoc/HtmlTabRenderer.java | 67 +++ .../tinkerpop/tinkeradoc/LlmsTxtGenerator.java | 288 ++++++++++++ .../tinkerpop/tinkeradoc/MarkdownConverter.java | 501 ++++++++++++++++++++ .../tinkerpop/tinkeradoc/MarkdownSplitter.java | 521 +++++++++++++++++++++ .../tinkerpop/tinkeradoc/MarkdownTabRenderer.java | 103 ++++ .../apache/tinkerpop/tinkeradoc/NeutralTab.java | 84 ++++ .../tinkerpop/tinkeradoc/NeutralTabCodec.java | 221 +++++++++ ...ciidoctor.jruby.converter.spi.ConverterRegistry | 1 + .../tinkeradoc/DualBackendIntegrationTest.java | 118 +++++ .../tinkeradoc/GremlinExecutionCacheTest.java | 124 +++++ .../tinkeradoc/GremlinHighlighterTest.java | 72 +++ .../tinkerpop/tinkeradoc/HtmlTabRendererTest.java | 104 ++++ .../tinkerpop/tinkeradoc/LlmsTxtGeneratorTest.java | 137 ++++++ .../tinkeradoc/MarkdownConverterProbeTest.java | 241 ++++++++++ .../tinkerpop/tinkeradoc/MarkdownSplitterTest.java | 227 +++++++++ .../tinkeradoc/MarkdownTabRendererTest.java | 113 +++++ .../tinkerpop/tinkeradoc/NeutralTabCodecTest.java | 113 +++++ .../tinkeradoc/PostprocessorBackendTest.java | 79 ++++ pom.xml | 275 +++++++++++ 82 files changed, 4385 insertions(+), 120 deletions(-) diff --cc docs/src/dev/provider/gremlin-semantics.asciidoc index 1fc85258a4,be010f1814..bced422437 --- a/docs/src/dev/provider/gremlin-semantics.asciidoc +++ b/docs/src/dev/provider/gremlin-semantics.asciidoc @@@ -509,84 -528,7 +511,85 @@@ fully demonstrative of Gremlin step sem step is meant to behave. This section discusses the semantics for individual steps to help users and providers understand implementation expectations. +[[adde-step]] +=== addE() + +*Description:* Adds an edge to the graph. + +*Syntax:* `addE(String edgeLabel)` | `addE(Traversal<?, String> edgeLabelTraversal)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|Y |Y |`from()`/`to()` |`any` |`Edge` +|========================================================= + +*Arguments:* + +* `edgeLabel` - The label of the edge to add. +* `edgeLabelTraversal` - A traversal that produces the label of the edge to add. + +*Modulation:* + +* `from()` - Specifies the source vertex for the edge. +* `to()` - Specifies the target vertex for the edge. + +*Considerations:* + +The `addE()` step can be used as both a start step and a mid-traversal step. When used as a start step, both `from()` +and `to()` must be specified. When used as a mid-traversal step, the current traverser becomes the source vertex and +only `to()` needs to be specified. + +The gremlin-lang grammar only permits `Traversal` and `String` (alias for `__.select(String)`) arguments in `from()` and +`to()`. The `Traversal` must either produce a `Vertex` which is attachable to the graph, or it must produce the id of an +existing `Vertex` in the graph. `GraphTraversal` implementations in GLVs may optionally support `from(Vertex)` and +`to(Vertex)` as syntactic sugar. If translating to gremlin-lang scripts, these sugared modulators must be converted to +`from(__.V(vertex.id()))` or `from(__.constant(vertex.id()))` (and equivalents for `to()`). + +*Exceptions* + +* If the edge label is null, an `IllegalArgumentException` will be thrown. + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java[source], +link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStartStep.java[source (start)], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#addedge-step[reference] + +[[addv-step]] +=== addV() + +*Description:* Adds a vertex to the graph. + +*Syntax:* `addV()` | `addV(String vertexLabel)` | `addV(Traversal<?, String> vertexLabelTraversal)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|Y |Y |N |`any` |`Vertex` +|========================================================= + +*Arguments:* + +* `vertexLabel` - The label of the vertex to add. +* `vertexLabelTraversal` - A traversal that produces the label of the vertex to add. + +*Modulation:* + +None + +*Considerations:* + +The `addV()` step can be used as both a start step and a mid-traversal step. If no label is provided, the default +vertex label for the graph will be used. + +*Exceptions* + +* If the vertex label is null, an `IllegalArgumentException` will be thrown. + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java[source], +link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStartStep.java[source (start)], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#addvertex-step[reference] + + [llms-summary="The formal semantics of the all() step: filters array data from the Traversal Stream if all of the array's items match the supplied predicate."] [[all-step]] === all() @@@ -620,72 -562,7 +623,73 @@@ will be filtered out of the Traversal S See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java[source], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#all-step[reference] +[[aggregate-step]] +=== aggregate() + +*Description:* Collects all objects in the traversal into a collection. + +*Syntax:* `aggregate(String sideEffectKey)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |`by()` |`any` |`any` +|========================================================= + +*Arguments:* + +* `sideEffectKey` - The name of the side-effect key that will hold the aggregated objects. + +*Modulation:* + +* `by()` - Determines how to transform the object before aggregating. If not specified, the object itself is used. + +*Considerations:* + +The `aggregate()` step is a side-effect step that collects objects but passes the traverser to the next step unchanged. +The aggregated objects can be accessed later using the `cap()` step. + +*Exceptions* + +None + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#aggregate-step[reference] + +[[and-step]] +=== and() + +*Description:* Ensures that all provided traversals yield a result. + +*Syntax:* `and(Traversal<?, ?>... andTraversals)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`any` |`any` +|========================================================= + +*Arguments:* + +* `andTraversals` - One or more traversals that will be executed against the current object. + +*Modulation:* + +None + +*Considerations:* + +The `and()` step is a filter step that allows the traverser to pass if all of the provided traversals yield a result. +It follows the ternary boolean logic described in the <<gremlin-semantics-concepts,Ternary Boolean Logics>> section. + +*Exceptions* + +None + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AndStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#and-step[reference] + + [llms-summary="The formal semantics of the any() step: filters array data from the Traversal Stream if any of the array's items match the supplied predicate."] [[any-step]] === any() @@@ -719,67 -596,7 +723,68 @@@ filtered out of the Traversal Stream See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AnyStep.java[source], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#any-step[reference] +[[as-step]] +=== as() + +*Description:* Labels a step for later access by steps that make use of such labels. + +*Syntax:* `as(String stepLabel, String... stepLabels)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`any` |`any` +|========================================================= + +*Arguments:* + +* `stepLabel` - The label to assign to the step. +* `stepLabels` - Additional labels to assign to the step. + +*Modulation:* + +None + +*Considerations:* + +The `as()` step is not a real step, but a "step modulator" similar to `by()` and `option()`. It allows labeling a step +for later access by steps like `select()` and `match()`. A step can have any number of labels associated with it, which +is useful for referencing the same step multiple times in a future step. + +*Exceptions* + +None + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#as-step[reference] + +[[asBool-step]] +=== asBool() + +*Description:* Parse the value of the incoming traverser as boolean. + +*Syntax:* `asBool()` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`Number`/`String`/`Boolean` |`Boolean` +|========================================================= + +*Arguments:* + +None + +Booleans are passed as is, numbers evaluate to `true` if non-zero, and `false` if zero or `NaN`. Strings only accept "true" or "false" (case-insensitive). + +*Exceptions* + +If the incoming traverser type is unsupported, a string other than "true" or "false", or `null`, then an `IllegalArgumentException` is thrown. + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsBoolStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asBool-step[reference] + + [llms-summary="The formal semantics of the asDate() step: parse the value of incoming traverser as date."] [[asDate-step]] === asDate() @@@ -793,238 -610,11 +798,239 @@@ |N |Y |N |`any` |`any` |========================================================= -*Arguments:* +*Arguments:* + +None + +Incoming date remains unchanged. + +*Exceptions* + +* If the incoming traverser is a non-String/Number/Date value then an `IllegalArgumentException` will be thrown. + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsDateStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asDate-step[reference] + +[[asNumber-step]] +=== asNumber() + +*Description:* converts the incoming traverser to the nearest parsable type if no argument is provided, or to the desired numerical type, based on the type token (`GType`) provided. + +*Syntax:* `asNumber()` | `asNumber(GType typeToken)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`Number`/`String`/`Date` |`Number` +|========================================================= + +*Arguments:* + +* `typeToken` - The enum `GType` to denote the desired type to parse/cast to. + +If no type token is provided, the incoming number remains unchanged. A `Date` input is converted to milliseconds since epoch. A `null` input passes through as `null`. + +*Exceptions* + +* If any overflow occurs during narrowing of types, then an `ArithmeticException` will be thrown. +* If the incoming string cannot be parsed into a valid number format, then a `NumberFormatException` will be thrown. +* If the incoming traverser is a non-String/Number/Date value then an `IllegalArgumentException` will be thrown. +* If the supplied type token is not a number type, then an `IllegalArgumentException` will be thrown. + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asNumber-step[reference] + ++[llms-summary="The formal semantics of the asString() step: returns the value of incoming traverser as strings, or if Scope.local is specified, returns each element inside incoming list traverser as string."] +[[asString-step]] +=== asString() + +*Description:* Returns the value of incoming traverser as strings, or if `Scope.local` is specified, returns each element inside +incoming list traverser as string. + +*Syntax:* `asString()` | `asString(Scope scope)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`any` |`String`/`List` +|========================================================= + +*Arguments:* + +* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers. +The `global` scope will operate on individual traverser, casting all (except `null`) to string. The `local` scope will behave like +`global` for everything except lists, where it will cast individual non-`null` elements inside the list into string and return a +list of string instead. + +*Exceptions* + +* If the incoming traverser is a `null` value then an `IllegalArgumentException` will be thrown. + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringGlobalStep.java[source], +link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringLocalStep.java[source (local)], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asString-step[reference] + +[[barrier-step]] +=== barrier() + +*Description:* Turns the lazy traversal pipeline into a bulk-synchronous pipeline. + +*Syntax:* `barrier()` | `barrier(int maxBarrierSize)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`any` |`any` +|========================================================= + +*Arguments:* + +* `maxBarrierSize` - The maximum number of traversers that can be held in the barrier before being processed. + +*Modulation:* + +None + +*Considerations:* + +The `barrier()` step is useful in the following situations: +* When everything prior to `barrier()` needs to be executed before moving onto the steps after the `barrier()` (i.e., ordering). +* When "stalling" the traversal may lead to a "bulking optimization" in traversals that repeatedly touch many of the +same elements (i.e., optimizing). + +*Exceptions* + +None + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/NoOpBarrierStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#barrier-step[reference] + +[[both-step]] +=== both() + +*Description:* Maps a vertex to its adjacent vertices given the edge labels. + +*Syntax:* `both(String... edgeLabels)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`Vertex` |`Vertex` +|========================================================= + +*Arguments:* + +* `edgeLabels` - The edge labels to traverse. If no labels are provided, all edges are traversed. + +*Modulation:* + +None + +*Considerations:* + +The `both()` step is a vertex-centric step that traverses both incoming and outgoing edges from the current vertex to +adjacent vertices. It is equivalent to the union of `in()` and `out()`. + +*Exceptions* + +None + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#vertex-steps[reference] + +[[bothe-step]] +=== bothE() + +*Description:* Maps a vertex to its incident edges given the edge labels. + +*Syntax:* `bothE(String... edgeLabels)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`Vertex` |`Edge` +|========================================================= + +*Arguments:* + +* `edgeLabels` - The edge labels to traverse. If no labels are provided, all edges are traversed. + +*Modulation:* + +None + +*Considerations:* + +The `bothE()` step is a vertex-centric step that traverses both incoming and outgoing edges from the current vertex. It +is equivalent to the union of `inE()` and `outE()`. + +*Exceptions* + +None + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#vertex-steps[reference] + +[[bothv-step]] +=== bothV() + +*Description:* Maps an edge to its incident vertices. + +*Syntax:* `bothV()` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`Edge` |`Vertex` +|========================================================= + +*Arguments:* + +None + +*Modulation:* + +None + +*Considerations:* + +The `bothV()` step is an edge-centric step that traverses to both the incoming and outgoing vertices of the current +edge. It is equivalent to the union of `inV()` and `outV()`. + +*Exceptions* + +None + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeVertexStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#vertex-steps[reference] + +[[branch-step]] +=== branch() + +*Description:* Splits the traverser to all the specified traversals. + +*Syntax:* `branch(Traversal<?, M> branchTraversal)` | `branch(Function<Traverser<E>, M> function)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |`option()` |`any` |`any` +|========================================================= + +*Arguments:* + +* `branchTraversal` - The traversal to branch the traverser to. +* `function` - The function to branch the traverser to. + +*Modulation:* -None +* `option()` - Specifies the branch options for the traverser. -Incoming date remains unchanged. +*Considerations:* + +The `branch()` step is a general step that splits the traverser to all the child traversals provided to it. It's the +basis for more robust steps like `choose()` and `union()`. The branch step is typically used with the `option()` step +to specify the branch options. *Exceptions* @@@ -1064,9 -651,11 +1070,10 @@@ provided key. If multiple keys are prov None -See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringGlobalStep.java[source], -link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringLocalStep.java[source (local)], -link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asString-step[reference] +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SideEffectCapStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#cap-step[reference] + [llms-summary="The formal semantics of the call() step: provides support for provider-specific service calls."] [[call-step]] === call() @@@ -1152,67 -741,7 +1159,68 @@@ link:https://github.com/apache/tinkerpo link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/service/ServiceRegistry.java[ServiceRegistry], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#call-step[reference] +[[choose-step]] +=== choose() + +*Description:* A branch step that routes the traverser to different paths based on a choice criterion. + +*Syntax:* `choose(Traversal|T choice)` | `choose(Traversal|P choice, Traversal trueChoice)` |`choose(Traversal|P choice, Traversal trueChoice, Traversal falseChoice)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |Y |`any` |`any` +|========================================================= + +*Arguments:* + +* `choice` - A `Traversal`, or `T` that produces a value used to determine which option to take. In the `if-then` forms, this value may be a `P` to determine `true` or `false`. +* `trueChoice` - The traversal to take if the predicate traversal returns a value (has a next element). +* `falseChoice` - The traversal to take if the predicate traversal returns no value (has no next element). + +*Modulation:* + +* `option(pickToken, traversalOption)` - Adds a traversal option to the `choose` step. The `pickToken` is matched +against the result of the choice traversal. The `pickToken` may be a literal value, a predicate `P` or a `Pick` enum +value. `Traversal` is not allowed as a `pickToken` here and will lead to `IllegalArgumentException`. If a match is +found, the traverser is routed to the corresponding `traversalOption`. + +*Considerations:* + +The `choose()` step is a branch step that routes the traverser to different paths based on a choice criterion. There are +two main forms of the `choose()` step: + +1. *if-then form*: `choose(predicate, trueChoice, falseChoice)` - If the predicate traversal or `P` returns a value +(has a next element), the traverser is routed to the trueChoice traversal. Otherwise, it is routed to the falseChoice +traversal. If the predicate is unproductive or if the falseChoice is not specified, then the traverser passes through. + +2. *switch form*: `choose(choice).option(pickValue, resultTraversal)` - The choice which may be a `Traversal` or +`T` produces a value that is matched against the pickValue of each option. If a match is found, the traverser is routed +to the corresponding resultTraversal and no further matches are attempted. If no match is found then the traverser +passes through by default or can be matched on `Pick.none`. If the choiceTraversal is unproductive, then the traverser +passes through by default or can be matched on `Pick.unproductive`. + +`choose` does not allow more than one traversal to be assigned to a single `Pick`. The first `Pick` assigned via +`option` is the one that will be used, similar to how the first pickValue match that is found is used. + +The `choose()` step ensures that only one option is selected for each traverser, unlike other branch steps like +`union()` that can route a traverser to multiple paths. As it is like `union()`, note that each `option` stream will +behave like one: + +[gremlin-groovy,modern] +---- +g.V().union(__.has("name", "vadas").values('age').fold(), __.has('name',neq('vadas')).values('name').fold()) +g.V().choose(__.has("name", "vadas"), __.values('age').fold(), __.values('name').fold()) +---- + +*Exceptions* + +* `IllegalArgumentException` - If `Pick.any` is used as an option token, as only one option per traverser is allowed. + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#choose-step[reference] + + [llms-summary="The formal semantics of the combine() step: its exact expected behavior when merging an incoming list with a supplied list argument."] [[combine-step]] === combine() @@@ -1249,39 -778,7 +1257,40 @@@ See: link:https://github.com/apache/tin link:https://tinkerpop.apache.org/docs/x.y.z/reference/#combine-step[reference], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#merge-step[merge() reference] +[[coin-step]] +=== coin() + +*Description:* Filters traversers from the Traversal Stream based on a biased coin toss. + +*Syntax:* `coin(double probability)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`any` |`any` +|========================================================= + +*Arguments:* + +* `probability` - The probability (between 0.0 and 1.0) that the traverser will pass through the filter. + +*Modulation:* + +None + +*Considerations:* + +Each traverser is subject to a random filter based on the provided probability. A probability of 0.0 means no +traversers pass through, while a probability of 1.0 means all traversers pass through. + +*Exceptions* + +None + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#coin-step[reference] + + [llms-summary="The formal semantics of the concat() step: concatenates the incoming String traverser with the input String arguments, and return the joined String."] [[concat-step]] === concat() @@@ -1557,86 -1061,7 +1573,87 @@@ Non See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/FormatStep.java[source], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#format-step[reference] +[[group-step]] +=== group() + +*Description:* Groups objects in the traversal stream by a key and applies a reducing operation to the grouped values. + +*Syntax:* `group()` | `group(String sideEffectKey)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |`by()` |`any` |`any` +|========================================================= + +*Arguments:* + +* `sideEffectKey` - The name of the side-effect key that will hold the aggregated grouping. When provided, the step +operates as a side-effect barrier step and passes the traverser to the next step unchanged. If `sideEffectKey` is +omitted, the step operates as a reducing barrier step, and a single traverser containing the computed map is passed to +the next step. + +*Modulation:* + +* `by()` - The first `by()` determines the key for grouping. The second `by()` determines the value to be reduced for +each group. If no key `by()` is provided, the object itself is used as the key. If no value `by()` is provided, the +objects are collected into a list. + +*Considerations:* + +The `group()` step can be used as both a reducing barrier step and a side-effect step. As a reducing barrier step (no +side-effect key), it returns a `Map<Object, Object>` where keys are the grouping criteria and values are the reduced +results. As a side-effect step, it stores the grouping in a side-effect and passes the traverser to the next step +unchanged. In both forms, this step is a barrier and must fully iterate the traversal before returning any results. + +*Exceptions* + +* If more than 2 `by()` modulators are provided, an `IllegalStateException` will be thrown. + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java[source], +link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java[source (sideEffect)], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#group-step[reference] + +[[groupcount-step]] +=== groupCount() + +*Description:* Counts the number of times a particular object has been part of a traversal, returning a `Map` where the +object is the key and the value is the count. + +*Syntax:* `groupCount()` | `groupCount(String sideEffectKey)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |`by()` |`any` |`any` +|========================================================= + +*Arguments:* + +* `sideEffectKey` - The name of the side-effect key that will hold the aggregated grouping. When provided, the step +operates as a side-effect step and passes the traverser to the next step unchanged. + +*Modulation:* + +* `by()` - Determines how to transform the object before counting. If not specified, the object itself is used as the +key. + +*Considerations:* + +The `groupCount()` step can be used as both a map step and a side-effect step. As a map step, it returns a +`Map<Object, Long>` with the counted objects as keys and their counts as values. As a side-effect step, it stores the +counts in a side-effect and passes the traverser to the next step unchanged. Note that both the map and side-effect +forms of this step are barriers that must fully iterate the traversal before returning any results. + +*Exceptions* + +* If multiple `by()` modulators are provided, an `IllegalStateException` will be thrown. + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupCountStep.java[source], +link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupCountSideEffectStep.java[source (sideEffect)], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#groupcount-step[reference] + + [llms-summary="The formal semantics of the length() step: returns the length of the incoming string or list, if Scope.local is specified, returns the length of each string elements inside incoming list traverser."] [[length-step]] === length() @@@ -1667,36 -1092,7 +1684,37 @@@ See: link:https://github.com/apache/tin link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LengthLocalStep.java[source (local)], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#length-step[reference] +[[local-step]] +=== local() + +*Description:* Executes the provided traversal in an object-local manner. + +*Syntax:* `local(Traversal localTraversal)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`any` |`any` +|========================================================= + +*Arguments:* + +* `localTraversal` - The traversal that processes each single-object traverser individually. + +*Modulation:* + +None + +*Considerations:* + +The `local()` step enforces object-local execution. As a branching step with local children, it implements strict lazy +evaluation by passing a single traverser at a time to the local traversal (bulk of exactly one, if bulking is supported) +and resetting the traversal to clean state between executions. + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LocalStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#local-step[reference] + + [llms-summary="The formal semantics of the intersect() step: adds the intersection to the Traversal Stream."] [[intersect-step]] === intersect() @@@ -1978,40 -1379,7 +2001,41 @@@ resolve to a `Map` See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java[source], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#mergev-step[reference] +[[none-step]] +=== none() + +*Description:* Filters array data from the traversal stream if none of the array's items match the supplied predicate. + +*Syntax:* `none(P predicate)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`List`/`array`/`Iterable`/`Iterator` |`List`/`array`/`Iterable`/`Iterator` +|========================================================= + +*Arguments:* + +* `predicate` - The predicate used to test each value in the array data. + +*Modulation:* + +None + +*Considerations:* + +Each value will be tested using the supplied predicate. Empty lists always pass through and null/non-list traversers +will be filtered out of the traversal stream. + +*Exceptions* + +* A GremlinTypeErrorException will be thrown if one occurs and no other value evaluates to true. + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NoneStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#none-step[reference] + + + [llms-summary="The formal semantics of the product() step: adds the cartesian product to the Traversal Stream."] [[product-step]] === product() @@@ -2046,43 -1414,7 +2070,44 @@@ applies to list types which means that See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProductStep.java[source], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#product-step[reference] +[[project-step]] +=== project() + +*Description:* Projects the current object in the stream into a `Map` that is keyed by the provided labels. + +*Syntax:* `project(String projectKey, String... otherProjectKeys)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |`by()` |`any` |`Map<String, Object>` +|========================================================= + +*Arguments:* + +* `projectKey` - The first key to use in the resulting map. +* `otherProjectKeys` - Additional keys to use in the resulting map. + +*Modulation:* + +* `by()` - Determines how to transform the current object for each key in the resulting map. The number of `by()` +modulations should match the number of keys provided. + +*Considerations:* + +The `project()` step is similar to `select()` but instead of retrieving historic traverser state, it modulates the +current state of the traverser. Each key in the resulting map corresponds to a `by()` modulation in the order they are +provided. If a `by()` modulation doesn't produce a value for a particular key (not productive), that key will be omitted +from the resulting `Map`. + +*Exceptions* + +* If duplicate keys are provided, an `IllegalArgumentException` will be thrown. + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#project-step[reference] + + [llms-summary="The formal semantics of the repeat() step: iteratively applies a traversal (the \"loop body\") to each incoming traverser until a stopping condition is met."] [[repeat-step]] === repeat() @@@ -2280,40 -1613,7 +2309,41 @@@ See: link:https://github.com/apache/tin link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SplitLocalStep.java[source (local)], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#split-step[reference] +[[subgraph-step]] +=== subgraph() + +*Description:* Extracts an edge-induced subgraph from the current graph based on the edges encountered during traversal. + +*Syntax:* `subgraph(String sideEffectKey)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`Edge` |`Edge` +|========================================================= + +*Arguments:* + +* `sideEffectKey` - The name of the side-effect key that will hold the extracted subgraph. + +*Modulation:* + +None + +*Considerations:* + +The `subgraph()` step is a side-effect step that extracts edges encountered during traversal and their incident vertices +into a new subgraph. The step passes traversers through unchanged while building the subgraph as a side-effect. Subgraph +step is a barrier and must fully iterate the traversal before returning any results. + +*Exceptions* + +None + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphStep.java[source], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#subgraph-step[reference] + + [llms-summary="The formal semantics of the substring() step: its exact expected behavior extracting a portion of a string by index."] [[substring-step]] === substring() @@@ -2407,48 -1709,7 +2439,49 @@@ See: link:https://github.com/apache/tin link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ToUpperLocalStep.java[source (local)], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#toUpper-step[reference] +[[tree-step]] +=== tree() + +*Description:* Aggregates the paths of the traversal into a tree data structure. + +*Syntax:* `tree()` | `tree(String sideEffectKey)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |`by()` |`any` |`any` +|========================================================= + +*Arguments:* + +* `sideEffectKey` - The name of the side-effect key that will hold the aggregated tree. When provided, the step +operates as a side-effect step and passes the traverser to the next step unchanged. If omitted, the step acts as a +reducing barrier step, and a single traverser containing the aggregated tree is passed to the next step. + +*Modulation:* + +* `by()` - Determines how to transform path objects before adding them to the tree. If not specified, the objects +themselves are used as tree nodes. If multiple `by()` modulators are provided, they will be applied to each level of the +tree according to a round robin. For example, if 2 `by()` modulators are present, the first `by()` will apply to the +first, third, fifth... levels of the tree, and the second `by()` will apply to the second, fourth, sixth... levels of +the tree. An unlimited number of `by()` modulators may be provided. + +*Considerations:* + +The `tree()` step can be used as both a map step and a side-effect step. As a map step, it returns a `Tree` data +structure representing the hierarchical paths taken during traversal. As a side-effect step, it stores the tree in a +side-effect and passes the traverser to the next step unchanged. The tree structure reflects the branching paths of the +traversal, with each level representing a step in the path. + +*Exceptions* + +None + +See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TreeStep.java[source], +link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/TreeSideEffectStep.java[source (sideEffect)], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#tree-step[reference] + + [llms-summary="The formal semantics of the trim() step: returns a string with leading and trailing whitespace removed."] [[trim-step]] === trim() diff --cc docs/src/reference/the-traversal.asciidoc index 3980f119cb,01afa7cf3e..6b979c286d --- a/docs/src/reference/the-traversal.asciidoc +++ b/docs/src/reference/the-traversal.asciidoc @@@ -652,7 -668,9 +659,8 @@@ g.E().local(aggregate('x').by('weight') *Additional References* link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#aggregate(java.lang.String)++[`aggregate(String)`], -link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#aggregate(org.apache.tinkerpop.gremlin.process.traversal.Scope,java.lang.String)++[`aggregate(Scope,String)`] + [llms-summary="It is possible to filter list traversers using all()-step (filter)."] [[all-step]] === All Step @@@ -796,27 -818,7 +808,28 @@@ g.V().hasLabel('person').values('age'). link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asString()++[`asString()`] link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asString(org.apache.tinkerpop.gremlin.process.traversal.Scope)++[`asString(Scope)`] +[[asBool-step]] +=== AsBool Step + +The `asBool()`-step (*map*) converts the incoming traverser to a boolean value. If the traverser is already a boolean value, it is passed as-is. Numbers evaluate to +`true` if non-zero, and to `false` if zero or `NaN`. Strings are only accepted when +equal to `"true"` or `"false"` (case-insensitive), otherwise an `IllegalArgumentException` is thrown. +All other types (including `null`) will throw an `IllegalArgumentException`. + +[gremlin-groovy,modern] +---- +g.inject(1).asBool() <1> +g.inject("false").asBool() <2> +---- + +<1> Convert number to boolean +<2> Convert string to boolean + +*Additional References* + +link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asBool()++[`asBool()`] + + [llms-summary="The asDate()-step (map) converts string or numeric input to Date."] [[asDate-step]] === AsDate Step @@@ -844,42 -844,7 +857,43 @@@ g.inject(datetime("2023-08-24T00:00:00Z link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asDate()++[`asDate()`] +[[asNumber-step]] +=== AsNumber Step + +The `asNumber()`-step (*map*) converts the incoming traverser to the nearest parsable type if no argument is provided, +or to the desired numerical type, based on the type token (`GType`) provided. If a type token entered isn't a numerical type, an `IllegalArgumentException` will be thrown. + +Numerical input will pass through unless a type is specified by the number token. `ArithmeticException` will be thrown +for any overflow during narrowing of types. + +String inputs are parsed into numeric values, choosing the smallest type that can represent the value without loss of +precision. A whole number is parsed as an `Integer`, widening to `Long` or `BigInteger` if it is too large to fit. +A number with a decimal point is parsed as a `Float`, widening to `Double` or `BigDecimal` when higher precision is +required. A `NumberFormatException` will be thrown if the string cannot be parsed into a valid number format. + +Date inputs are converted to milliseconds since epoch (January 1, 1970, 00:00:00 GMT). + +A `null` input passes through as `null`. All other input types will result in `IllegalArgumentException`. + +[gremlin-groovy,modern] +---- +g.inject(1234).asNumber() <1> +g.inject(1.76d).asNumber() <2> +g.inject(1.76d).asNumber(GType.INT) <3> +g.inject("2023-08-02T00:00:00Z").asDate().asNumber() <4> +---- + +<1> An int will be passed through. +<2> A double will be passed through. +<3> A double is converted into an int. +<4> A date is converted into milliseconds since epoch. + +*Additional References* + +link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asNumber()++[`asNumber()`], +link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asNumber(org.apache.tinkerpop.gremlin.process.traversal.GType)++[`asNumber(GType)`] + + [llms-summary="The barrier()-step (barrier) turns the lazy traversal pipeline into a bulk-synchronous pipeline."] [[barrier-step]] === Barrier Step @@@ -1552,9 -1436,9 +1582,10 @@@ NOTE: The `dateDiff(Date)` method is de *Additional References* link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dateDiff(java.util.Date)++[`dateDiff(Date)`], +link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dateDiff(java.time.OffsetDateTime)++[`dateDiff(OffsetDateTime)`], link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dateDiff(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`dateDiff(Traversal)`] + [llms-summary="With dedup()-step (filter), repeatedly seen objects are removed from the traversal stream."] [[dedup-step]] === Dedup Step @@@ -1654,32 -1539,7 +1686,33 @@@ g.V().values("name").fold().difference( link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#difference(java.lang.Object)++[`difference(Object)`] link:++https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#difference-step++[`Semantics`] +[[discard-step]] +=== Discard Step + +The `discard()`-step (*filter*) filters all objects from a traversal stream. It is helpful with <<branch-step>> types +of steps where a particular branch of code should "throw away" traversers. In the following example, traversers that +don't match are filtered out of the traversal stream. + +[gremlin-groovy,modern] +---- +g.V().choose(T.label). + option("person", __.out("knows").values("name")). + option("bleep", __.out("created").values("name")). + option(none, discard()) +---- + +It is also useful for traversals that are executed remotely where returning results is not useful and the traversal is +only meant to generate side-effects. Choosing not to return results saves in serialization and network costs as the +objects are filtered on the remote end and not returned to the client side. Typically, this step does not need to be +used directly and is quietly used by the `iterate()` terminal step which appends `discard()` to the traversal before +actually cycling through results. + +*Additional References* + +link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/Traversal.html#discard()++[`discard()`] +link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/Traversal.html#iterate()++[`iterate()`] + + [llms-summary="The disjunct()-step (map) calculates the disjunct set between the incoming list traverser and the provided list argument."] [[disjunct-step]] === Disjunct Step @@@ -3411,11 -3328,11 +3484,12 @@@ g.V().values('age').fold().none(gt(25) *Additional References* -link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/Traversal.html#none()++[`none()`] -link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/Traversal.html#iterate()++[`iterate()`] +link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#none(org.apache.tinkerpop.gremlin.process.traversal.P)++[`none(P)`], +link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/P.html++[`P`] + [[not-step]] + [llms-summary="The not() step (filter) removes traversers for which the provided sub-traversal returns a result, negating a pattern."] === Not Step The `not()`-step (*filter*) removes objects from the traversal stream when the traversal provided as an argument @@@ -5474,55 -5414,7 +5598,56 @@@ location. Please see the <<io-step,docu link:++https://tinkerpop.apache.org/javadocs/x.y.z/full/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#write()++[`write()`] +[[traversal-parameterization]] +== Traversal Parameterization + +A subset of gremlin steps are able to accept parameterized arguments also known as GValues. GValues can be used to +provide protection against gremlin-injection attacks in cases where untrusted and unsanitized inputs must be passed as +step arguments. Additionally, use of GValues may offer performance benefits in certain environments by making use of +some query caching capabilities. Note that the reference implementation of the gremlin language and `gremlin-server` do +not have such a query caching mechanism, and thus will not see any performance improvements through parameterization. Users +should consult the documentation of their specific graph system details of potential performance benefits via parameterization. + +NOTE: There are unique considerations regarding parameters when using `gremlin-groovy` scripts. Groovy allows for parameterization +at arbitrary points in the query in addition to the subset of parameterizable steps documented here. Groovy is also bound by +a comparatively slow script compilation, which makes parameterization essential for performant execution of `gremlin-groovy` scripts. + +[cols="1,1"] +|=== +|Step | Parameterizable arguments + +|<<addedge-step,addE()>> | String edgeLabel +|<<addvertex-step,addV()>> | String vertexLabel +|<<vertex-steps,both()>> | String... edgeLabels +|<<vertex-steps,bothE()>> | String... edgeLabels +|<<call-step,call()>> | Map params +|<<from-step,from()>> | Vertex fromVertex +|<<has-step,has()>> | String label +|<<has-step,hasId()>> | Object id, Object... ids +|<<has-step,hasLabel()>> | String label, String... labels +|<<has-step,hasValue()>> | Object value, Object... values +|<<vertex-steps,in()>> | String... edgeLabels +|<<vertex-steps,inE()>> | String... edgeLabels +|<<is-step,is()>> | Object value +|<<limit-step,limit()>> | Long limit +|<<mergeedge-step,mergeE()>> | Map searchCreate +|<<mergevertex-step,mergeV()>> | Map searchCreate +|<<option-step,option()>> | Map m +|<<vertex-steps,out()>> | String... edgeLabels +|<<vertex-steps,outE()>> | String... edgeLabels +|<<property-step,property()>> | Object value, Object... values +|<<range-step,range()>> | Long low, Long high +|<<skip-step,skip()>> | Long limit +|<<tail-step,tail()>> | Long limit +|<<to-step,to()>> | String... edgeLabels, Vertex toVertex +|<<vertex-steps,toE()>> | String... edgeLabels +|=== + +*Additional References* + +<<gremlin-java-gvalue,Java>>, <<parameterized-scripts,Server>> + + [llms-summary="A note on predicates used in Gremlin traversals, including standard and text predicates."] [[a-note-on-predicates]] == A Note on Predicates @@@ -5602,69 -5496,7 +5727,70 @@@ g.V().as('a').both().both().as('b').cou g.V().as('a').both().both().as('b').where('a',neq('b')).count() ---- +[[a-note-on-types]] +== A Note on Types + +Gremlin steps typically operate over a handful of types that are mostly standard across graph systems. There are the +common numeric types like `Integer`, `Long`, `Double`, general types like `String`, and `Boolean`, container types like +`List`, `Set`, and `Map`, and structural types particular to graphs such as `Vertex`, `Edge`, and `Property`. During +traversal execution, it's common to encounter mixed data types, especially when extracting values from multiple +properties or when working with heterogeneous data that may have been stored inconsistently over time. + +Gremlin identifies these types in the `GType` enumeration, offering a clear presentation of the standard data types one +might typically encounter with Gremlin. This enumeration is an important part of the Gremlin language in that it acts +as the argument to the `typeOf()` predicate used for filtering values based on their runtime data type. + +[[gtype-enum]] +=== GType Enums + +`GType` consists of the following enumerations: + +* **Numeric types**: `INT`, `LONG`, `DOUBLE`, `FLOAT`, `BYTE`, `SHORT`, `BIGDECIMAL`, `BIGINT` +* **General types**: `STRING`, `BOOLEAN`, `CHAR`, `UUID`, `BINARY` +* **Collection types**: `LIST`, `SET`, `MAP` +* **Graph types**: `VERTEX`, `EDGE`, `PROPERTY`, `VPROPERTY`, `PATH`, `TREE`, `GRAPH` +* **Temporal types**: `DATETIME`, `DURATION` +* **Special types**: `NULL`, `NUMBER` (supertype for all numeric types) + +As mentioned, the `typeOf()` predicate becomes particularly useful when dealing with mixed data scenarios. For example, +you would like to only return the integer values of a set of properties for further processing: + +[gremlin-groovy,modern] +---- +g.V().values('age','name').is(P.typeOf(GType.INT)).asNumber(GType.SHORT) +---- + +The `NUMBER` type allows for broader type-based filtering without needing to specify each individual numeric type: + +[gremlin-groovy,modern] +---- +g.union(V(), E()).values().is(P.typeOf(GType.NUMBER)) +---- + +Type filtering is also valuable when working with traversals that return mixed graph elements. For example, when a +traversal might return both vertices and edges, you can add filter or condition based on the elements of interest: + +[gremlin-groovy,modern] +---- +g.V().outE().inV().path().unfold().is(P.typeOf(GType.EDGE)) +g.V().outE().inV().path().unfold().choose(typeOf(VERTEX), values('name'), values('weight')) +---- + +[[global-type-cache]] +=== GlobalTypeCache + +The `GlobalTypeCache` stores custom types registered by database providers as string-to-class mappings. These registered +type names can then be used with `P.typeOf()` for type filtering in the traversal. Consult your provider's documentation +for the correct type names when using provider-specific types. + +By default, `GType` enumerations are registered using their simple class names and can be used as shown below. + +[gremlin-groovy,modern] +---- +g.V().values('age','name').is(P.typeOf('Integer')) +---- + + [llms-summary="A note on maps in Gremlin, including differences in behavior between embedded and remote contexts."] [[a-note-on-maps]] == A Note on Maps
