[
https://issues.apache.org/jira/browse/TINKERPOP-3261?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18095037#comment-18095037
]
ASF GitHub Bot commented on TINKERPOP-3261:
-------------------------------------------
spmallette commented on code in PR #3483:
URL: https://github.com/apache/tinkerpop/pull/3483#discussion_r3553153086
##########
docs/src/upgrade/release-4.x.x.asciidoc:
##########
@@ -186,6 +186,93 @@ For full details on the interceptor API for each language
variant, refer to the
each GLV's documentation in the
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#gremlin-drivers-variants[Gremlin
Drivers and Variants]
reference.
+==== Multi-Label Support
+
+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.
+
+The feature is controlled by `LabelCardinality`, 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:
+
+```
+gremlin.tinkergraph.vertexLabelCardinality=ZERO_OR_MORE
+```
+
+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`.
+
+With multi-label enabled, several new traversal steps become available:
+
+```text
+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()
+==>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]}
+```
+
+Note the following behavioral details:
+
+* The deprecated `label()` step returns a single, non-deterministic label when
multiple labels are present. Always
+ use `labels()` to retrieve the full set reliably.
+* When a source is configured with `with("multilabel")`, the label output can
be forced back to a single string
+ per-traversal using `with("singlelabel")`. This is useful for providers that
enable multi-label output by default
+ but need an escape hatch for backward compatibility. Note that when both
options are present on the same source,
+ `"singlelabel"` always takes precedence regardless of the order in which
they were applied.
+* Serialization via GraphSON V1/V2/V3 or Gryo only transmits one label per
vertex (using `label()`). Multi-label data
Review Comment:
do we have a GraphSON v1/v2/v3 anymore in 4.0? We're running into Gryo
issues now - is that single label note relevant once we fix that?
> Enable multiple label support on vertex with configurable label cardinality
> ---------------------------------------------------------------------------
>
> Key: TINKERPOP-3261
> URL: https://issues.apache.org/jira/browse/TINKERPOP-3261
> Project: TinkerPop
> Issue Type: Task
> Affects Versions: 4.0.0
> Reporter: Yang Xia
> Priority: Major
>
> Vertices are currently limited to a single immutable label assigned at
> creation. This prevents modeling common real-world scenarios where entities
> naturally belong to multiple categories (e.g., a person who is both an
> employee and a manager).
>
> Introduce a configurable LabelCardinality that controls how many labels a
> vertex may have and whether they can be mutated after creation. Three
> proposed modes: ONE (current behavior, default), ONE_OR_MORE (mutable,
> minimum one), ZERO_OR_MORE (fully flexible).
>
> New steps:
>
> - labels() — flatMap step emitting each label as a traverser
> - addLabel(String, String...) — add labels to a vertex
> - dropLabel(String, String...) — remove specific labels
> - dropLabels() — remove all labels
> Edge labels remain at cardinality ONE. The infrastructure would support
> future edge multi-label enablement without wire format changes.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)