imbajin commented on code in PR #541:
URL: https://github.com/apache/hugegraph-doc/pull/541#discussion_r4323397738


##########
content/en/docs/guides/gremlin-migration-3.8.md:
##########
@@ -0,0 +1,218 @@
+---
+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 5 High-Frequency Syntax and Behavioral Changes
+
+Among existing query scripts, the following 5 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**:
+  In TinkerPop 3.5.1, `none()` was a traversal step used to discard all 
incoming traversers (e.g., `g.V().hasLabel('person').none()`, which returned 
`[]`).
+  In 3.8.1, this step has been renamed to **`discard()`**.
+  Meanwhile, 3.8 introduces a new collection predicate step `none(P)` 
(checking if no elements in a collection match predicate P). Invoking 
parameterless
+  `none()` in 3.8.1 fails immediately with:
+  `IllegalArgumentException: Input predicate to none step can't be null.`
+* **Recommended Rewrite**:
+  ```groovy
+  // Legacy (runs on 3.5.1, returning []):
+  g.V().hasLabel('person').none()
+
+  // Rewritten for 3.8: use discard() to discard traversers
+  g.V().hasLabel('person').discard()
+
+  // Discarding unhandled inputs in choose() branches:
+  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**:
+  - **Missing Property Handling**: When a choice child traversal evaluated an 
absent property on an element, TinkerPop 3.5.1 threw:
+    `IllegalArgumentException: The provided traverser does not map to a value: 
v[3]->[PropertiesStep([age],value)]`.
+    In 3.8.1, elements missing the target property pass through unchanged 
without error.
+  - **Single Branch Execution**: When multiple `option()` conditions match 
simultaneously, 3.8.1 **executes only the first matching branch** (legacy 
versions might execute all matching branches).
+  - **Default Pass-Through**: When no `option()` condition matches, 3.8.1 
**passes the input element through unchanged** by default (whereas 3.5.1 
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())
+  ```
+
+---
+
+## New Steps & Functions in 1.8 (TinkerPop 3.8)
+
+TinkerPop 3.8 introduces native date manipulation functions and steps that 
were not present in 3.5.1 (HugeGraph 1.7.0):
+
+### Date Steps (`datetime()`, `dateAdd()`, `dateDiff()`)
+
+- **`datetime()`**: Creates a date-time object or retrieves server time.
+  In 3.8, it returns **`java.time.OffsetDateTime`** (e.g., 
`datetime('2026-10-19T00:00:00Z')`).
+- **`dateAdd()`**: Performs date arithmetic, adding a duration to a date.
+- **`dateDiff()`**: Computes the difference between two date-time objects, 
returning the difference in **milliseconds**
+  (e.g., a 1-day difference yields `86400000` ms).
+- **Example**:
+  ```groovy
+  // Current time as OffsetDateTime
+  g.inject(datetime())
+
+  // Compute difference in milliseconds, convert 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 Configuration in `conf/gremlin-server.yaml`
+
+In TinkerPop 3.8, serializer classes moved from `gremlin-driver` 
(`org.apache.tinkerpop.gremlin.driver.ser.*`)
+to `gremlin-util` (`org.apache.tinkerpop.gremlin.util.ser.*`).
+
+> [!IMPORTANT]
+> **Do not simply copy an old `gremlin-server.yaml` from 1.7.0 and edit class 
names.**
+> Always start from the `conf/gremlin-server.yaml` bundled with HugeGraph 
1.8.0 and carry over your customizations (ports, host, authenticator).
+> HugeGraph requires custom serializer builders and registries: GraphBinary 
requires `builder: 
org.apache.hugegraph.io.HugeGraphTypeSerializerRegistryBuilder`
+> to serialize HugeGraph `Id`, schema, `Blob`, and enum values (otherwise 
failing with `IOException: Serializer for type ... not found`);
+> untyped GraphSON V1 requires 
`org.apache.hugegraph.io.HugeGraphSONV1MessageIoRegistry`.
+
+| Legacy Serializer (`driver.ser.*`) | 1.8.0 Serializer (`util.ser.*`) | 
Required Registries / Builder | Notes |
+|---|---|---|---|
+| `GraphBinaryMessageSerializerV1` | 
`org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1` | 
`builder: 
org.apache.hugegraph.io.HugeGraphTypeSerializerRegistryBuilder`<br>`ioRegistries:
 [org.apache.hugegraph.io.HugeGraphIoRegistry]` | Recommended default binary 
serializer |
+| `GraphSONMessageSerializerV1d0` | 
`org.apache.tinkerpop.gremlin.util.ser.GraphSONUntypedMessageSerializerV1` | 
`ioRegistries: [org.apache.hugegraph.io.HugeGraphIoRegistry, 
org.apache.hugegraph.io.HugeGraphSONV1MessageIoRegistry]` | Untyped GraphSON V1 
|
+| `GraphSONMessageSerializerV2d0` | 
`org.apache.tinkerpop.gremlin.util.ser.GraphSONUntypedMessageSerializerV2` | 
`ioRegistries: [org.apache.hugegraph.io.HugeGraphIoRegistry]` | Untyped 
GraphSON V2 |
+| `GraphSONMessageSerializerV3d0` | 
`org.apache.tinkerpop.gremlin.util.ser.GraphSONUntypedMessageSerializerV3` | 
`ioRegistries: [org.apache.hugegraph.io.HugeGraphIoRegistry]` | Untyped 
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.

Review Comment:
   ⚠️ Important: This compatibility claim says Server 1.8 redirects the legacy 
auth path, but Client 1.5 uses `graphs/{graph}/auth/...` while the server 
`PathFilter` only prefixes the default graphspace and `UserAPI` is mounted at 
`graphspaces/{graphspace}/auth/users`; the rewritten request still has no 
matching route. Please narrow the claim to verified operations or 
document/provide the legacy auth adapter, and mirror the correction in Chinese.



##########
content/en/docs/guides/gremlin-migration-3.8.md:
##########
@@ -0,0 +1,218 @@
+---
+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 5 High-Frequency Syntax and Behavioral Changes
+
+Among existing query scripts, the following 5 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**:
+  In TinkerPop 3.5.1, `none()` was a traversal step used to discard all 
incoming traversers (e.g., `g.V().hasLabel('person').none()`, which returned 
`[]`).
+  In 3.8.1, this step has been renamed to **`discard()`**.
+  Meanwhile, 3.8 introduces a new collection predicate step `none(P)` 
(checking if no elements in a collection match predicate P). Invoking 
parameterless
+  `none()` in 3.8.1 fails immediately with:
+  `IllegalArgumentException: Input predicate to none step can't be null.`
+* **Recommended Rewrite**:
+  ```groovy
+  // Legacy (runs on 3.5.1, returning []):
+  g.V().hasLabel('person').none()
+
+  // Rewritten for 3.8: use discard() to discard traversers
+  g.V().hasLabel('person').discard()
+
+  // Discarding unhandled inputs in choose() branches:
+  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**:
+  - **Missing Property Handling**: When a choice child traversal evaluated an 
absent property on an element, TinkerPop 3.5.1 threw:
+    `IllegalArgumentException: The provided traverser does not map to a value: 
v[3]->[PropertiesStep([age],value)]`.
+    In 3.8.1, elements missing the target property pass through unchanged 
without error.
+  - **Single Branch Execution**: When multiple `option()` conditions match 
simultaneously, 3.8.1 **executes only the first matching branch** (legacy 
versions might execute all matching branches).
+  - **Default Pass-Through**: When no `option()` condition matches, 3.8.1 
**passes the input element through unchanged** by default (whereas 3.5.1 
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())
+  ```
+
+---
+
+## New Steps & Functions in 1.8 (TinkerPop 3.8)
+
+TinkerPop 3.8 introduces native date manipulation functions and steps that 
were not present in 3.5.1 (HugeGraph 1.7.0):
+
+### Date Steps (`datetime()`, `dateAdd()`, `dateDiff()`)
+
+- **`datetime()`**: Creates a date-time object or retrieves server time.
+  In 3.8, it returns **`java.time.OffsetDateTime`** (e.g., 
`datetime('2026-10-19T00:00:00Z')`).
+- **`dateAdd()`**: Performs date arithmetic, adding a duration to a date.
+- **`dateDiff()`**: Computes the difference between two date-time objects, 
returning the difference in **milliseconds**
+  (e.g., a 1-day difference yields `86400000` ms).
+- **Example**:
+  ```groovy
+  // Current time as OffsetDateTime
+  g.inject(datetime())
+
+  // Compute difference in milliseconds, convert 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 Configuration in `conf/gremlin-server.yaml`
+
+In TinkerPop 3.8, serializer classes moved from `gremlin-driver` 
(`org.apache.tinkerpop.gremlin.driver.ser.*`)
+to `gremlin-util` (`org.apache.tinkerpop.gremlin.util.ser.*`).
+
+> [!IMPORTANT]
+> **Do not simply copy an old `gremlin-server.yaml` from 1.7.0 and edit class 
names.**
+> Always start from the `conf/gremlin-server.yaml` bundled with HugeGraph 
1.8.0 and carry over your customizations (ports, host, authenticator).
+> HugeGraph requires custom serializer builders and registries: GraphBinary 
requires `builder: 
org.apache.hugegraph.io.HugeGraphTypeSerializerRegistryBuilder`
+> to serialize HugeGraph `Id`, schema, `Blob`, and enum values (otherwise 
failing with `IOException: Serializer for type ... not found`);
+> untyped GraphSON V1 requires 
`org.apache.hugegraph.io.HugeGraphSONV1MessageIoRegistry`.
+
+| Legacy Serializer (`driver.ser.*`) | 1.8.0 Serializer (`util.ser.*`) | 
Required Registries / Builder | Notes |
+|---|---|---|---|
+| `GraphBinaryMessageSerializerV1` | 
`org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1` | 
`builder: 
org.apache.hugegraph.io.HugeGraphTypeSerializerRegistryBuilder`<br>`ioRegistries:
 [org.apache.hugegraph.io.HugeGraphIoRegistry]` | Recommended default binary 
serializer |
+| `GraphSONMessageSerializerV1d0` | 
`org.apache.tinkerpop.gremlin.util.ser.GraphSONUntypedMessageSerializerV1` | 
`ioRegistries: [org.apache.hugegraph.io.HugeGraphIoRegistry, 
org.apache.hugegraph.io.HugeGraphSONV1MessageIoRegistry]` | Untyped GraphSON V1 
|
+| `GraphSONMessageSerializerV2d0` | 
`org.apache.tinkerpop.gremlin.util.ser.GraphSONUntypedMessageSerializerV2` | 
`ioRegistries: [org.apache.hugegraph.io.HugeGraphIoRegistry]` | Untyped 
GraphSON V2 |
+| `GraphSONMessageSerializerV3d0` | 
`org.apache.tinkerpop.gremlin.util.ser.GraphSONUntypedMessageSerializerV3` | 
`ioRegistries: [org.apache.hugegraph.io.HugeGraphIoRegistry]` | Untyped 
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`)
+`mergeV()` and `mergeE()` are new steps in TinkerPop 3.8 (absent in 3.5.1) for 
graph upserts:
+- **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.

