You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@hugegraph.apache.org by "contrueCT (via GitHub)" <gi...@apache.org> on 2026/10/19 09:30:59 UTC

[PR] docs: add 1.8 Gremlin and TinkerPop 3.8 migration guide [hugegraph-doc]

contrueCT opened a new pull request, #541:
URL: https://github.com/apache/hugegraph-doc/pull/541

   ## What does this PR do?
   
   This PR adds comprehensive documentation for the upcoming HugeGraph 1.8.0 release regarding **TinkerPop 3.8.1 upgrade compatibility and Gremlin migration**, aligning with Java 17 and Groovy 4.0.25 runtime requirements.
   
   ### Key Changes
   1. **Migration Guides (Bilingual)**:
      - Added `content/cn/docs/guides/gremlin-migration-3.8.md` and `content/en/docs/guides/gremlin-migration-3.8.md`.
      - Highlighted the **Top 6 high-frequency syntax breaking changes** with comparative code examples:
        - Removal of `has(key, traversal)` overload (avoids silent empty results in Groovy).
        - Removal of `store()` and scoped `aggregate()` steps.
        - Parameterless `none()` renamed to `discard()`.
        - Stricter `by()` behavior on missing properties (`order`, `project`, `path` drops) and `coalesce` patterns.
        - `choose()` branch semantics alignment.
        - Datetime return types (`OffsetDateTime`) and `dateDiff()` unit change (seconds to milliseconds).
      - Documented server serializer migration (`gremlin.util.ser.*`) and HugeGraph Client 1.5.0 backward-compatibility support.
      - Categorized 70+ secondary edge cases and GLV client variations into quick-reference appendices.
   2. **Gremlin Language Reference**:
      - Updated `hugegraph-gremlin.md` (CN & EN) features table (`supportsUniformListValues=false`) and step tables (added `discard`, `datetime`, `mergeV`, `mergeE`, removed `store`).
   3. **Quickstart & Introduction Scope Refinements**:
      - Refined 1.7 vs master/1.8 scope warnings in `quickstart/hugegraph-server.md` and linked to the migration guide.
      - Polished storage backend support statements in `introduction/_index.md`.
   4. **1.8.0 Release Notes Draft**:
      - Prepared initial 1.8.0 release notes skeleton summarizing Gremlin and runtime breaking changes.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)


-- 
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: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] docs: add 1.8 Gremlin and TinkerPop 3.8 migration guide [hugegraph-doc]

Posted by "imbajin (via GitHub)" <gi...@apache.org>.
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: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] docs: add 1.8 Gremlin and TinkerPop 3.8 migration guide [hugegraph-doc]

Posted by "imbajin (via GitHub)" <gi...@apache.org>.
imbajin commented on code in PR #541:
URL: https://github.com/apache/hugegraph-doc/pull/541#discussion_r4356291909


##########
content/en/docs/guides/gremlin-migration-3.8.md:
##########
@@ -0,0 +1,229 @@
+---

Review Comment:
   ⚠️ Important: Please register this guide and the 1.8 release notes in `data/version_routes.json` for both languages. All four pages are absent from the exact-head map. `validate_aggregate_version_routes()` in `scripts/versioning.py` rejects canonical pages that are not in that map; a focused fixture with these four additional pages fails with `canonical Docs pages are absent from route-map for latest`. The same routes are also unknown to the version-switch lookup. Add `en/cn:guides/gremlin-migration-3.8` and `en/cn:changelog/hugegraph-1.8.0-release-notes` with their latest URLs and null historical targets so the aggregate validation can accept the new pages.



-- 
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: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] docs: add 1.8 Gremlin and TinkerPop 3.8 migration guide [hugegraph-doc]

Posted by "bitflicker64 (via GitHub)" <gi...@apache.org>.
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: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] docs: add 1.8 Gremlin and TinkerPop 3.8 migration guide [hugegraph-doc]

Posted by "bitflicker64 (via GitHub)" <gi...@apache.org>.
bitflicker64 commented on code in PR #541:
URL: https://github.com/apache/hugegraph-doc/pull/541#discussion_r4322278042


##########
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**!

Review Comment:
   Important: On HugeGraph 1.8 this query does not return an empty result; it fails. HugeGraph pushes `has()` into its own query, and `TraversalUtil.validPropertyValue()` rejects a traversal as the value. I ran the guide's two legacy lines on an in-process 1.8.0 build (TinkerPop 3.8.1, memory backend, `age` as an INT key with a range index). `g.V().has('age', __.is(gt(30)))` fails with `IllegalArgumentException: Invalid data type of query value '[IsStep(gt(30))]', expect INT for 'age', actual got class org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal`. `g.V().has(T.label, __.is('person'))` fails with `HugeException: The label type must be number or string, but got 'class org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal'`. The same error appears when the `has()` sits inside `where()` or `filter()`, or follows `in()`. The silent `[]` happens on TinkerGraph, not on HugeGraph. Users who follow this text will look for queries tha
 t return nothing, while their logs show an error that the guide never mentions. Please describe the 1.8 symptom as this error and quote its text, and keep the TinkerGraph silent case as a side note at most. Line 29 of this page and line 17 of both release notes make the same claim. The CN guide needs the same change at lines 22, 26 and 29.



