bitflicker64 commented on code in PR #541:
URL: https://github.com/apache/hugegraph-doc/pull/541#discussion_r4314135356
##########
content/en/docs/guides/gremlin-migration-3.8.md:
##########
@@ -0,0 +1,189 @@
+---
+title: "HugeGraph 1.8.0 Gremlin Migration & Compatibility Guide"
+linkTitle: "1.8 Gremlin & TinkerPop Migration"
+description: "Comprehensive guide to breaking changes, high-frequency syntax
rewrites, configuration migrations, and complete compatibility references from
TinkerPop 3.5 to 3.8 in HugeGraph 1.8.0."
+weight: 9
+---
+
+HugeGraph 1.8.0 upgrades its underlying graph traversal and query framework
from Apache TinkerPop 3.5.1 to **TinkerPop 3.8.1**, requires **Java 17** for
Server and builds, and updates the script engine to **Groovy 4.0.25**.
+
+While bringing substantial performance optimizations and specification
alignments, this upgrade introduces several language-level breaking changes.
This guide highlights the **most critical and frequently used syntax changes**
with recommended rewrites to ensure seamless migration. Edge cases and
lower-level protocol details are organized in the [Full Compatibility
Reference](#full-compatibility-reference) at the end.
+
+> [!NOTE]
+> - This guide applies to upgrades from version 1.7.0 (or earlier) to 1.8.0.
+> - The **Groovy script engine** remains supported in 1.8.0, allowing existing
multi-line scripts, variable definitions, and Java closures to continue
functioning as expected.
+
+---
+
+## Top 6 High-Frequency Syntax and Behavioral Changes
+
+Among existing query scripts, the following 6 changes are the most common.
**Failure to update these may cause query errors or silently return empty
results.**
+
+### 1. `has(key, traversal)` Overload Removed (High Risk: Silent Empty Results)
+
+* **Impact**:
+ In TinkerPop 3.8.0, the `has(String, Traversal)` and `has(T, Traversal)`
overloads were removed.
+ In the Groovy script engine, legacy code will not throw a compilation error;
instead, it **silently falls back to `has(String, Object)`**, comparing the
anonymous traversal object itself against vertex/edge properties. In practice,
this **silently yields 0 results / empty sets**!
+* **Legacy Query**:
+ ```groovy
+ // Broken in 3.8: will not throw an error, but silently returns 0 results
+ g.V().has('age', __.is(gt(30)))
+ g.V().has(T.label, __.is('person'))
+ ```
+* **Recommended Rewrite**:
+ ```groovy
+ // For simple scalar/predicate checks, pass predicates directly
+ g.V().has('age', gt(30))
+ g.V().hasLabel('person')
+ g.V().hasId('v-1')
+
+ // If passing property values into child traversals for complex filtering,
use filter()
+ g.V().filter(__.values('age').is(gt(30)))
+ ```
+
+---
+
+### 2. `store()` Removed & `aggregate()` Scope Overload Removed
+
+* **Impact**:
+ - The `store('x')` step, previously used for lazy side-effect collection,
has been completely removed (`No signature of method: store()`).
+ - The `aggregate(Scope, 'x')` overload with an explicit `Scope` (both
`local` and `global`) has also been removed.
+* **Legacy Query**:
+ ```groovy
+ // Broken: store step removed
+ g.V().store('x').by('age').cap('x')
+
+ // Broken: aggregate(Scope, ...) overload removed
+ g.V().aggregate(local, 'x')
+ g.V().aggregate(global, 'x')
+ ```
+* **Recommended Rewrite**:
+ ```groovy
+ // 1. Eager global collection (formerly global aggregate): use
aggregate('x') directly
+ g.V().aggregate('x').by('age').cap('x')
+
+ // 2. Per-object / lazy collection (formerly store or local aggregate): wrap
in local()
+ g.V().local(__.aggregate('x').by('age')).cap('x')
+ ```
+
+---
+
+### 3. Step `none()` Renamed to `discard()`
+
+* **Impact**:
+ The parameterless `none()` step was originally used to discard all incoming
traversers (e.g., at the end of `choose()` or `coalesce()` branches). In 3.8.0,
this step is renamed to **`discard()`**.
+ Meanwhile, 3.8 introduces a new collection predicate step `none(P)`
(checking if no elements in a collection match predicate P). Calling
parameterless `none()` in 3.8 triggers argument errors.
+* **Recommended Rewrite**:
+ ```groovy
+ // Legacy:
+ g.V().choose(__.values('age')).option(gt(30),
__.values('name')).option(Pick.none, __.none()) // Error
+
+ // Rewritten: use discard()
+ g.V().choose(__.values('age')).option(gt(30),
__.values('name')).option(Pick.none, __.discard())
+ ```
+
+---
+
+### 4. Strict Behavior for Missing Properties in `by()`
+
+* **Impact**:
+ TinkerPop 3.6+ unified missing value handling across `by()` modulators
(removing previous default-null behaviors). In 3.8.1, when a property
referenced by `by()` does not exist:
+ 1. **Ordering `order().by('age')`**: Vertices missing `age` are
**immediately filtered out** (previously they might sort first/last).
+ 2. **Projection `project('name', 'age').by('name').by('age')`**: If `age` is
missing, the returned Map **will not contain the `age` key at all** (previously
returned `age: null`).
+ 3. **Path `path().by('age')`**: If any vertex along the path misses `age`,
the **entire path is dropped**.
+* **Recommended Rewrite**:
+ If your application requires preserving elements with explicit defaults
(e.g., `null`), use `coalesce()` inside `by()`:
+ ```groovy
+ // Retain key 'age' with null when missing
+ g.V().project('name', 'age')
+ .by('name')
+ .by(__.coalesce(__.values('age'), __.constant(null)))
+
+ // Provide a typed default for sorting missing fields
+ g.V().order().by(__.coalesce(__.values('age'), __.constant(-1)), desc)
+ ```
+
+---
+
+### 5. `choose()` Semantics Alignment
+
+* **Impact**:
+ - **Single Branch Execution**: When multiple `option()` conditions match
simultaneously, 3.8 **executes only the first matching branch** (legacy
versions might execute all matching branches).
+ - **Default Pass-Through**: If the choice child traversal yields no values
(e.g., property missing) or no `option()` matches, 3.8 **passes the input
element through unchanged** by default (legacy versions often filtered it out).
+* **Recommended Rewrite**:
+ - To execute multiple matching branches, rewrite using `union()` combined
with `filter()`.
+ - To filter out elements when no option matches or property is missing,
explicitly supply `Pick.none` and `Pick.unproductive` branches:
+ ```groovy
+ // Discard unmatched and missing-property inputs
+ g.V().choose(__.values('age'))
+ .option(gt(30), __.values('name'))
+ .option(Pick.none, __.discard())
+ .option(Pick.unproductive, __.discard())
+ ```
+
+---
+
+### 6. Date Types and Time Difference Units
+
+* **Impact**:
+ - **Return Type**: Date steps such as `datetime()` and `dateAdd()` now
return **`java.time.OffsetDateTime`** instead of `java.util.Date`.
+ - **Unit Change in `dateDiff()`**: The difference between two dates is now
returned in **milliseconds** instead of seconds (e.g., 1 day difference is
`86400000` ms instead of `86400` s).
Review Comment:
Important: `datetime()`, `dateAdd()` and `dateDiff()` do not exist in
TinkerPop 3.5.1, the version HugeGraph 1.7.0 ships (`tinkerpop.version` is
3.5.1 in `hugegraph-server/pom.xml` at the 1.7.0 tag). On a 3.5.1 Groovy
engine, `g.inject(new Date(86400000L)).dateDiff(new Date(0L))` fails with
`MissingMethodException: No signature of method: ...dateDiff()`, and
`datetime('2026-10-19T00:00:00Z')` fails the same way. No 1.7.0 script can have
got a `java.util.Date` or a seconds value from these steps. Seconds to
milliseconds and `Date` to `OffsetDateTime` are differences between 3.7 and
3.8, not between 1.7.0 and 1.8.0. Because this section is listed as one of the
six breaking changes, and the release notes repeat it under Key Breaking
Changes (EN and CN line 22), 1.7 users are told to audit `dateDiff()` TTL
checks they cannot have written. On 3.8.1 the steps do what the text says:
`dateDiff` returns `86400000` and `datetime()` returns `OffsetDateTime`. So the
facts are right, but they
describe new steps. Please move section 6 out of the Top 6 into a "new in 1.8"
note, and drop the date bullet from the release-note breaking changes. Appendix
1 (`mergeV`/`mergeE` are also absent in 3.5.1) and B14/B15 (`split()` and
`asString()` are also absent in 3.5.1) have the same problem: list them as new
steps, not as changed behaviour. The CN guide (lines 126-138 and 165-177) needs
the same change.
##########
content/en/docs/guides/gremlin-migration-3.8.md:
##########
@@ -0,0 +1,189 @@
+---
+title: "HugeGraph 1.8.0 Gremlin Migration & Compatibility Guide"
+linkTitle: "1.8 Gremlin & TinkerPop Migration"
+description: "Comprehensive guide to breaking changes, high-frequency syntax
rewrites, configuration migrations, and complete compatibility references from
TinkerPop 3.5 to 3.8 in HugeGraph 1.8.0."
+weight: 9
+---
+
+HugeGraph 1.8.0 upgrades its underlying graph traversal and query framework
from Apache TinkerPop 3.5.1 to **TinkerPop 3.8.1**, requires **Java 17** for
Server and builds, and updates the script engine to **Groovy 4.0.25**.
+
+While bringing substantial performance optimizations and specification
alignments, this upgrade introduces several language-level breaking changes.
This guide highlights the **most critical and frequently used syntax changes**
with recommended rewrites to ensure seamless migration. Edge cases and
lower-level protocol details are organized in the [Full Compatibility
Reference](#full-compatibility-reference) at the end.
+
+> [!NOTE]
+> - This guide applies to upgrades from version 1.7.0 (or earlier) to 1.8.0.
+> - The **Groovy script engine** remains supported in 1.8.0, allowing existing
multi-line scripts, variable definitions, and Java closures to continue
functioning as expected.
+
+---
+
+## Top 6 High-Frequency Syntax and Behavioral Changes
+
+Among existing query scripts, the following 6 changes are the most common.
**Failure to update these may cause query errors or silently return empty
results.**
+
+### 1. `has(key, traversal)` Overload Removed (High Risk: Silent Empty Results)
+
+* **Impact**:
+ In TinkerPop 3.8.0, the `has(String, Traversal)` and `has(T, Traversal)`
overloads were removed.
+ In the Groovy script engine, legacy code will not throw a compilation error;
instead, it **silently falls back to `has(String, Object)`**, comparing the
anonymous traversal object itself against vertex/edge properties. In practice,
this **silently yields 0 results / empty sets**!
+* **Legacy Query**:
+ ```groovy
+ // Broken in 3.8: will not throw an error, but silently returns 0 results
+ g.V().has('age', __.is(gt(30)))
+ g.V().has(T.label, __.is('person'))
+ ```
+* **Recommended Rewrite**:
+ ```groovy
+ // For simple scalar/predicate checks, pass predicates directly
+ g.V().has('age', gt(30))
+ g.V().hasLabel('person')
+ g.V().hasId('v-1')
+
+ // If passing property values into child traversals for complex filtering,
use filter()
+ g.V().filter(__.values('age').is(gt(30)))
+ ```
+
+---
+
+### 2. `store()` Removed & `aggregate()` Scope Overload Removed
+
+* **Impact**:
+ - The `store('x')` step, previously used for lazy side-effect collection,
has been completely removed (`No signature of method: store()`).
+ - The `aggregate(Scope, 'x')` overload with an explicit `Scope` (both
`local` and `global`) has also been removed.
+* **Legacy Query**:
+ ```groovy
+ // Broken: store step removed
+ g.V().store('x').by('age').cap('x')
+
+ // Broken: aggregate(Scope, ...) overload removed
+ g.V().aggregate(local, 'x')
+ g.V().aggregate(global, 'x')
+ ```
+* **Recommended Rewrite**:
+ ```groovy
+ // 1. Eager global collection (formerly global aggregate): use
aggregate('x') directly
+ g.V().aggregate('x').by('age').cap('x')
+
+ // 2. Per-object / lazy collection (formerly store or local aggregate): wrap
in local()
+ g.V().local(__.aggregate('x').by('age')).cap('x')
+ ```
+
+---
+
+### 3. Step `none()` Renamed to `discard()`
+
+* **Impact**:
+ The parameterless `none()` step was originally used to discard all incoming
traversers (e.g., at the end of `choose()` or `coalesce()` branches). In 3.8.0,
this step is renamed to **`discard()`**.
+ Meanwhile, 3.8 introduces a new collection predicate step `none(P)`
(checking if no elements in a collection match predicate P). Calling
parameterless `none()` in 3.8 triggers argument errors.
+* **Recommended Rewrite**:
+ ```groovy
+ // Legacy:
+ g.V().choose(__.values('age')).option(gt(30),
__.values('name')).option(Pick.none, __.none()) // Error
+
+ // Rewritten: use discard()
+ g.V().choose(__.values('age')).option(gt(30),
__.values('name')).option(Pick.none, __.discard())
+ ```
+
+---
+
+### 4. Strict Behavior for Missing Properties in `by()`
+
+* **Impact**:
+ TinkerPop 3.6+ unified missing value handling across `by()` modulators
(removing previous default-null behaviors). In 3.8.1, when a property
referenced by `by()` does not exist:
+ 1. **Ordering `order().by('age')`**: Vertices missing `age` are
**immediately filtered out** (previously they might sort first/last).
+ 2. **Projection `project('name', 'age').by('name').by('age')`**: If `age` is
missing, the returned Map **will not contain the `age` key at all** (previously
returned `age: null`).
+ 3. **Path `path().by('age')`**: If any vertex along the path misses `age`,
the **entire path is dropped**.
+* **Recommended Rewrite**:
+ If your application requires preserving elements with explicit defaults
(e.g., `null`), use `coalesce()` inside `by()`:
+ ```groovy
+ // Retain key 'age' with null when missing
+ g.V().project('name', 'age')
+ .by('name')
+ .by(__.coalesce(__.values('age'), __.constant(null)))
+
+ // Provide a typed default for sorting missing fields
+ g.V().order().by(__.coalesce(__.values('age'), __.constant(-1)), desc)
+ ```
+
+---
+
+### 5. `choose()` Semantics Alignment
+
+* **Impact**:
+ - **Single Branch Execution**: When multiple `option()` conditions match
simultaneously, 3.8 **executes only the first matching branch** (legacy
versions might execute all matching branches).
+ - **Default Pass-Through**: If the choice child traversal yields no values
(e.g., property missing) or no `option()` matches, 3.8 **passes the input
element through unchanged** by default (legacy versions often filtered it out).
+* **Recommended Rewrite**:
+ - To execute multiple matching branches, rewrite using `union()` combined
with `filter()`.
+ - To filter out elements when no option matches or property is missing,
explicitly supply `Pick.none` and `Pick.unproductive` branches:
+ ```groovy
+ // Discard unmatched and missing-property inputs
+ g.V().choose(__.values('age'))
+ .option(gt(30), __.values('name'))
+ .option(Pick.none, __.discard())
+ .option(Pick.unproductive, __.discard())
+ ```
+
+---
+
+### 6. Date Types and Time Difference Units
+
+* **Impact**:
+ - **Return Type**: Date steps such as `datetime()` and `dateAdd()` now
return **`java.time.OffsetDateTime`** instead of `java.util.Date`.
+ - **Unit Change in `dateDiff()`**: The difference between two dates is now
returned in **milliseconds** instead of seconds (e.g., 1 day difference is
`86400000` ms instead of `86400` s).
+* **Recommended Rewrite**:
+ - Update Java clients to expect `OffsetDateTime`; convert to
`java.util.Date` via `Date.from(offsetDateTime.toInstant())` only if strictly
required.
+ - Review all TTL checks and date comparisons that use `dateDiff()`. Adjust
multipliers or divide by 1000:
+ ```groovy
+ // Convert dateDiff milliseconds to seconds
+
g.inject(datetime('2026-10-19T00:00:00Z')).dateDiff(datetime('2026-10-18T00:00:00Z'))
+ .math('_ / 1000').asNumber(GType.LONG)
+ ```
+
+---
+
+## Server Configuration and Client Compatibility
+
+### 1. Serializer Class Names and Package Migration
+In `conf/gremlin-server.yaml`, serializer classes moved from `gremlin-driver`
to `gremlin-util`. **You must update serializer package names in the
configuration, as legacy class names will cause ClassNotFoundException**:
Review Comment:
Important: Changing the package name alone does not give a working 1.8
serializer config for HugeGraph. The `conf/gremlin-server.yaml` on master sets
`builder: org.apache.hugegraph.io.HugeGraphTypeSerializerRegistryBuilder` on
GraphBinary, and adds `org.apache.hugegraph.io.HugeGraphSONV1MessageIoRegistry`
to untyped GraphSON V1. `docs/server-runtime.md` says to keep both, and
`GremlinConfigCompatibilityTest` checks that the builder is present.
`HugeGraphIoRegistry` registers only the Gryo and GraphSON modules, so without
the builder GraphBinary has no serializer for HugeGraph `Id`, schema, `Blob` or
enum values. I checked this locally: with gremlin-util 3.8.1, a GraphBinary
serializer given an unregistered type fails with `IOException: Serializer for
type ... not found`. The 1.7.0 yaml also has `GraphSONMessageSerializerV2d0`,
which the table leaves out (its 3.8 name is `GraphSONMessageSerializerV2`).
Please tell users to start from the `gremlin-server.yaml` that ships with 1.8.0
and carry their own edits into it; the quickstart page already says "Use the
Gremlin configuration files bundled with Server". If the table stays, add the
builder and registry lines and the V2 row. The CN guide (lines 144-152) needs
the same change.
##########
content/en/docs/introduction/_index.md:
##########
@@ -43,7 +43,7 @@ HugeGraph Server is the OLTP engine and service entry point
for the graph databa
- **Query languages**: Supports Gremlin (TinkerPop 3) and Cypher (OpenCypher)
- **REST API**: Provides endpoints for schemas, graph data, queries, tasks,
and operations
- **Indexes and queries**: Supports exact, range, and compound-condition
queries
-- **Storage backends**: Versions 1.7.0 through `master` primarily support
RocksDB (standalone), HStore (distributed), and HBase
+- **Storage backends**: Supports RocksDB (recommended for standalone), HStore
(recommended for distributed), and HBase (legacy backends such as Cassandra,
MySQL, and PostgreSQL were deprecated starting in 1.7.0)
Review Comment:
Minor: "Deprecated starting in 1.7.0" understates what happened. The 1.7.0
release notes list "BREAKING CHANGE: Disable legacy backends include
MySQL/PG/c*" (apache/hugegraph#2746). On master, the `hugegraph-cassandra`,
`hugegraph-mysql`, `hugegraph-postgresql`, `hugegraph-scylladb` and
`hugegraph-palo` modules are gone. Please say these backends were disabled in
1.7.0 and have been removed for 1.8.0, so readers of the current docs do not
expect to be able to select them. CN line 46 needs the same fix.
##########
content/en/docs/guides/gremlin-migration-3.8.md:
##########
@@ -0,0 +1,189 @@
+---
+title: "HugeGraph 1.8.0 Gremlin Migration & Compatibility Guide"
+linkTitle: "1.8 Gremlin & TinkerPop Migration"
+description: "Comprehensive guide to breaking changes, high-frequency syntax
rewrites, configuration migrations, and complete compatibility references from
TinkerPop 3.5 to 3.8 in HugeGraph 1.8.0."
+weight: 9
+---
+
+HugeGraph 1.8.0 upgrades its underlying graph traversal and query framework
from Apache TinkerPop 3.5.1 to **TinkerPop 3.8.1**, requires **Java 17** for
Server and builds, and updates the script engine to **Groovy 4.0.25**.
+
+While bringing substantial performance optimizations and specification
alignments, this upgrade introduces several language-level breaking changes.
This guide highlights the **most critical and frequently used syntax changes**
with recommended rewrites to ensure seamless migration. Edge cases and
lower-level protocol details are organized in the [Full Compatibility
Reference](#full-compatibility-reference) at the end.
+
+> [!NOTE]
+> - This guide applies to upgrades from version 1.7.0 (or earlier) to 1.8.0.
+> - The **Groovy script engine** remains supported in 1.8.0, allowing existing
multi-line scripts, variable definitions, and Java closures to continue
functioning as expected.
+
+---
+
+## Top 6 High-Frequency Syntax and Behavioral Changes
+
+Among existing query scripts, the following 6 changes are the most common.
**Failure to update these may cause query errors or silently return empty
results.**
+
+### 1. `has(key, traversal)` Overload Removed (High Risk: Silent Empty Results)
+
+* **Impact**:
+ In TinkerPop 3.8.0, the `has(String, Traversal)` and `has(T, Traversal)`
overloads were removed.
+ In the Groovy script engine, legacy code will not throw a compilation error;
instead, it **silently falls back to `has(String, Object)`**, comparing the
anonymous traversal object itself against vertex/edge properties. In practice,
this **silently yields 0 results / empty sets**!
+* **Legacy Query**:
+ ```groovy
+ // Broken in 3.8: will not throw an error, but silently returns 0 results
+ g.V().has('age', __.is(gt(30)))
+ g.V().has(T.label, __.is('person'))
+ ```
+* **Recommended Rewrite**:
+ ```groovy
+ // For simple scalar/predicate checks, pass predicates directly
+ g.V().has('age', gt(30))
+ g.V().hasLabel('person')
+ g.V().hasId('v-1')
+
+ // If passing property values into child traversals for complex filtering,
use filter()
+ g.V().filter(__.values('age').is(gt(30)))
+ ```
+
+---
+
+### 2. `store()` Removed & `aggregate()` Scope Overload Removed
+
+* **Impact**:
+ - The `store('x')` step, previously used for lazy side-effect collection,
has been completely removed (`No signature of method: store()`).
+ - The `aggregate(Scope, 'x')` overload with an explicit `Scope` (both
`local` and `global`) has also been removed.
+* **Legacy Query**:
+ ```groovy
+ // Broken: store step removed
+ g.V().store('x').by('age').cap('x')
+
+ // Broken: aggregate(Scope, ...) overload removed
+ g.V().aggregate(local, 'x')
+ g.V().aggregate(global, 'x')
+ ```
+* **Recommended Rewrite**:
+ ```groovy
+ // 1. Eager global collection (formerly global aggregate): use
aggregate('x') directly
+ g.V().aggregate('x').by('age').cap('x')
+
+ // 2. Per-object / lazy collection (formerly store or local aggregate): wrap
in local()
+ g.V().local(__.aggregate('x').by('age')).cap('x')
+ ```
+
+---
+
+### 3. Step `none()` Renamed to `discard()`
+
+* **Impact**:
+ The parameterless `none()` step was originally used to discard all incoming
traversers (e.g., at the end of `choose()` or `coalesce()` branches). In 3.8.0,
this step is renamed to **`discard()`**.
+ Meanwhile, 3.8 introduces a new collection predicate step `none(P)`
(checking if no elements in a collection match predicate P). Calling
parameterless `none()` in 3.8 triggers argument errors.
+* **Recommended Rewrite**:
+ ```groovy
+ // Legacy:
+ g.V().choose(__.values('age')).option(gt(30),
__.values('name')).option(Pick.none, __.none()) // Error
+
+ // Rewritten: use discard()
+ g.V().choose(__.values('age')).option(gt(30),
__.values('name')).option(Pick.none, __.discard())
+ ```
+
+---
+
+### 4. Strict Behavior for Missing Properties in `by()`
+
+* **Impact**:
+ TinkerPop 3.6+ unified missing value handling across `by()` modulators
(removing previous default-null behaviors). In 3.8.1, when a property
referenced by `by()` does not exist:
+ 1. **Ordering `order().by('age')`**: Vertices missing `age` are
**immediately filtered out** (previously they might sort first/last).
+ 2. **Projection `project('name', 'age').by('name').by('age')`**: If `age` is
missing, the returned Map **will not contain the `age` key at all** (previously
returned `age: null`).
+ 3. **Path `path().by('age')`**: If any vertex along the path misses `age`,
the **entire path is dropped**.
+* **Recommended Rewrite**:
+ If your application requires preserving elements with explicit defaults
(e.g., `null`), use `coalesce()` inside `by()`:
+ ```groovy
+ // Retain key 'age' with null when missing
+ g.V().project('name', 'age')
+ .by('name')
+ .by(__.coalesce(__.values('age'), __.constant(null)))
+
+ // Provide a typed default for sorting missing fields
+ g.V().order().by(__.coalesce(__.values('age'), __.constant(-1)), desc)
+ ```
+
+---
+
+### 5. `choose()` Semantics Alignment
+
+* **Impact**:
+ - **Single Branch Execution**: When multiple `option()` conditions match
simultaneously, 3.8 **executes only the first matching branch** (legacy
versions might execute all matching branches).
+ - **Default Pass-Through**: If the choice child traversal yields no values
(e.g., property missing) or no `option()` matches, 3.8 **passes the input
element through unchanged** by default (legacy versions often filtered it out).
+* **Recommended Rewrite**:
+ - To execute multiple matching branches, rewrite using `union()` combined
with `filter()`.
+ - To filter out elements when no option matches or property is missing,
explicitly supply `Pick.none` and `Pick.unproductive` branches:
+ ```groovy
+ // Discard unmatched and missing-property inputs
+ g.V().choose(__.values('age'))
+ .option(gt(30), __.values('name'))
+ .option(Pick.none, __.discard())
+ .option(Pick.unproductive, __.discard())
+ ```
+
+---
+
+### 6. Date Types and Time Difference Units
+
+* **Impact**:
+ - **Return Type**: Date steps such as `datetime()` and `dateAdd()` now
return **`java.time.OffsetDateTime`** instead of `java.util.Date`.
+ - **Unit Change in `dateDiff()`**: The difference between two dates is now
returned in **milliseconds** instead of seconds (e.g., 1 day difference is
`86400000` ms instead of `86400` s).
+* **Recommended Rewrite**:
+ - Update Java clients to expect `OffsetDateTime`; convert to
`java.util.Date` via `Date.from(offsetDateTime.toInstant())` only if strictly
required.
+ - Review all TTL checks and date comparisons that use `dateDiff()`. Adjust
multipliers or divide by 1000:
+ ```groovy
+ // Convert dateDiff milliseconds to seconds
+
g.inject(datetime('2026-10-19T00:00:00Z')).dateDiff(datetime('2026-10-18T00:00:00Z'))
+ .math('_ / 1000').asNumber(GType.LONG)
+ ```
+
+---
+
+## Server Configuration and Client Compatibility
+
+### 1. Serializer Class Names and Package Migration
+In `conf/gremlin-server.yaml`, serializer classes moved from `gremlin-driver`
to `gremlin-util`. **You must update serializer package names in the
configuration, as legacy class names will cause ClassNotFoundException**:
+
+| Legacy Class (`driver.ser.*`) | 1.8.0 Class (`util.ser.*`) | Notes |
+|---|---|---|
+| `GraphBinaryMessageSerializerV1` |
`org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1` |
Recommended default binary serializer |
+| `GraphSONMessageSerializerV1d0` |
`org.apache.tinkerpop.gremlin.util.ser.GraphSONUntypedMessageSerializerV1` |
Retains untyped JSON (do not just remove `d0`, which becomes typed) |
+| `GraphSONMessageSerializerV3d0` |
`org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV3` | Standard
Typed GraphSON V3 |
+{.td-table--wide}
+
+### 2. Can HugeGraph Client 1.5.0 Continue to Work?
+* **Verdict**: **Yes**.
+* HugeGraph Server 1.8.0 provides backward-compatible adapters (graph alias
mapping and legacy auth path redirection). Applications using
`hugegraph-client:1.5.0` can continue standard CRUD, schema management, and
REST operations without forced SDK upgrades.
+* **Important Note**: Although Client 1.5.0 connects successfully, **all
submitted Gremlin script strings are executed on the 3.8.1 server engine**.
Therefore, Gremlin queries constructed in your code must comply with the 3.8
rules described above.
+
+---
+
+## Full Compatibility Reference
+
+### Appendix 1: Writes & Upsert (`mergeV` / `mergeE`)
+- **M01**: `onCreate` property maps strictly inherit the search match map.
Conflicting keys cannot overwrite matched properties.
+- **M02**: `mergeE` no longer implicitly binds incoming/outgoing vertices from
upstream traversers; specify `Direction.OUT` and `Direction.IN` in the map or
use explicit options.
+- **M03**: Conflicting `onCreate` / `onMatch` maps are validated during
construction rather than deferred to runtime execution.
+- **M04**: In 3.8, child traversers in `onMatch` receive the matched Element
object rather than the original input Map. Preserve input map references prior
to merge with `.as('input')` and reference with `select('input')`.
+
+### Appendix 2: Advanced Traversal Steps & Collections
+- **B07 (`local()` unpacks bulk)**: Traversers with bulk counters are expanded
into individual items when entering `local()` child traversals. Use
`groupCount()` for frequency analysis.
+- **B09 (`range(local)` collection unpacking)**: Slicing a single item from a
list (e.g., `limit(local, 1)`) consistently returns a Collection wrapper
(`[item]`). Append `.unfold()` if a scalar is needed.
+- **B11 (`sum()` return type)**: Summing integer streams without overflow may
return `Integer` instead of `Long`. Clients should accept `Number`.
+- **B14 (`split('')`)**: Splitting with an empty separator returns a list of
individual characters.
+- **B15 (`asString()` on null)**: `asString()` throws an
`IllegalArgumentException` on null inputs.
+
+### Appendix 3: GLV Client Variations
+- **Python**: Avoids Python keyword conflicts by appending an underscore to
step names (`filter_()`, `id_()`, `range_()`, `max_()`).
+- **JavaScript**: Set collections are returned as native ECMAScript `Set`
instances (use `.size` and `.has()`). Deprecated `connectOnStartup` option
removed; call `await connection.open()`.
+- **.NET**: `byte` values serialize strictly as signed bytes (`sbyte`).
+- **Go**: BigDecimal/BigInt aligned; always inspect errors on `Next()`.
+
+### Appendix 4: Network Protocols & Serializer Guardrails
+- **C03 (OLTP element properties)**: Remote OLTP queries return elements with
full properties by default rather than reference tokens only. Use `project()`
or `valueMap()` to restrict payload sizes when necessary.
+- **C06 (GraphSON payload limits)**: Added guardrails for max number length
(10,000), max string length (20,000,000), and max nesting depth (1,000).
+
+### Appendix 5: HugeGraph Feature Capabilities
+- **Meta-Properties Unsupported**: HugeGraph strictly follows its native
schema design and does not support TinkerPop meta-properties (properties on
properties). Writing property metadata in 1.8.0 will be **explicitly rejected**.
Review Comment:
Minor: 1.8.0 does not change this. At the 1.7.0 tag,
`HugeVertex.property(cardinality, key, value, objects...)` already throws
`VertexProperty.Exceptions.metaPropertiesNotSupported()` when key-values are
passed, and `HugeVertexProperty.property(key, value)` throws
`NotSupportException("nested property")`. Master has the same code. CN line 190
also says the write is "no longer implicitly degraded" (不再隐式退化), which
describes a 1.7 behaviour that never existed. Please describe it as unchanged
behaviour.
##########
content/en/docs/guides/gremlin-migration-3.8.md:
##########
@@ -0,0 +1,189 @@
+---
+title: "HugeGraph 1.8.0 Gremlin Migration & Compatibility Guide"
+linkTitle: "1.8 Gremlin & TinkerPop Migration"
+description: "Comprehensive guide to breaking changes, high-frequency syntax
rewrites, configuration migrations, and complete compatibility references from
TinkerPop 3.5 to 3.8 in HugeGraph 1.8.0."
+weight: 9
+---
+
+HugeGraph 1.8.0 upgrades its underlying graph traversal and query framework
from Apache TinkerPop 3.5.1 to **TinkerPop 3.8.1**, requires **Java 17** for
Server and builds, and updates the script engine to **Groovy 4.0.25**.
+
+While bringing substantial performance optimizations and specification
alignments, this upgrade introduces several language-level breaking changes.
This guide highlights the **most critical and frequently used syntax changes**
with recommended rewrites to ensure seamless migration. Edge cases and
lower-level protocol details are organized in the [Full Compatibility
Reference](#full-compatibility-reference) at the end.
+
+> [!NOTE]
+> - This guide applies to upgrades from version 1.7.0 (or earlier) to 1.8.0.
+> - The **Groovy script engine** remains supported in 1.8.0, allowing existing
multi-line scripts, variable definitions, and Java closures to continue
functioning as expected.
+
+---
+
+## Top 6 High-Frequency Syntax and Behavioral Changes
+
+Among existing query scripts, the following 6 changes are the most common.
**Failure to update these may cause query errors or silently return empty
results.**
+
+### 1. `has(key, traversal)` Overload Removed (High Risk: Silent Empty Results)
+
+* **Impact**:
+ In TinkerPop 3.8.0, the `has(String, Traversal)` and `has(T, Traversal)`
overloads were removed.
+ In the Groovy script engine, legacy code will not throw a compilation error;
instead, it **silently falls back to `has(String, Object)`**, comparing the
anonymous traversal object itself against vertex/edge properties. In practice,
this **silently yields 0 results / empty sets**!
+* **Legacy Query**:
+ ```groovy
+ // Broken in 3.8: will not throw an error, but silently returns 0 results
+ g.V().has('age', __.is(gt(30)))
+ g.V().has(T.label, __.is('person'))
+ ```
+* **Recommended Rewrite**:
+ ```groovy
+ // For simple scalar/predicate checks, pass predicates directly
+ g.V().has('age', gt(30))
+ g.V().hasLabel('person')
+ g.V().hasId('v-1')
+
+ // If passing property values into child traversals for complex filtering,
use filter()
+ g.V().filter(__.values('age').is(gt(30)))
+ ```
+
+---
+
+### 2. `store()` Removed & `aggregate()` Scope Overload Removed
+
+* **Impact**:
+ - The `store('x')` step, previously used for lazy side-effect collection,
has been completely removed (`No signature of method: store()`).
+ - The `aggregate(Scope, 'x')` overload with an explicit `Scope` (both
`local` and `global`) has also been removed.
+* **Legacy Query**:
+ ```groovy
+ // Broken: store step removed
+ g.V().store('x').by('age').cap('x')
+
+ // Broken: aggregate(Scope, ...) overload removed
+ g.V().aggregate(local, 'x')
+ g.V().aggregate(global, 'x')
+ ```
+* **Recommended Rewrite**:
+ ```groovy
+ // 1. Eager global collection (formerly global aggregate): use
aggregate('x') directly
+ g.V().aggregate('x').by('age').cap('x')
+
+ // 2. Per-object / lazy collection (formerly store or local aggregate): wrap
in local()
+ g.V().local(__.aggregate('x').by('age')).cap('x')
+ ```
+
+---
+
+### 3. Step `none()` Renamed to `discard()`
+
+* **Impact**:
+ The parameterless `none()` step was originally used to discard all incoming
traversers (e.g., at the end of `choose()` or `coalesce()` branches). In 3.8.0,
this step is renamed to **`discard()`**.
+ Meanwhile, 3.8 introduces a new collection predicate step `none(P)`
(checking if no elements in a collection match predicate P). Calling
parameterless `none()` in 3.8 triggers argument errors.
+* **Recommended Rewrite**:
+ ```groovy
+ // Legacy:
+ g.V().choose(__.values('age')).option(gt(30),
__.values('name')).option(Pick.none, __.none()) // Error
Review Comment:
Minor: This "Legacy" line fails on 1.7.0 too. TinkerPop 3.5.1 has no
anonymous `__.none()`, so the 3.5.1 Groovy engine fails with
`MissingMethodException: No signature of method: static ...__.none()`. Only the
traversal method existed: `g.V().none()` returns `[]` on 3.5.1, and on 3.8.1 it
fails with `IllegalArgumentException: Input predicate to none step can't be
null.` Please use a legacy example that ran on 3.5.1, such as
`g.V().hasLabel('person').none()` rewritten to `.discard()`, and quote the
3.8.1 error so users can search for it. CN line 79 needs the same fix.
##########
content/en/docs/changelog/hugegraph-1.8.0-release-notes.md:
##########
@@ -0,0 +1,42 @@
+---
+title: "HugeGraph 1.8.0 Release Notes"
+linkTitle: "Release-1.8.0"
+weight: 1
+---
+
+> WIP: This doc is under construction, please wait for the final version (BETA)
+
+### Runtime & Version Requirements
+
+- **Java Environment**: **1.8.0** HugeGraph components (Server, PD, Store)
require **Java 17** for runtime and source builds (1.7.0 is the last release
supporting Java 11).
+- **Query & Script Engine**: Graph traversal framework upgraded to **Apache
TinkerPop 3.8.1**, script engine upgraded to **Groovy 4.0.25**.
+
+### Key Breaking Changes & Compatibility
+
+#### 1. Critical Gremlin Traversal Breaking Changes
+- **Removed `has(key, traversal)` overload**: In Groovy, legacy syntax
silently falls back to Object comparison, resulting in **0 results / empty
sets** without throwing an error. Use `has('age', gt(30))` for simple
conditions, or `filter(__.values('age').is(gt(30)))` for child traversals.
+- **Removed `store()` & scoped `aggregate()`**: Use `aggregate('x')` for
global eager collection; use `local(__.aggregate('x'))` for lazy or per-object
collection.
+- **Step `none()` renamed to `discard()`**: Discarding incoming traversers
must now use `discard()` (avoids collision with new collection predicate
`none(P)`).
+- **Strict `by()` behavior on missing properties**: Vertices missing
properties are dropped in `order().by()`; keys are omitted from maps in
`project().by()`; paths are discarded in `path().by()`. Wrap with `coalesce()`
to provide explicit defaults if preservation is needed.
+- **`choose()` semantics alignment**: Executes only the first matching branch
when conditions overlap; passes elements through unchanged by default when no
branch matches or values are absent.
+- **Date types & unit changes**: Date operations return `OffsetDateTime`
instead of `java.util.Date`; `dateDiff()` results are in **milliseconds instead
of seconds**.
+
+> For comprehensive query comparison examples and the full migration
checklist, see the [HugeGraph 1.8.0 Gremlin Migration & Compatibility
Guide](../guides/gremlin-migration-3.8).
+
+#### 2. Server Configuration & Client Compatibility
+- **Serializer class names**: Serializer packages in
`conf/gremlin-server.yaml` moved from
`org.apache.tinkerpop.gremlin.driver.ser.*` to
`org.apache.tinkerpop.gremlin.util.ser.*`.
+- **HugeGraph Client 1.5.0**: Supported via server-side backward-compatibility
adapters; however, Gremlin query strings must follow TinkerPop 3.8 syntax.
+- **GPL word analyzer removed**: Use IK, SmartCN, or other compliant analyzers.
Review Comment:
Important: The word analyzer is still in 1.8.
`hugegraph-struct/src/main/java/org/apache/hugegraph/analyzer/WordAnalyzer.java`
is on master; apache/hugegraph#3295 only stopped bundling the GPLv3
`org.apdplat:word:1.3` jar. According to `docs/BUILDING.md` on master, a graph
configured with `search.text_analyzer=word` keeps working once `word-1.3.jar`
is placed in the Server's `lib/` directory. Without the jar, the graph fails
with a configuration error that names the missing dependency. If users follow
this note and switch to IK or SmartCN, text gets segmented differently, and
existing search-index entries written with `word` may stop matching new queries
unless the index is rebuilt. Please say that the jar is no longer bundled and
that graphs using `word` need `word-1.3.jar` added to `lib/`. CN line 29 needs
the same fix.
##########
content/en/docs/guides/gremlin-migration-3.8.md:
##########
@@ -0,0 +1,189 @@
+---
+title: "HugeGraph 1.8.0 Gremlin Migration & Compatibility Guide"
+linkTitle: "1.8 Gremlin & TinkerPop Migration"
+description: "Comprehensive guide to breaking changes, high-frequency syntax
rewrites, configuration migrations, and complete compatibility references from
TinkerPop 3.5 to 3.8 in HugeGraph 1.8.0."
+weight: 9
+---
+
+HugeGraph 1.8.0 upgrades its underlying graph traversal and query framework
from Apache TinkerPop 3.5.1 to **TinkerPop 3.8.1**, requires **Java 17** for
Server and builds, and updates the script engine to **Groovy 4.0.25**.
+
+While bringing substantial performance optimizations and specification
alignments, this upgrade introduces several language-level breaking changes.
This guide highlights the **most critical and frequently used syntax changes**
with recommended rewrites to ensure seamless migration. Edge cases and
lower-level protocol details are organized in the [Full Compatibility
Reference](#full-compatibility-reference) at the end.
+
+> [!NOTE]
+> - This guide applies to upgrades from version 1.7.0 (or earlier) to 1.8.0.
+> - The **Groovy script engine** remains supported in 1.8.0, allowing existing
multi-line scripts, variable definitions, and Java closures to continue
functioning as expected.
+
+---
+
+## Top 6 High-Frequency Syntax and Behavioral Changes
+
+Among existing query scripts, the following 6 changes are the most common.
**Failure to update these may cause query errors or silently return empty
results.**
+
+### 1. `has(key, traversal)` Overload Removed (High Risk: Silent Empty Results)
+
+* **Impact**:
+ In TinkerPop 3.8.0, the `has(String, Traversal)` and `has(T, Traversal)`
overloads were removed.
+ In the Groovy script engine, legacy code will not throw a compilation error;
instead, it **silently falls back to `has(String, Object)`**, comparing the
anonymous traversal object itself against vertex/edge properties. In practice,
this **silently yields 0 results / empty sets**!
+* **Legacy Query**:
+ ```groovy
+ // Broken in 3.8: will not throw an error, but silently returns 0 results
+ g.V().has('age', __.is(gt(30)))
+ g.V().has(T.label, __.is('person'))
+ ```
+* **Recommended Rewrite**:
+ ```groovy
+ // For simple scalar/predicate checks, pass predicates directly
+ g.V().has('age', gt(30))
+ g.V().hasLabel('person')
+ g.V().hasId('v-1')
+
+ // If passing property values into child traversals for complex filtering,
use filter()
+ g.V().filter(__.values('age').is(gt(30)))
+ ```
+
+---
+
+### 2. `store()` Removed & `aggregate()` Scope Overload Removed
+
+* **Impact**:
+ - The `store('x')` step, previously used for lazy side-effect collection,
has been completely removed (`No signature of method: store()`).
+ - The `aggregate(Scope, 'x')` overload with an explicit `Scope` (both
`local` and `global`) has also been removed.
+* **Legacy Query**:
+ ```groovy
+ // Broken: store step removed
+ g.V().store('x').by('age').cap('x')
+
+ // Broken: aggregate(Scope, ...) overload removed
+ g.V().aggregate(local, 'x')
+ g.V().aggregate(global, 'x')
+ ```
+* **Recommended Rewrite**:
+ ```groovy
+ // 1. Eager global collection (formerly global aggregate): use
aggregate('x') directly
+ g.V().aggregate('x').by('age').cap('x')
+
+ // 2. Per-object / lazy collection (formerly store or local aggregate): wrap
in local()
+ g.V().local(__.aggregate('x').by('age')).cap('x')
+ ```
+
+---
+
+### 3. Step `none()` Renamed to `discard()`
+
+* **Impact**:
+ The parameterless `none()` step was originally used to discard all incoming
traversers (e.g., at the end of `choose()` or `coalesce()` branches). In 3.8.0,
this step is renamed to **`discard()`**.
+ Meanwhile, 3.8 introduces a new collection predicate step `none(P)`
(checking if no elements in a collection match predicate P). Calling
parameterless `none()` in 3.8 triggers argument errors.
+* **Recommended Rewrite**:
+ ```groovy
+ // Legacy:
+ g.V().choose(__.values('age')).option(gt(30),
__.values('name')).option(Pick.none, __.none()) // Error
+
+ // Rewritten: use discard()
+ g.V().choose(__.values('age')).option(gt(30),
__.values('name')).option(Pick.none, __.discard())
+ ```
+
+---
+
+### 4. Strict Behavior for Missing Properties in `by()`
+
+* **Impact**:
+ TinkerPop 3.6+ unified missing value handling across `by()` modulators
(removing previous default-null behaviors). In 3.8.1, when a property
referenced by `by()` does not exist:
+ 1. **Ordering `order().by('age')`**: Vertices missing `age` are
**immediately filtered out** (previously they might sort first/last).
+ 2. **Projection `project('name', 'age').by('name').by('age')`**: If `age` is
missing, the returned Map **will not contain the `age` key at all** (previously
returned `age: null`).
+ 3. **Path `path().by('age')`**: If any vertex along the path misses `age`,
the **entire path is dropped**.
+* **Recommended Rewrite**:
+ If your application requires preserving elements with explicit defaults
(e.g., `null`), use `coalesce()` inside `by()`:
+ ```groovy
+ // Retain key 'age' with null when missing
+ g.V().project('name', 'age')
+ .by('name')
+ .by(__.coalesce(__.values('age'), __.constant(null)))
+
+ // Provide a typed default for sorting missing fields
+ g.V().order().by(__.coalesce(__.values('age'), __.constant(-1)), desc)
+ ```
+
+---
+
+### 5. `choose()` Semantics Alignment
+
+* **Impact**:
+ - **Single Branch Execution**: When multiple `option()` conditions match
simultaneously, 3.8 **executes only the first matching branch** (legacy
versions might execute all matching branches).
+ - **Default Pass-Through**: If the choice child traversal yields no values
(e.g., property missing) or no `option()` matches, 3.8 **passes the input
element through unchanged** by default (legacy versions often filtered it out).
Review Comment:
Minor: On 1.7.0 (TinkerPop 3.5.1), an element whose choice traversal returns
nothing is not filtered out; the query throws. On the modern graph,
`g.V().choose(__.values('age')).option(gt(30), __.values('name'))` fails on
3.5.1 with `IllegalArgumentException: The provided traverser does not map to a
value: v[3]->[PropertiesStep([age],value)]`. On 3.8.1 it passes `lop` and
`ripple` through. The no-match case is as described: 3.5.1 drops `vadas`, and
3.8.1 passes `v[2]` through. Please say that a missing property used to raise
this error and now passes the element through, so users can find these queries
by the old error text. CN line 112 needs the same fix.
##########
content/en/docs/language/hugegraph-gremlin.md:
##########
@@ -96,7 +100,9 @@ HugeGraph supports all steps of Gremlin. For complete
reference information abou
| coalesce | Returns the first traversal that returns a result.
|
[coalesce
step](http://tinkerpop.apache.org/docs/current/reference/#coalesce-step) |
| constant | Returns a constant value. Used in conjunction with coalesce.
|
[constant
step](http://tinkerpop.apache.org/docs/current/reference/#constant-step) |
| count | Returns a count from the traversal.
| [count
step](http://tinkerpop.apache.org/docs/current/reference/#count-step) |
+| datetime | Creates a datetime object or retrieves current server time
(returns `OffsetDateTime` in 1.8.0). | [datetime
step](http://tinkerpop.apache.org/docs/current/reference/#datetime-step) |
Review Comment:
Minor: The TinkerPop reference has no `#datetime-step` anchor. The current
(3.8.2) page has `discard-step`, `mergevertex-step` and `mergeedge-step`, and
for dates it has `asDate-step`, `dateAdd-step` and `dateDiff-step`.
`datetime()` is a Gremlin language function, documented under
`gremlin-groovy-differences`, so this link opens at the top of a very long
page. Please link to `#gremlin-groovy-differences` or to one of the date-step
anchors. CN line 103 needs the same fix.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]