You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by co...@apache.org on 2026/07/17 22:13:24 UTC

(tinkerpop) branch master updated: Multilabel Docs Update (#3523)

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

Cole-Greer pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/master by this push:
     new fb262302b1 Multilabel Docs Update (#3523)
fb262302b1 is described below

commit fb262302b13bc98d8214d6eca0e3c542d935832f
Author: Yang Xia <55...@users.noreply.github.com>
AuthorDate: Fri Jul 17 15:13:18 2026 -0700

    Multilabel Docs Update (#3523)
    
    ---------
    
    Co-authored-by: Cole Greer <co...@colegreer.ca>
---
 docs/src/dev/provider/gremlin-semantics.asciidoc |  10 +-
 docs/src/dev/provider/index.asciidoc             |   6 ++
 docs/src/reference/the-traversal.asciidoc        |  21 ++++
 docs/src/upgrade/release-4.x.x.asciidoc          | 117 ++++++++---------------
 4 files changed, 76 insertions(+), 78 deletions(-)

diff --git a/docs/src/dev/provider/gremlin-semantics.asciidoc b/docs/src/dev/provider/gremlin-semantics.asciidoc
index ddb0b95b9e..b13b13e6dc 100644
--- a/docs/src/dev/provider/gremlin-semantics.asciidoc
+++ b/docs/src/dev/provider/gremlin-semantics.asciidoc
@@ -552,7 +552,7 @@ link:https://tinkerpop.apache.org/docs/x.y.z/reference/#addedge-step[reference]
 
 *Description:* Adds a vertex to the graph.
 
-*Syntax:* `addV()` | `addV(vertexLabel: STRING)` | `addV(vertexLabelTraversal: Traversal<any, STRING>)`
+*Syntax:* `addV()` | `addV(vertexLabel: STRING, moreLabels: STRING...)` | `addV(vertexLabelTraversal: Traversal<any, STRING>, moreLabelTraversals: Traversal<any, STRING>...)`
 
 [width="100%",options="header"]
 |=========================================================
@@ -563,7 +563,9 @@ link:https://tinkerpop.apache.org/docs/x.y.z/reference/#addedge-step[reference]
 *Arguments:*
 
 * `vertexLabel` - The label of the vertex to add.
+* `moreLabels` - Additional labels for the vertex, on graphs that permit more than one label per vertex.
 * `vertexLabelTraversal` - A traversal that produces the label of the vertex to add.
+* `moreLabelTraversals` - Additional traversals that each produce a further label for the vertex.
 
 *Modulation:*
 
@@ -572,11 +574,15 @@ 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.
+vertex label for the graph will be used. On a graph that permits more than one label per vertex, additional labels
+may be supplied to create a multi-label vertex; the resulting set of labels must satisfy the graph's label
+cardinality.
 
 *Exceptions:*
 
 * If the vertex label is null, an `Argument Error` is raised.
+* If the number of labels supplied violates the graph's label cardinality (for example, more than one label on a
+single-label graph), a `State Error` is raised.
 
 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)],
diff --git a/docs/src/dev/provider/index.asciidoc b/docs/src/dev/provider/index.asciidoc
index f2f505c368..9262cb8191 100644
--- a/docs/src/dev/provider/index.asciidoc
+++ b/docs/src/dev/provider/index.asciidoc
@@ -192,6 +192,12 @@ The following bullets provide some tips to consider when implementing the struct
 `Graph open(Configuration)` method where the `Configuration` is an Apache Commons class of that name. Alternatively, the
 `Graph` implementation can have the `GraphFactoryClass` annotation which specifies a class with that static
 `Graph open(Configuration)` method.