##########
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())

Review Comment:
   Minor: On a vertex without `age`, this example does not discard the input. `Pick.none` only covers values that match no option; when the choice traversal returns nothing, 3.8.1 passes the element through. On TinkerGraph 3.8.1 this exact line returns `[v[3], josh, v[5], peter]`. On the HugeGraph 1.8.0 build, a `person` vertex without `age` comes back as `v[1:noage]`. Section 5 already adds `.option(Pick.unproductive, __.discard())` for this case. Please add it here as well, or change the comment so it says only unmatched values are dropped. CN lines 86-87 need the same change.



##########
content/en/docs/language/hugegraph-gremlin.md:
##########
@@ -10,6 +10,10 @@ HugeGraph supports [Gremlin](https://tinkerpop.apache.org/gremlin.html), a graph
 
 Gremlin can be used to create entities (Vertex and Edge) of a graph, modify the properties of entities, and delete entities. More importantly, it can be used to perform graph querying and analysis operations.
 
+> [!NOTE]
+> **Version & Migration Note**: HugeGraph 1.8.0 upgrades its underlying TinkerPop engine to **3.8.1** (along with Java 17 and Groovy 4.0.25).
+> Certain legacy syntax patterns (e.g., `store()`, `has(key, traversal)`, and scoped `aggregate()`) have been deprecated or modified. See the [1.8 Gremlin & TinkerPop Migration Guide](../guides/gremlin-migration-3.8) for details.

Review Comment:
   Minor: `store()` and `aggregate(Scope, ...)` are removed, not deprecated. On 3.8.1, `g.V().store('x')` fails with `MissingMethodException: No signature of method: ...DefaultGraphTraversal.store()`, and `aggregate(local, 'x')` fails the same way. On HugeGraph 1.8, `has(key, traversal)` fails with `Invalid data type of query value`. "Deprecated" suggests old scripts still run with a warning. Please say these forms were removed and now fail. CN line 15 (已被废弃) needs the same change.



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

Review Comment:
   Important: These two rows map typed serializers to untyped ones. In TinkerPop 3.5.1, `GraphSONMessageSerializerV2d0` serves `application/vnd.gremlin-v2.0+json` and `GraphSONMessageSerializerV3d0` serves `application/vnd.gremlin-v3.0+json`, and both are typed. Their 3.8.1 names are `GraphSONMessageSerializerV2` and `GraphSONMessageSerializerV3`, which serve the same MIME types. `GraphSONUntypedMessageSerializerV2` and `GraphSONUntypedMessageSerializerV3` serve `application/vnd.gremlin-v2.0+json;types=false` and `application/vnd.gremlin-v3.0+json;types=false` instead. I printed these lists from `mimeTypesSupported()` in gremlin-driver 3.5.1 and gremlin-util 3.8.1. If a user edits a 1.7.0 yaml row by row with this table, a client that asks for typed GraphSON v2 or v3 finds no matching serializer, and its requests fail. The `gremlin-server.yaml` on master has both forms: untyped V1/V2/V3, then typed `GraphSONMessageSerializerV2` and `GraphSONMessageSerializerV3`, the order `docs/serve
 r-runtime.md` describes. Please map `V2d0` to `GraphSONMessageSerializerV2` and `V3d0` to `GraphSONMessageSerializerV3`, and list the untyped V2/V3 entries as additions that the 1.8.0 file brings. The CN table (lines 172-173) needs the same change. Its V3 row also labels the untyped class "标准 Typed GraphSON V3".



##########
content/en/docs/changelog/hugegraph-1.8.0-release-notes.md:
##########
@@ -0,0 +1,43 @@
+---
+title: "HugeGraph 1.8.0 Release Notes"
+linkTitle: "Release-1.8.0"
+weight: 1

Review Comment:
   Minor: The 1.7.0 release notes also use `weight: 1`. The changelog pages step by 2 (1.5.0 is 3, 1.3.0 is 5) so the newest release comes first. When weights are equal, Hugo orders pages by date and then by link title. These pages have no `date`, so `Release-1.7.0` sorts above `Release-1.8.0` in the sidebar. `weight: 0` does not work either, because Hugo treats 0 as unweighted and puts the page last. Please give 1.7.0 a larger weight (for example 2) in both languages, or use a negative weight here. The CN page has the same front matter.



-- 
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: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org