This is an automated email from the ASF dual-hosted git repository.

colegreer pushed a commit to branch 3.8.0-GameDay-Snapshot
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 612c4c464ba1bd699abf82d4c58ab9b5a94d89b5
Author: Cole-Greer <[email protected]>
AuthorDate: Mon Oct 20 23:16:07 2025 -0700

    add docs for local() changes
---
 docs/src/dev/provider/gremlin-semantics.asciidoc | 34 ++++++++++++++++++++++++
 docs/src/reference/the-traversal.asciidoc        | 23 +++-------------
 docs/src/upgrade/release-3.8.x.asciidoc          | 28 +++++++++++++++++++
 3 files changed, 66 insertions(+), 19 deletions(-)

diff --git a/docs/src/dev/provider/gremlin-semantics.asciidoc 
b/docs/src/dev/provider/gremlin-semantics.asciidoc
index e36fa984c2..eeb331e61b 100644
--- a/docs/src/dev/provider/gremlin-semantics.asciidoc
+++ b/docs/src/dev/provider/gremlin-semantics.asciidoc
@@ -1589,6 +1589,40 @@ See: 
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/j
 
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.
+
+Under lazy evaluation, each traverser must complete its full journey through 
all steps in the local traversal before
+the next traverser begins processing. This creates a sequential, pull-based 
execution model where each step processes
+one traverser completely before requesting the next.
+
+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]
+
 [[intersect-step]]
 === intersect()
 
diff --git a/docs/src/reference/the-traversal.asciidoc 
b/docs/src/reference/the-traversal.asciidoc
index 1bbb336560..f136bdba4e 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -2557,30 +2557,15 @@ in an object-local traversal. As such, the 
`order().by()` and the `limit()` refe
 stream as a whole.
 
 Local Step is quite similar in functionality to <<general-steps,Flat Map 
Step>> where it can often be confused.
-`local()` propagates the traverser through the internal traversal as is 
without splitting/cloning it. Thus, its
-a “global traversal” with local processing. Its use is subtle and primarily 
finds application in compilation
-optimizations (i.e. when writing `TraversalStrategy` implementations. As 
another example consider:
+The primary distinction between these steps is that while `local()` preserves 
the path history of traversers as they
+pass through its child traversal, `flatMap()` does not. As another example 
consider:
 
 [gremlin-groovy,modern]
 ----
-g.V().both().barrier().flatMap(groupCount().by("name"))
-g.V().both().barrier().local(groupCount().by("name"))
+g.V().local(outE().inV()).path()
+g.V().flatMap(outE().inV()).path()
 ----
 
-Use of `local()` is often a mistake. This is especially true when its argument 
contains a reducing step. For example,
-let's say the requirement was to count the number of properties per `Vertex` 
in:
-
-[gremlin-groovy,modern]
-----
-g.V().both().local(properties('name','age').count())  <1>
-g.V().both().map(properties('name','age').count()) <2>
-----
-
-<1> The output here seems impossible because no single vertex in the "modern" 
graph can have more than two properties
-given the "name" and "age" filters, but because the counting is happening 
object-local the counting is occurring unique
-to each object rather than each global traverser.
-<2> Replacing `local()` with `map()` returns the result desired by the 
requirement.
-
 WARNING: The anonymous traversal of `local()` processes the current object 
"locally." In OLAP, where the atomic unit
 of computing is the vertex and its local "star graph," it is important that 
the anonymous traversal does not leave
 the confines of the vertex's star graph. In other words, it can not traverse 
to an adjacent vertex's properties or edges.
diff --git a/docs/src/upgrade/release-3.8.x.asciidoc 
b/docs/src/upgrade/release-3.8.x.asciidoc
index 9392434f50..8508b949f7 100644
--- a/docs/src/upgrade/release-3.8.x.asciidoc
+++ b/docs/src/upgrade/release-3.8.x.asciidoc
@@ -554,6 +554,34 @@ compatibility.
 
 See: link:https://issues.apache.org/jira/browse/TINKERPOP-3161[TINKERPOP-3161]
 
+==== Split bulked traversers for `local()`
+
+Prior to 3.8.0, the `local()` exhibited "traverser-local" semantics, where the 
local traversal would independently to
+each individual Traverser. This often led to confusion, especially in the 
presence of reducing barrier steps as the
+presence of bulked traversers would lead to multiple objects being processed 
at once. `local()` has been updated to
+automatically split any bulked traversers and thus now exhibits true 
"object-local" semantics.
+
+[source,groovy]
+----
+// 3.7.4
+gremlin> g.V().out().barrier().local(count())
+==>3
+==>1
+==>1
+==>1
+
+// 3.8.0
+gremlin> g.V().out().barrier().local(count())
+==>1
+==>1
+==>1
+==>1
+==>1
+==>1
+----
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-3196[TINKERPOP-3196]
+
 ==== Removal of P.getOriginalValue()
 
 `P.getOriginalValue()` has been removed as it was not offering much value and 
was often confused with `P.getValue()`.

Reply via email to