+* `Vertex`
+** Providers must opt into a specific `VertexLabelCardinality` of `ONE`, `ONE_OR_MORE`, or `ZERO_OR_MORE`. Any graph
+supporting a `VertexLabelCardinality` of `ONE_OR_MORE`, or `ZERO_OR_MORE` must use a `Vertex` implementation which
+overrides the default `Element.labels()`, `Element.addLabel(String, String...)`, `Element.dropLabel(String, String...)`,
+and `Element.dropLabels()` methods. See the
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#vertex-labels[Vertex Labels] reference docs for more details.
 * `VertexProperty`
 ** This interface is both a `Property` and an `Element` as `VertexProperty` is a first-class graph element in that it
 can have its own properties (i.e. meta-properties). Even if the implementation does not intend to support
diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc
index 065952a3f3..a44084506a 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -655,10 +655,27 @@ g.V().has('name','nothing')
 g.V().has('name','nothing').bothE()
 ----
 
+On a graph configured with a `LabelCardinality` that permits more than one label (`ONE_OR_MORE` or `ZERO_OR_MORE`),
+`addV()` accepts additional labels so a vertex can be created with several labels at once:
+
+[gremlin-groovy]
+----
+conf = new BaseConfiguration()
+conf.setProperty("gremlin.tinkergraph.vertexLabelCardinality", "ZERO_OR_MORE")
+graph = TinkerGraph.open(conf)
+g = traversal().with(graph)
+g.addV('person','employee').property('name','marko').labels() <1>
+----
+
+<1> The vertex is created carrying both the "person" and "employee" labels. Use <<addlabel-step,`addLabel()`>> to
+add further labels after creation. With the default `LabelCardinality.ONE`, supplying more than one label to `addV()`
+throws, since a vertex may carry only a single immutable label.
+
 *Additional References*
 
 link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#addV()++[`addV()`],
 link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#addV(java.lang.String)++[`addV(String)`],
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#addV(java.lang.String,java.lang.String...)++[`addV(String, String...)`],
 link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#addV(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`addV(Traversal)`]
 
 [[addlabel-step]]
@@ -2773,6 +2790,9 @@ link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gre
 
 The `label()`-step (*map*) takes an `Element` and extracts its label from it.
 
+NOTE: As of 4.0.0, `label()` is deprecated in favor of the <<labels-step,`labels()`>> step, which reliably returns
+every label an element carries.
+
 [gremlin-groovy,modern]
 ----
 g.V().label()
@@ -2802,6 +2822,7 @@ link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gre
 
 The `labels()`-step (*flatMap*) takes an `Element` and emits each of its labels as a separate traverser. For elements
 with a single label this behaves identically to `label()`. For multi-label elements, it emits one traverser per label.
+A vertex with no labels (possible only under `LabelCardinality.ZERO_OR_MORE`) emits nothing.
 
 [gremlin-groovy,theZoo]
 ----
diff --git a/docs/src/upgrade/release-4.x.x.asciidoc b/docs/src/upgrade/release-4.x.x.asciidoc
index 39f72fa69f..5221c0a9a0 100644
--- a/docs/src/upgrade/release-4.x.x.asciidoc
+++ b/docs/src/upgrade/release-4.x.x.asciidoc
@@ -97,70 +97,47 @@ See: link:https://tinkerpop.apache.org/docs/4.0.0/reference/#match-step[match()]
 Until now, vertices in the property graph model were limited to a single, immutable label assigned at creation. This
 release introduces configurable label cardinality, allowing vertices to carry multiple labels that can be added and
 removed over their lifetime. This is an optional feature for graph providers and not all will support it in the same
-way. TinkerGraph offers a configurable approach to enabling the the feature using one of the `LabelCardinality` settings
-as a graph-level setting that defaults to `ONE`, preserving the existing single-label behavior. To enable multi-label
-in TinkerGraph, set the vertex label cardinality in the graph properties:
+way. TinkerGraph enables it through a graph-level `LabelCardinality` setting that defaults to `ONE`, preserving the
+existing single-label behavior:
 
-```
-gremlin.tinkergraph.vertexLabelCardinality=ZERO_OR_MORE
-```
+[source,groovy]
+----
+gremlin.tinkergraph.vertexLabelCardinality=ONE
+----
 