Review Comment:
   ⚠️ Important: TinkerPop's construction-time validation applies to a static 
`onCreate` map that overrides the merge search criteria; it does not validate 
conflicts between `onCreate` and `onMatch` maps. Please narrow M03 to the 
`onCreate` versus search-criteria case and mirror the correction in Chinese.



##########
content/en/docs/guides/gremlin-migration-3.8.md:
##########
@@ -0,0 +1,218 @@
+---
+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 5 High-Frequency Syntax and Behavioral Changes
+
+Among existing query scripts, the following 5 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**:
+  In TinkerPop 3.5.1, `none()` was a traversal step used to discard all 
incoming traversers (e.g., `g.V().hasLabel('person').none()`, which returned 
`[]`).
+  In 3.8.1, this step has been renamed to **`discard()`**.
+  Meanwhile, 3.8 introduces a new collection predicate step `none(P)` 
(checking if no elements in a collection match predicate P). Invoking 
parameterless
+  `none()` in 3.8.1 fails immediately with:
+  `IllegalArgumentException: Input predicate to none step can't be null.`
+* **Recommended Rewrite**:
+  ```groovy
+  // Legacy (runs on 3.5.1, returning []):
+  g.V().hasLabel('person').none()
+
+  // Rewritten for 3.8: use discard() to discard traversers
+  g.V().hasLabel('person').discard()
+
+  // Discarding unhandled inputs in choose() branches:
+  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**:
+  - **Missing Property Handling**: When a choice child traversal evaluated an 
absent property on an element, TinkerPop 3.5.1 threw:
+    `IllegalArgumentException: The provided traverser does not map to a value: 
v[3]->[PropertiesStep([age],value)]`.
+    In 3.8.1, elements missing the target property pass through unchanged 
without error.
+  - **Single Branch Execution**: When multiple `option()` conditions match 
simultaneously, 3.8.1 **executes only the first matching branch** (legacy 
versions might execute all matching branches).
+  - **Default Pass-Through**: When no `option()` condition matches, 3.8.1 
**passes the input element through unchanged** by default (whereas 3.5.1 
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())
+  ```
+
+---
+
+## New Steps & Functions in 1.8 (TinkerPop 3.8)
+
+TinkerPop 3.8 introduces native date manipulation functions and steps that 
were not present in 3.5.1 (HugeGraph 1.7.0):
+
+### Date Steps (`datetime()`, `dateAdd()`, `dateDiff()`)
+
+- **`datetime()`**: Creates a date-time object or retrieves server time.
+  In 3.8, it returns **`java.time.OffsetDateTime`** (e.g., 
`datetime('2026-10-19T00:00:00Z')`).
+- **`dateAdd()`**: Performs date arithmetic, adding a duration to a date.
+- **`dateDiff()`**: Computes the difference between two date-time objects, 
returning the difference in **milliseconds**
+  (e.g., a 1-day difference yields `86400000` ms).
+- **Example**:
+  ```groovy
+  // Current time as OffsetDateTime
+  g.inject(datetime())
+
+  // Compute difference in milliseconds, convert 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 Configuration in `conf/gremlin-server.yaml`
+
+In TinkerPop 3.8, serializer classes moved from `gremlin-driver` 
(`org.apache.tinkerpop.gremlin.driver.ser.*`)
+to `gremlin-util` (`org.apache.tinkerpop.gremlin.util.ser.*`).
+
+> [!IMPORTANT]
+> **Do not simply copy an old `gremlin-server.yaml` from 1.7.0 and edit class 
names.**
+> Always start from the `conf/gremlin-server.yaml` bundled with HugeGraph 
1.8.0 and carry over your customizations (ports, host, authenticator).
+> HugeGraph requires custom serializer builders and registries: GraphBinary 
requires `builder: 
org.apache.hugegraph.io.HugeGraphTypeSerializerRegistryBuilder`
+> to serialize HugeGraph `Id`, schema, `Blob`, and enum values (otherwise 
failing with `IOException: Serializer for type ... not found`);
+> untyped GraphSON V1 requires 
`org.apache.hugegraph.io.HugeGraphSONV1MessageIoRegistry`.
+
+| Legacy Serializer (`driver.ser.*`) | 1.8.0 Serializer (`util.ser.*`) | 
Required Registries / Builder | Notes |
+|---|---|---|---|
+| `GraphBinaryMessageSerializerV1` | 
`org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1` | 
`builder: 
org.apache.hugegraph.io.HugeGraphTypeSerializerRegistryBuilder`<br>`ioRegistries:
 [org.apache.hugegraph.io.HugeGraphIoRegistry]` | Recommended default binary 
serializer |
+| `GraphSONMessageSerializerV1d0` | 
`org.apache.tinkerpop.gremlin.util.ser.GraphSONUntypedMessageSerializerV1` | 
`ioRegistries: [org.apache.hugegraph.io.HugeGraphIoRegistry, 
org.apache.hugegraph.io.HugeGraphSONV1MessageIoRegistry]` | Untyped GraphSON V1 
|
+| `GraphSONMessageSerializerV2d0` | 
`org.apache.tinkerpop.gremlin.util.ser.GraphSONUntypedMessageSerializerV2` | 
`ioRegistries: [org.apache.hugegraph.io.HugeGraphIoRegistry]` | Untyped 
GraphSON V2 |
+| `GraphSONMessageSerializerV3d0` | 
`org.apache.tinkerpop.gremlin.util.ser.GraphSONUntypedMessageSerializerV3` | 
`ioRegistries: [org.apache.hugegraph.io.HugeGraphIoRegistry]` | Untyped 
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`)
+`mergeV()` and `mergeE()` are new steps in TinkerPop 3.8 (absent in 3.5.1) for 
graph upserts:

Review Comment:
   🧹 Minor: TinkerPop introduced `mergeV()` and `mergeE()` in 3.6.0, with 
further semantics changes in 3.6.2; they are not new in TinkerPop 3.8. Since 
this guide compares HugeGraph's 3.5.1 and 3.8.1 stacks, please describe them as 
newly available in HugeGraph 1.8.0 or in this upgrade, and mirror that wording 
in Chinese.



-- 
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]

Reply via email to