-The three modes are `ONE` (single, immutable, the 3.x default), `ONE_OR_MORE` (mutable, minimum one), and
-`ZERO_OR_MORE` (fully flexible). Edge labels remain fixed at `ONE`.
+The three modes are `ONE` (exactly one immutable label per vertex), `ONE_OR_MORE` (requires at least one label but
+permits additional labels to be added or removed), and
+`ZERO_OR_MORE` (allows a vertex to have any number of labels including none). Edge labels remain fixed at `ONE`.
 
-The following examples demonstrate how Gremlin behaves with multi-label enabled:
+With `ONE_OR_MORE` or `ZERO_OR_MORE`, `addLabel()` and `dropLabel()` mutate a vertex's labels. The new `labels()` step
+produces all labels, while the legacy `label()` step continues to produce a single label only, and is now deprecated:
 
-```text
+[source,groovy]
+----
 gremlin> g.addV('person','employee').property('name','marko')
 ==>v[0]
-gremlin> g.V().has('name','marko').addLabel('manager')
-==>v[0]
-gremlin> g.V().has('name','marko').labels()
+gremlin> g.V().has('name','marko').addLabel('manager').labels()
 ==>person
 ==>employee
 ==>manager
 gremlin> g.V().has('name','marko').dropLabel('employee').labels()
 ==>person
 ==>manager
-```
-
-The `labels()` step is a flatMap that emits one traverser per label, unlike `label()` which returns a single string.
-For single-label vertices the two behave identically.
-
-The `mergeV()` step accepts a list for `T.label` to match or create multi-label vertices. The `onMatch` option uses
-append-only semantics: new labels are added, existing labels are preserved:
+----
 
-```text
-gremlin> g.mergeV([(T.label): ['person','employee'], name: 'marko'])
-==>v[0]
-gremlin> g.mergeV([(T.label): 'person', name: 'marko']).option(Merge.onMatch, [(T.label): 'director'])
-==>v[0]
-```
-
-By default, `elementMap()` and `valueMap()` continue to return labels as a single string. To receive all labels as a
-set, use `with("multilabel")` either per-traversal or as a persistent source configuration:
-
-```text
-// assuming a vertex with labels [person, employee, manager] and name "marko"
-gremlin> g.with("multilabel").V().has('name','marko').elementMap()
-==>{id=0, label=[manager, person, employee], name=marko}
-gremlin> g.V().has('name','marko').elementMap()
-==>{id=0, label=manager, name=marko}
-```
-
-To avoid repeating `with("multilabel")` on every traversal, create a persistent source:
-
-```text
-gremlin> gml = g.with("multilabel")
-==>graphtraversalsource[tinkergraph[vertices:1 edges:0], standard]
-gremlin> gml.V().has('name','marko').elementMap()
-==>{id=0, label=[manager, person, employee], name=marko}
-gremlin> gml.V().has('name','marko').valueMap(true)
-==>{id=0, label=[manager, person, employee], name=[marko]}
-```
+`mergeV()` now optionally accepts a list for `T.label` to match or create multi-label vertices. By default
+`elementMap()` and `valueMap()` still return a single label string, and a new traversal-source level
+`with("multilabel")` config alters the results to wrap labels in lists. The reference documentation covers each of these
+behaviors in detail.
 
 See: link:https://issues.apache.org/jira/browse/TINKERPOP-3261[TINKERPOP-3261],
-link:https://tinkerpop.apache.org/docs/4.0.0/reference/#tinkergraph-multi-label[Multi-Label], link:https://tinkerpop.apache.org/docs/4.0.0/reference/#labels-step[labels()],
+link:https://tinkerpop.apache.org/docs/4.0.0/reference/#tinkergraph-multi-label[Multi-Label],
+link:https://tinkerpop.apache.org/docs/4.0.0/reference/#vertex-labels[Vertex Labels],
+link:https://tinkerpop.apache.org/docs/4.0.0/reference/#labels-step[labels()],
+link:https://tinkerpop.apache.org/docs/4.0.0/reference/#addlabel-step[addLabel()],
+link:https://tinkerpop.apache.org/docs/4.0.0/reference/#elementmap-step[elementMap()],
+link:https://tinkerpop.apache.org/docs/4.0.0/reference/#valuemap-step[valueMap()],
+link:https://tinkerpop.apache.org/docs/4.0.0/reference/#mergevertex-step[mergeV()],
 link:https://tinkerpop.apache.org/docs/4.0.0/reference/#the-zoo-toy-graph[The Zoo]
 
 ==== More Dynamic Arguments in Gremlin
@@ -1081,33 +1058,21 @@ expected for the 4.0.0 major release.
 
 ===== Multi-Label Support
 
-Providers declare their supported label cardinality via `Graph.Features.getLabelCardinality()`, which defaults to
-`LabelCardinality.ONE` (single label, immutable, the 3.x behavior). To support multi-label, return `ONE_OR_MORE` or
-`ZERO_OR_MORE` from this method. This value may be a static constant for a graphs which do not offer configurable label
-cardinality. The label cardinality should reflect the current `Graph` instance.
-
-The `LabelCardinality` enum exposes `min()`, `max()`, and `supportsMutation()` for programmatic introspection of
-constraints. Constraint enforcement is handled by the `LabelCardinalityValidator` utility class, which providers may
-use directly or replace with their own validation logic tailored to their storage backend.
-
-Providers implementing multi-label must:
-
-- Store and return a `Set<String>` from `Element.labels()`
-- Implement `Element.addLabel(String, String...)` and `Element.dropLabel(String, String...)`
-- Ensure `hasLabel("a", "b")` uses OR semantics (matches vertices with label "a" or "b")
-- Serialize/deserialize the label set via the V4 GraphBinary format (which sends labels as a list)
-
-The default `elementMap()` and `valueMap()` implementations determine label output format solely from the
-`with("multilabel")` source option, not from the graph's `LabelCardinality`. This means a multi-label graph still
-returns a single label string from these steps unless `with("multilabel")` is explicitly configured. The intent is
-to eventually deprecate the single-string path entirely and always return labels as a set, aligning `elementMap()`
-and `valueMap()` with `labels()`. Until then, `with("singlelabel")` allows users to override a source-level
-`with("multilabel")` back to single-string output.
-
-Providers who want `elementMap()`/`valueMap()` to return the full label set by default (without requiring users to
-set `with("multilabel")`) should override `PropertyMapStep` and `ElementMapStep` to tie label output to their
-server-side label cardinality configuration. In that case, `with("singlelabel")` should still be respected as an
-explicit user override back to single-string output.
+The TinkerPop data model now allows providers to configure label cardinalities on vertices. Providers declare their
+supported label cardinality via `Graph.Features.VertexFeatures#getLabelCardinality()`, which must be set at one of three
+levels: `LabelCardinality.ONE` (consistent with TP3 semantics), `ONE_OR_MORE` or `ZERO_OR_MORE`. A choice of either
+`ONE_OR_MORE` or `ZERO_OR_MORE` requires an updated `Vertex` implementation, which overrides the default
+`Element.labels()`, `Element.addLabel()`, `Element.dropLabel()` and `Element.dropLabels()` methods.
+
+Providers may also choose default semantics for the `elementMap()` and `valueMap()` steps. The `T.label` fields in these
+maps may either be a `String` (consistent with TP3), or a `List<String>` (full compatibility with multi-labeled
+vertices). Users can provide a `with("singlelabel")` or `with("multilabel")` config on their traversal to explicitly opt
+into either of these behaviors. The reference implementation of `elementMap()` and `valueMap()` defaults to
+"singlelabel" semantics for an unconfigured traversal. All providers must either skip the `@SingleLabelDefault` or the
+`@MultiLabelDefault` tagged feature tests depending on their choice of default behavior.
+
+See the link:https://tinkerpop.apache.org/docs/4.0.0/reference/#vertex-labels[vertex labels] reference docs more details
+regarding the new vertex label cardinalities.
 
 ===== Traversal-Accepting Steps - HasContainer Guard