

# Notes on Amazon Neptune Standards Compliance
<a name="feature-overview-standards-compliance"></a>

Amazon Neptune complies with applicable standards in implementing the Gremlin and SPARQL graph query languages in most cases.

These sections describe the standards as well as those areas where Neptune extends or diverges from them.

**Topics**
+ [Gremlin standards compliance in Amazon Neptune](access-graph-gremlin-differences.md)
+ [SPARQL standards compliance in Amazon Neptune](feature-sparql-compliance.md)
+ [openCypher specification compliance in Amazon Neptune](feature-opencypher-compliance.md)

# Gremlin standards compliance in Amazon Neptune
<a name="access-graph-gremlin-differences"></a>

The following sections provide an overview of the Neptune implementation of Gremlin and how it differs from the Apache TinkerPop implementation.

Neptune implements some Gremlin steps natively in its engine, and uses the Apache TinkerPop Gremlin implementation to process others (see [Native Gremlin step support in Amazon Neptune](gremlin-step-support.md)).

**Note**  
For some concrete examples of these implementation differences shown in Gremlin Console and Amazon Neptune, see the [Using Gremlin to access graph data in Amazon Neptune](get-started-graph-gremlin.md) section of the Quick Start.

**Topics**
+ [Applicable Standards for Gremlin](#feature-gremlin-applicable-standards)
+ [Variables and parameters in scripts](#feature-gremlin-differences-variables)
+ [TinkerPop enumerations](#feature-gremlin-differences-tinkerpop)
+ [Java code](#feature-gremlin-differences-java)
+ [Properties on elements](#feature-gremlin-differences-properties-on-elements)
+ [Script execution](#feature-gremlin-differences-script)
+ [Sessions](#feature-gremlin-differences-sessions)
+ [Transactions](#feature-gremlin-differences-transactions)
+ [Vertex and edge IDs](#feature-gremlin-differences-vertex-edge-ids)
+ [User-supplied IDs](#feature-gremlin-differences-user-supplied-ids)
+ [Vertex property IDs](#feature-gremlin-differences-vertex-property-ids)
+ [Cardinality of vertex properties](#feature-gremlin-differences-vertex-property-cardinality)
+ [Updating a vertex property](#feature-gremlin-differences-vertex-property-update)
+ [Labels](#feature-gremlin-differences-labels)
+ [Escape characters](#feature-gremlin-differences-escapes)
+ [Groovy limitations](#feature-gremlin-differences-groovy)
+ [Serialization](#feature-gremlin-differences-serialization)
+ [Lambda steps](#feature-gremlin-differences-lambda)
+ [Unsupported Gremlin methods](#feature-gremlin-differences-unsupported-methods)
+ [Unsupported Gremlin steps](#feature-gremlin-differences-unsupported-steps)
+ [Gremlin graph features in Neptune](#gremlin-api-reference-features)

## Applicable Standards for Gremlin
<a name="feature-gremlin-applicable-standards"></a>
+ The Gremlin language is defined by [Apache TinkerPop Documentation](http://tinkerpop.apache.org/docs/current/reference/) and the Apache TinkerPop implementation of Gremlin rather than by a formal specification.
+ For numeric formats, Gremlin follows the IEEE 754 standard ([IEEE 754-2019 - IEEE Standard for Floating-Point Arithmetic](https://standards.ieee.org/content/ieee-standards/en/standard/754-2019.html). For more information, also see the [Wikipedia IEEE 754 page](https://en.wikipedia.org/wiki/IEEE_754)).

## Variables and parameters in scripts
<a name="feature-gremlin-differences-variables"></a>

Where pre-bound variables are concerned, the traversal object `g` is Pre-bound in Neptune, and the `graph` object is not supported.

Although Neptune does not support Gremlin variables or parameterization in scripts, you may often encounter sample scripts for Gremlin Server on the Internet that contain variable declarations, such as:

```
String query = "x = 1; g.V(x)";
List<Result> results = client.submit(query).all().get();
```

There are also many examples that make use of [parameterization](https://tinkerpop.apache.org/docs/current/reference/#parameterized-scripts) (or bindings) when submitting queries, such as:

```
Map<String,Object> params = new HashMap<>();
params.put("x",1);
String query = "g.V(x)";
List<Result> results = client.submit(query).all().get();
```

The parameter examples are usually associated with warnings about performance penalties for not parameterizing when possible. There are a great many such examples for TinkerPop that you may encounter, and they all sound quite convincing about the need to parameterize.

However, both the variables declarations feature and the parameterization feature (along with the warnings) only apply to TinkerPop's Gremlin Server when it is using the `GremlinGroovyScriptEngine`. They do not apply when Gremlin Server uses Gremlin's `gremlin-language` ANTLR grammar to parse queries. The ANTLR grammar doesn't support either variable declarations or parameterization, so when using ANTLR, you don't have to worry about failing to parameterize. Because the ANTLR grammar is a newer component of TinkerPop, older content you may encounter on the Internet doesn't generally reflect this distinction.

Neptune uses the ANTLR grammar in its query processing engine rather than the `GremlinGroovyScriptEngine`, so it does not support variables or parameterization or the `bindings` property. As a result, the problems related to failing to parameterize do not apply in Neptune. Using Neptune, it's perfectly safe simply to submit the query as-is where one would normally parameterize. As a result, the previous example can be simplified without any performance penalty as follows:

```
String query = "g.V(1)";
List<Result> results = client.submit(query).all().get();
```

## TinkerPop enumerations
<a name="feature-gremlin-differences-tinkerpop"></a>

Neptune does not support fully qualified class names for enumeration values. For example, you must use `single` and not `org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality.single` in your Groovy request.

The enumeration type is determined by parameter type.

The following table shows the allowed enumeration values and the related TinkerPop fully qualified name.

| Allowed Values | Class | 
| --- |--- |
| id, key, label, value | [org.apache.tinkerpop.gremlin.structure.T](https://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/structure/T.html) | 
| T.id, T.key, T.label, T.value | [org.apache.tinkerpop.gremlin.structure.T](https://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/structure/T.html) | 
| set, single | [org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality](https://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/structure/VertexProperty.Cardinality.html) | 
| asc, desc, shuffle | [org.apache.tinkerpop.gremlin.process.traversal.Order](https://tinkerpop.apache.org/javadocs/3.7.2/full/org/apache/tinkerpop/gremlin/process/traversal/Order.html) | 
| Order.asc, Order.desc, Order.shuffle | [org.apache.tinkerpop.gremlin.process.traversal.Order](https://tinkerpop.apache.org/javadocs/3.7.2/full/org/apache/tinkerpop/gremlin/process/traversal/Order.html) | 
| global, local | [org.apache.tinkerpop.gremlin.process.traversal.Scope](https://tinkerpop.apache.org/javadocs/3.7.2/core/org/apache/tinkerpop/gremlin/process/traversal/Scope.html) | 
| Scope.global, Scope.local | [org.apache.tinkerpop.gremlin.process.traversal.Scope](https://tinkerpop.apache.org/javadocs/3.7.2/core/org/apache/tinkerpop/gremlin/process/traversal/Scope.html) | 
| all, first, last, mixed | [org.apache.tinkerpop.gremlin.process.traversal.Pop](https://tinkerpop.apache.org/javadocs/3.7.2/core/org/apache/tinkerpop/gremlin/process/traversal/Pop.html) | 
| normSack | [org.apache.tinkerpop.gremlin.process.traversal.SackFunctions.Barrier](https://tinkerpop.apache.org/javadocs/3.7.2/core/org/apache/tinkerpop/gremlin/process/traversal/SackFunctions.Barrier.html) | 
| addAll, and, assign, div, max, min, minus, mult, or, sum, sumLong | [org.apache.tinkerpop.gremlin.process.traversal.Operator](https://tinkerpop.apache.org/javadocs/3.7.2/core/org/apache/tinkerpop/gremlin/process/traversal/Operator.html) | 
| keys, values | [org.apache.tinkerpop.gremlin.structure.Column](https://tinkerpop.apache.org/javadocs/3.7.2/core/org/apache/tinkerpop/gremlin/structure/Column.html) | 
| BOTH, IN, OUT | [org.apache.tinkerpop.gremlin.structure.Direction](https://tinkerpop.apache.org/javadocs/3.7.2/core/org/apache/tinkerpop/gremlin/structure/Direction.html) | 
| any, none | [org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent.Pick](https://tinkerpop.apache.org/javadocs/current/full/org/apache/tinkerpop/gremlin/process/traversal/Pick.html) | 

## Java code
<a name="feature-gremlin-differences-java"></a>

Neptune does not support calls to methods defined by arbitrary Java or Java library calls other than supported Gremlin APIs. For example, `java.lang.*`, `Date()`, and `g.V().tryNext().orElseGet()` are not allowed.

## Properties on elements
<a name="feature-gremlin-differences-properties-on-elements"></a>

 Neptune does not support the `materializeProperties` flag that was introduced in TinkerPop 3.7.0 to return properties on elements. As a result, Neptune will still only return vertices or edges as references with just their `id` and `label`.

## Script execution
<a name="feature-gremlin-differences-script"></a>

All queries must begin with `g`, the traversal object. 

In String query submissions, multiple traversals can be issued separated by a semicolon (`;`) or a newline character (`\n`). To be executed, every statement other than the last must end with an `.iterate()` step. Only the final traversal data is returned. Note that this does not apply to GLV ByteCode query submissions.

## Sessions
<a name="feature-gremlin-differences-sessions"></a>

Sessions in Neptune are limited to only 10 minutes in duration. See [Gremlin script-based sessions](access-graph-gremlin-sessions.md) and the [TinkerPop Session Reference](https://tinkerpop.apache.org/docs/current/reference/#console-sessions) for more information.

## Transactions
<a name="feature-gremlin-differences-transactions"></a>

Neptune opens a new transaction at the beginning of each Gremlin traversal and closes the transaction upon the successful completion of the traversal. The transaction is rolled back when there is an error. 

 Multiple statements separated by a semicolon (`;`) or a newline character (`\n`) are included in a single transaction. Every statement other than the last must end with a `next()` step to be executed. Only the final traversal data is returned.

Manual transaction logic using `tx.commit()` and `tx.rollback()` is not supported.

**Important**  
This ***only*** applies to methods where you send the Gremlin query as a ***text string*** (see [Gremlin transactions](access-graph-gremlin-transactions.md)).

## Vertex and edge IDs
<a name="feature-gremlin-differences-vertex-edge-ids"></a>

Neptune Gremlin Vertex and Edge IDs must be of type `String`. These ID strings support Unicode characters, and cannot exceed 55 MB in size.

User-supplied IDs are supported, but they are optional in normal usage. If you don't provide an ID when you add a vertex or an edge, Neptune generates a UUID and converts it to a string, in a form like this: `"48af8178-50ce-971a-fc41-8c9a954cea62"`. These UUIDs do not conform to the RFC standard, so if you need standard UUIDs you should generate them externally and provide them when you add vertices or edges.

**Note**  
The Neptune `Load` command requires that you provide IDs, using the **\$1id** field in the Neptune CSV format.

## User-supplied IDs
<a name="feature-gremlin-differences-user-supplied-ids"></a>

User-supplied IDs are allowed in Neptune Gremlin with the following stipulations.
+ Supplied IDs are optional.
+ Only vertexes and edges are supported.
+ Only type `String` is supported.

To create a new vertex with a custom ID, use the `property` step with the `id` keyword: `g.addV().property(id, 'customid')`.

**Note**  
 Do not put quotation marks around the `id` keyword. It refers to `T.id`.

All vertex IDs must be unique, and all edge IDs must be unique. However, Neptune does allow a vertex and an edge to have the same ID.

If you try to create a new vertex using the `g.addV()` and a vertex with that ID already exists, the operation fails. The exception to this is if you specify a new label for the vertex, the operation succeeds but adds the new label and any additional properties specified to the existing vertex. Nothing is overwritten. A new vertex is not created. The vertex ID does not change and remains unique.

For example, the following Gremlin Console commands succeed:

```
gremlin> g.addV('label1').property(id, 'customid')
gremlin> g.addV('label2').property(id, 'customid')
gremlin> g.V('customid').label()
==>label1::label2
```

## Vertex property IDs
<a name="feature-gremlin-differences-vertex-property-ids"></a>

Vertex property IDs are generated automatically and can show up as positive or negative numbers when queried.

## Cardinality of vertex properties
<a name="feature-gremlin-differences-vertex-property-cardinality"></a>

Neptune supports set cardinality and single cardinality. If it isn't specified, set cardinality is selected. This means that if you set a property value, it adds a new value to the property, but only if it doesn't already appear in the set of values. This is the Gremlin enumeration value of [Set](https://tinkerpop.apache.org/javadocs/3.7.2/core/org/apache/tinkerpop/gremlin/structure/VertexProperty.Cardinality.html). 

`List` is not supported. For more information about property cardinality, see the [Vertex](https://tinkerpop.apache.org/javadocs/3.7.2/core/org/apache/tinkerpop/gremlin/structure/Vertex.html#property-org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality-java.lang.String-V-java.lang.Object...-) topic in the Gremlin JavaDoc.

## Updating a vertex property
<a name="feature-gremlin-differences-vertex-property-update"></a>

To update a property value without adding an additional value to the set of values, specify `single` cardinality in the `property` step.

```
g.V('exampleid01').property(single, 'age', 25)
```

This removes all existing values for the property.

## Labels
<a name="feature-gremlin-differences-labels"></a>

Neptune supports multiple labels for a vertex. When you create a label, you can specify multiple labels by separating them with `::`. For example, `g.addV("Label1::Label2::Label3")` adds a vertex with three different labels. The `hasLabel` step matches this vertex with any of those three labels: `hasLabel("Label1")`, `hasLabel("Label2")`, and `hasLabel("Label3")`. 

**Important**  
The `::` delimiter is reserved for this use only. You cannot specify multiple labels in the `hasLabel` step. For example, `hasLabel("Label1::Label2")` does not match anything.

## Escape characters
<a name="feature-gremlin-differences-escapes"></a>

Neptune resolves all escape characters as described in the [Escaping Special Characters]( http://groovy-lang.org/syntax.html#_escaping_special_characters) section of the Apache Groovy language documentation.

## Groovy limitations
<a name="feature-gremlin-differences-groovy"></a>

Neptune doesn't support Groovy commands that don't start with `g`. This includes math (for example, `1+1`), system calls (for example, `System.nanoTime()`), and variable definitions (for example, `1+1`).

**Important**  
Neptune does not support fully qualified class names. For example, you must use `single` and not `org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality.single` in your Groovy request.

## Serialization
<a name="feature-gremlin-differences-serialization"></a>

Neptune supports the following serializations based on the requested MIME type.

 Neptune exposes all of the serializers that TinkerPop does, with support for the various versions and configurations of GraphSON and GraphBinary. Despite there being many options present, the guidance for which to use is straightforward: 
+  If you are using Apache TinkerPop drivers, prefer the default for the driver without specifying one explicitly. Unless you have a very specific reason for doing so, you likely don’t need to specify the serializer in your driver initialization. In general, the default used by the drivers is `application/vnd.graphbinary-v1.0`. 
+  If you are connecting to Neptune over HTTP, prioritize the use of `application/vnd.gremlin-v3.0+json;types=false` as the embedded types in the alternative version of GraphSON 3 make it complicated to work with. 
+  The `application/vnd.graphbinary-v1.0-stringd` is generally only useful when used in conjunction with [Gremlin Console](https://docs.aws.amazon.com//neptune/latest/userguide/access-graph-gremlin-console.html) as it converts all results to a string representation for simple display. 
+  The remaining formats remain present for legacy reasons and should typically not be used with drivers without clear cause. 

|  |  |  | 
| --- |--- |--- |
| MIME type | Serialization | Configuration | 
| `application/vnd.gremlin-v1.0+json` | GraphSONMessageSerializerV1 | ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV1] | 
| `application/vnd.gremlin-v1.0+json;types=false` | GraphSONUntypedMessageSerializerV1 | ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV1] | 
| `application/vnd.gremlin-v2.0+json` | GraphSONMessageSerializerV2 | ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2] | 
| `application/vnd.gremlin-v2.0+json;types=false` | GraphSONUntypedMessageSerializerV2 | ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2] | 
| `application/vnd.gremlin-v3.0+json` | GraphSONMessageSerializerV3 | ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3] | 
| `application/vnd.gremlin-v3.0+json;types=false` | GraphSONUntypedMessageSerializerV3 | ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3] | 
| `application/json` | GraphSONUntypedMessageSerializerV3 | ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV1] | 
| `application/vnd.graphbinary-v1.0` | GraphBinaryMessageSerializerV1 |  | 
| `application/vnd.graphbinary-v1.0-stringd` | GraphBinaryMessageSerializerV1 | serializeResultToString: true | 
| `application/vnd.gremlin-v1.0+json` | GraphSONMessageSerializerGremlinV1 | ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV1] | 
| `application/vnd.gremlin-v2.0+json` | GraphSONMessageSerializerV2   (only works with WebSockets) | ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2] | 
| `application/vnd.gremlin-v3.0+json` | `GraphSONMessageSerializerV3` |  | 
| `application/json` | GraphSONMessageSerializerV3 | ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3] | 
| `application/vnd.graphbinary-v1.0` | GraphBinaryMessageSerializerV1 |  | 

**Note**  
 The serializer table shown here refers to naming as of TinkerPop 3.7.0. If you would like to know more about this change, please see the [TinkerPop upgrade documentation](https://tinkerpop.apache.org/docs/current/upgrade/#_serializer_renaming). Gryo serialization support was deprecated in 3.4.3 and was officially removed in 3.6.0. If you are explicitly using Gryo or on a driver version that uses it by default, then you should switch to GraphBinary or upgrade your driver. 

## Lambda steps
<a name="feature-gremlin-differences-lambda"></a>

Neptune does not support Lambda Steps.

## Unsupported Gremlin methods
<a name="feature-gremlin-differences-unsupported-methods"></a>

Neptune does not support the following Gremlin methods:
+ `org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal.program(org.apache.tinkerpop.gremlin.process.computer.VertexProgram)`
+ `org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal.sideEffect(java.util.function.Consumer)`
+ `org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal.from(org.apache.tinkerpop.gremlin.structure.Vertex)`
+ `org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal.to(org.apache.tinkerpop.gremlin.structure.Vertex)`

For example, the following traversal is not allowed: `g.V().addE('something').from(__.V().next()).to(__.V().next())`.

**Important**  
This ***only*** applies to methods where you send the Gremlin query as a ***text string***.

## Unsupported Gremlin steps
<a name="feature-gremlin-differences-unsupported-steps"></a>

Neptune does not support the following Gremlin steps:
+ The Gremlin [io( ) Step](http://tinkerpop.apache.org/docs/3.7.2/reference/#io-step) is only partially supported in Neptune. It can be used in a read context, as in `g.io((url)).read()`, but not to write.

## Gremlin graph features in Neptune
<a name="gremlin-api-reference-features"></a>

The Neptune implementation of Gremlin does not expose the `graph` object. The following tables list Gremlin features and indicate whether or not Neptune supports them.

### Neptune support for `graph` features
<a name="gremlin-api-graph-features"></a>

The Neptune graph features, where supported, are the same as would be returned by the `graph.features()` command.


| 
| 
| Graph feature | Enabled? | 
| --- |--- |
| Transactions |  true | 
| ThreadedTransactions |  false | 
| Computer |  false | 
| Persistence |  true | 
| ConcurrentAccess |  true | 

### Neptune support for variable features
<a name="gremlin-api-variable-features"></a>


| 
| 
| Variable feature | Enabled? | 
| --- |--- |
| Variables |  false | 
| SerializableValues |  false | 
| UniformListValues |  false | 
| BooleanArrayValues |  false | 
| DoubleArrayValues |  false | 
| IntegerArrayValues |  false | 
| StringArrayValues |  false | 
| BooleanValues |  false | 
| ByteValues |  false | 
| DoubleValues |  false | 
| FloatValues |  false | 
| IntegerValues |  false | 
| LongValues |  false | 
| MapValues |  false | 
| MixedListValues |  false | 
| StringValues |  false | 
| ByteArrayValues |  false | 
| FloatArrayValues |  false | 
| LongArrayValues |  false | 

### Neptune support for vertex features
<a name="gremlin-api-vertex-features"></a>


| 
| 
| Vertex feature | Enabled? | 
| --- |--- |
| MetaProperties |  false | 
| DuplicateMultiProperties |  false | 
| AddVertices |  true | 
| RemoveVertices |  true | 
| MultiProperties |  true | 
| UserSuppliedIds |  true | 
| AddProperty |  true | 
| RemoveProperty |  true | 
| NumericIds |  false | 
| StringIds |  true | 
| UuidIds |  false | 
| CustomIds |  false | 
| AnyIds |  false | 

### Neptune support for vertex property features
<a name="gremlin-api-vertex-property-features"></a>


| 
| 
| Vertex property feature | Enabled? | 
| --- |--- |
| UserSuppliedIds |  false | 
| AddProperty |  true | 
| RemoveProperty |  true | 
| NumericIds |  true | 
| StringIds |  true | 
| UuidIds |  false | 
| CustomIds |  false | 
| AnyIds |  false | 
| Properties |  true | 
| SerializableValues |  false | 
|  UniformListValues |  false | 
| BooleanArrayValues |  false | 
| DoubleArrayValues |  false | 
| IntegerArrayValues |  false | 
| StringArrayValues |  false | 
| BooleanValues |  true | 
| ByteValues |  true | 
| DoubleValues |  true | 
| FloatValues |  true | 
| IntegerValues |  true | 
| LongValues |  true | 
| MapValues |  false | 
| MixedListValues |  false | 
| StringValues |  true | 
| ByteArrayValues |  false | 
| FloatArrayValues |  false | 
| LongArrayValues |  false | 

### Neptune support for edge features
<a name="gremlin-api-edge-features"></a>


| 
| 
| Edge feature | Enabled? | 
| --- |--- |
| AddEdges |  true | 
| RemoveEdges |  true | 
| UserSuppliedIds |  true | 
| AddProperty |  true | 
| RemoveProperty |  true | 
| NumericIds |  false | 
| StringIds |  true | 
| UuidIds |  false | 
| CustomIds |  false | 
| AnyIds |  false | 

### Neptune support for edge property features
<a name="gremlin-api-edge-property-features"></a>


| 
| 
| Edge property feature | Enabled? | 
| --- |--- |
| Properties |  true | 
| SerializableValues |  false | 
| UniformListValues |  false | 
| BooleanArrayValues |  false | 
| DoubleArrayValues |  false | 
| IntegerArrayValues |  false | 
| StringArrayValues |  false | 
| BooleanValues |  true | 
| ByteValues |  true | 
| DoubleValues |  true | 
| FloatValues |  true | 
| IntegerValues |  true | 
| LongValues |  true | 
| MapValues |  false | 
| MixedListValues |  false | 
| StringValues |  true | 
| ByteArrayValues |  false | 
| FloatArrayValues |  false | 
| LongArrayValues |  false | 

# SPARQL standards compliance in Amazon Neptune
<a name="feature-sparql-compliance"></a>

After listing applicable SPARQL standards, the following sections provide specific details about how Neptune's SPARQL implementation extends or diverges from those standards.

**Topics**
+ [Applicable Standards for SPARQL](#feature-sparql-applicable-standards)
+ [Default Namespace Prefixes in Neptune SPARQL](#sparql-default-prefixes)
+ [SPARQL Default Graph and Named Graphs](#sparql-default-graph)
+ [SPARQL XPath Constructor Functions Supported by Neptune](#access-graph-sparql-xpath-constructors)
+ [Default base IRI for queries and updates](#opencypher-compliance-default-iri)
+ [xsd:dateTime Values in Neptune](#access-graph-sparql-xsd-date-time)
+ [Neptune Handling of Special Floating Point Values](#feature-overview-special-values-comparisons)
+ [Neptune Limitation of Arbitrary-Length Values](#feature-overview-arbitrary-length-values)
+ [Neptune Extends Equals Comparison in SPARQL](#feature-overview-sparql-not-equal)
+ [Handling of Out-of-Range Literals in Neptune SPARQL](#feature-overview-sparql-out-of-range)

Amazon Neptune complies with the following standards in implementing the SPARQL graph query language.

## Applicable Standards for SPARQL
<a name="feature-sparql-applicable-standards"></a>
+ SPARQL is defined by the W3C [SPARQL 1.1 Query Language](https://www.w3.org/TR/sparql11-query/) recommendation of March 21, 2013.
+ The SPARQL Update protocol and query language are defined by the W3C [SPARQL 1.1 Update](https://www.w3.org/TR/sparql11-update/) specification.
+ For numeric formats, SPARQL follows the [W3C XML Schema Definition Language (XSD) 1.1 Part 2: Datatypes](https://www.w3.org/TR/xmlschema11-2/) specification, which is consistent with the IEEE 754 specification ([IEEE 754-2019 - IEEE Standard for Floating-Point Arithmetic](https://standards.ieee.org/content/ieee-standards/en/standard/754-2019.html). For more information, see also the [Wikipedia IEEE 754 page](https://en.wikipedia.org/wiki/IEEE_754)). However, features that were introduced after the `IEEE 754-1985` version are not included in the specification.

## Default Namespace Prefixes in Neptune SPARQL
<a name="sparql-default-prefixes"></a>

Neptune defines the following prefixes by default for use in SPARQL queries. For more information, see [Prefixed Names](https://www.w3.org/TR/sparql11-query/#prefNames) in the SPARQL specification.
+ `rdf`  – `http://www.w3.org/1999/02/22-rdf-syntax-ns#`
+ `rdfs` – `http://www.w3.org/2000/01/rdf-schema#`
+ `owl`  – `http://www.w3.org/2002/07/owl#`
+ `xsd`  – `http://www.w3.org/2001/XMLSchema#`

## SPARQL Default Graph and Named Graphs
<a name="sparql-default-graph"></a>

Amazon Neptune associates every triple with a named graph. The default graph is defined as the union of all named graphs. 

**Default Graph for Queries**  
If you submit a SPARQL query without explicitly specifying a graph via the `GRAPH` keyword or constructs such as `FROM NAMED`, Neptune always considers all triples in your DB instance. For example, the following query returns all triples from a Neptune SPARQL endpoint: 

`SELECT * WHERE { ?s ?p ?o }`

Triples that appear in more than one graph are returned only once.

For information about the default graph specification, see the [RDF Dataset](https://www.w3.org/TR/sparql11-query/#rdfDataset) section of the SPARQL 1.1 Query Language specification.

**Specifying the Named Graph for Loading, Inserts, or Updates**  
If you don't specify a named graph when loading, inserting, or updating triples, Neptune uses the fallback named graph defined by the URI `http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph`.

When you issue a Neptune `Load` request using a triple-based format, you can specify the named graph to use for all triples by using the `parserConfiguration: namedGraphUri` parameter. For information about the `Load` command syntax, see [Neptune Loader Command](load-api-reference-load.md).

**Important**  
 If you don't use this parameter, and you don't specify a named graph, the fallback URI is used: `http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph`.

This fallback named graph is also used if you load triples via `SPARQL UPDATE` without explicitly providing a named graph target.

You can use the quads-based format N-Quads to specify a named graph for each triple in the database. 

**Note**  
Using N-Quads allows you to leave the named graph blank. In this case, `http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph` is used.  
You can override the default named graph for N-Quads using the `namedGraphUri` parser configuration option.

## SPARQL XPath Constructor Functions Supported by Neptune
<a name="access-graph-sparql-xpath-constructors"></a>

The SPARQL standard allows SPARQL engines to support an extensible set of XPath constructor functions. Neptune currently supports the following constructor functions, where the `xsd` prefix is defined as `http://www.w3.org/2001/XMLSchema#`:
+ `xsd:boolean`
+ `xsd:integer`
+ `xsd:double`
+ `xsd:float`
+ `xsd:decimal`
+ `xsd:long`
+ `xsd:unsignedLong`

## Default base IRI for queries and updates
<a name="opencypher-compliance-default-iri"></a>

Because a Neptune cluster has several different endpoints, using the request URL of a query or update as the base IRI could lead to unexpected results when resolving relative IRIs.

As of [engine release 1.2.1.0](engine-releases-1.2.1.0.md), Neptune uses `http://aws.amazon.com/neptune/default/` as the base IRI if an explicit base IRI is not part of the request.

In the following request, the base IRI is part of the request:

```
BASE <http://example.org/default/>
INSERT DATA { <node1> <id> "n1" }

BASE <http://example.org/default/>
SELECT * { <node1> ?p ?o }
```

And the result would be:

```
?p                                                   ?o
http://example.org/default/id                        n1
```

In this request, however, no base IRI is included:

```
INSERT DATA { <node1> <id> "n1" }

SELECT * { <node1> ?p ?o }
```

In that case, the result would be:

```
?p                                                   ?o
http://aws.amazon.com/neptune/default/id             n1
```

## xsd:dateTime Values in Neptune
<a name="access-graph-sparql-xsd-date-time"></a>

For performance reasons, Neptune always stores date/time values as Coordinated Universal Time (UTC). This makes direct comparisons very efficient.

This also means that if you enter a `dateTime` value that specifies a particular time zone, Neptune translates the value to UTC and discards that time-zone information. Then, when you retrieve the `dateTime` value later, it is expressed in UTC, not the time of the original time zone, and you can no longer tell what that original time zone was.

## Neptune Handling of Special Floating Point Values
<a name="feature-overview-special-values-comparisons"></a>

Neptune handles special floating-point values in SPARQL as follows.

### SPARQL NaN Handling in Neptune
<a name="feature-overview-NaN-comparisons"></a>

In Neptune, SPARQL can accept a value of `NaN` in a query. No distinction is made between signaling and quiet `NaN` values. Neptune treats all `NaN` values as quiet.

Semantically, no comparison of a `NaN` is possible, because nothing is greater than, less than, or equal to a `NaN`. This means that a value of `NaN` on one side of a comparison in theory never matches *anything* on the other side.

 However, the [XSD specification](https://www.w3.org/TR/xmlschema-2/#double) does treat two `xsd:double` or `xsd:float` `NaN` values as equal. Neptune follows this for the `IN` filter, for the equal operator in filter expressions, and for exact match semantics (having a `NaN` in the object position of a triple pattern).

### SPARQL Infinite Value Handling in Neptune
<a name="feature-overview-infinity-comparisons"></a>

In Neptune, SPARQL can accept a value of `INF` or `-INF` in a query. `INF` compares as greater than any other numeric value, and `-INF` compares as less than any other numeric value.

Two INF values with matching signs compare as equal to each other regardless of their type (for example, a float `-INF` compares as equal to a double `-INF`).

Of course, no comparison with a `NaN` is possible because nothing is greater than, less than, or equal to a `NaN`.

### SPARQL Negative Zero Handling in Neptune
<a name="feature-overview-zero-comparisons"></a>

Neptune normalizes a negative zero value to an unsigned zero. You can use negative zero values in a query, but they aren't recorded as such in the database, and they compare as equal to unsigned zeros.

## Neptune Limitation of Arbitrary-Length Values
<a name="feature-overview-arbitrary-length-values"></a>

Neptune limits the storage size of XSD integer, floating point, and decimal values in SPARQL to 64 bits. Using larger values results in an `InvalidNumericDataException` error.

## Neptune Extends Equals Comparison in SPARQL
<a name="feature-overview-sparql-not-equal"></a>

The SPARQL standard defines a ternary logic for value expressions, where a value expression can either evaluate to `true`, `false`, or `error`. The default semantics for term equality as defined in the [SPARQL 1.1 specification](https://www.w3.org/TR/sparql11-query/#func-RDFterm-equal)), which applies to `=` and `!=` comparisons in `FILTER` conditions, produces an `error` when comparing data types that are not explicitly comparable in the [operators table](https://www.w3.org/TR/sparql11-query/#OperatorMapping) in the specification.

This behavior can lead to unintuitive results, as in the following example.

Data:

```
<http://example.com/Server/1> <http://example.com/ip> "127.0.0.1"^^<http://example.com/datatype/IPAddress>
```

Query 1:

```
SELECT * WHERE {
    <http://example.com/Server/1> <http://example.com/ip> ?o .
    FILTER(?o = "127.0.0.2"^^<http://example.com/datatype/IPAddress>)
}
```

Query 2:

```
SELECT * WHERE {
    <http://example.com/Server/1> <http://example.com/ip> ?o .
    FILTER(?o != "127.0.0.2"^^<http://example.com/datatype/IPAddress>)
}
```

With the default SPARQL semantics that Neptune used before release 1.0.2.1, both queries would return the empty result. The reason is that `?o = "127.0.0.2"^^<http://example.com/IPAddress>` when evaluated for `?o := "127.0.0.1"^^<http://example.com/IPAddress>` produces an `error` rather than `false` because there are no explicit comparison rules specified for the custom data type `<http://example.com/IPAddress>`. As a result, the negated version in the second query also produces an `error`. In both queries, the `error` causes the candidate solution to be filtered out.

Starting with release 1.0.2.1, Neptune has extended the SPARQL inequality operator in accord with the specification. See the [SPARQL 1.1 section on operator extensibility](https://www.w3.org/TR/sparql11-query/#operatorExtensibility), which allows engines to define additional rules on how to compare across user-defined and non-comparable built-in data types.

Using this option, Neptune now treats a comparison of any two data types that is not explicitly defined in the operator-mapping table as evaluating to `true` if the literal values and data types are syntactically equal, and false otherwise. An `error` is not produced in any case.

Using these new semantics, the second query would return `"127.0.0.1"^^<http://example.com/IPAddress>` instead of an empty result.

## Handling of Out-of-Range Literals in Neptune SPARQL
<a name="feature-overview-sparql-out-of-range"></a>

XSD semantics define each numeric type with its value space, except for `integer` and `decimal`. These definitions limit each type to a range of values. For example, the range of an `xsd:byte` range is from -128 to \$1127, inclusive. Any value outside of this range is considered invalid.

If you try to assign a literal value outside of the value space of a type (for example, if you try to set an `xsd:byte` to a literal value of 999), Neptune accepts the out-of-range value as-is, without rounding or truncating it. But it doesn't persist it as a numeric value because the given type can't represent it.

That is, Neptune accepts `"999"^^xsd:byte` even though it is a value outside of the defined `xsd:byte` value range. However, after the value is persisted in the database, it can only be used in exact match semantics, in an object position of a triple pattern. No range filter can be executed on it because out-of-range literals are not treated as numeric values.

The SPARQL 1.1 specification defines [range operators](https://www.w3.org/TR/sparql11-query/#OperatorMapping) in the form `numeric`*-operator-*`numeric`, `string`*-operator-*`string`, `literal`*-operator-*`literal`, and so forth. Neptune can't execute a range comparison operator anything like `invalid-literal`*-operator-*`numeric-value`.

# openCypher specification compliance in Amazon Neptune
<a name="feature-opencypher-compliance"></a>

The Amazon Neptune release of openCypher generally supports the clauses, operators, expressions, functions, and syntax defined in the by the current openCypher specification, which is the [Cypher Query Language Reference Version 9](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf). Limitations and differences in Neptune support for openCypher are called out below.

 Amazon Neptune also supports several features beyond the scope of the openCypher specification. Refer to [openCypher extensions in Amazon Neptune](access-graph-opencypher-extensions.md) for details. 

**Note**  
The current Neo4j implementation of Cypher contains functionality that is not contained in the openCypher specification mentioned above. If you are migrating current Cypher code to Neptune, see [Neptune compatibility with Neo4j](migration-compatibility.md) and [Rewriting Cypher queries to run in openCypher on Neptune](migration-opencypher-rewrites.md) for more information.

## Support for openCypher clauses in Neptune
<a name="opencypher-compliance-clauses"></a>

Neptune supports the following clauses, except as noted:
+ `MATCH`   –   Supported, except that *`shortestPath()`* and *`allShortestPaths()`* are not currently supported.
+ `OPTIONAL MATCH`
+ *`MANDATORY MATCH`*   –   is **not** currently supported in Neptune. Neptune does, however, support [custom ID values](access-graph-opencypher-extensions.md#opencypher-compliance-custom-ids) in `MATCH` queries.
+ `RETURN`   –   Supported, except when used with non-static values for `SKIP` or `LIMIT`. For example, the following currently does not work:

  ```
  MATCH (n)
  RETURN n LIMIT toInteger(rand())    // Does NOT work!
  ```
+ `WITH`   –   Supported, except when used with non-static values for `SKIP` or `LIMIT`. For example, the following currently does not work:

  ```
  MATCH (n)
  WITH n SKIP toInteger(rand())
  WITH count() AS count
  RETURN count > 0 AS nonEmpty    // Does NOT work!
  ```
+ `UNWIND`
+ `WHERE`
+ `ORDER BY`
+ `SKIP`
+ `LIMIT`
+ `CREATE`   –   Neptune lets you create [custom ID values](access-graph-opencypher-extensions.md#opencypher-compliance-custom-ids) in `CREATE` queries.
+ `DELETE`
+ `SET`
+ `REMOVE`
+ `MERGE`   –   Neptune supports [custom ID values](access-graph-opencypher-extensions.md#opencypher-compliance-custom-ids) in `MERGE` queries.
+ *`CALL[YIELD...]`*   –   is **not** currently supported in Neptune.
+ `UNION, UNION ALL`   –   read-only queries are supported, but mutation queries are **not** currently supported.
+  `USING`   –   `USING` is supported from engine version [1.3.2.0](https://docs.aws.amazon.com//neptune/latest/userguide/engine-releases-1.3.2.0.html). See [Query hints](https://docs.aws.amazon.com//neptune/latest/userguide/opencypher-query-hints.html) for more information. 

## Support for openCypher operators in Neptune
<a name="opencypher-compliance-operators"></a>

Neptune supports the following operators, except as noted:

**General operators**
+ `DISTINCT`
+ The `.` operator for accessing properties of a nested literal map.

**Mathematical operators**
+ The `+` addition operator.
+ The `-` subtraction operator.
+ The `*` multiplication operator.
+ The `/` division operator.
+ The `%` modulo division operator.
+ The `^` exponentiation operator *is NOT supported*.

**Comparison operators**
+ The `=` addition operator.
+ The `<>` inequality operator.
+ The `<` less-than operator is supported except when either of the arguments is a Path, List, or Map.
+ The `>` greater-than operator is supported except when either of the arguments is a Path, List, or Map.
+ The `<=` less-than-or-equal-to operator is supported except when either of the arguments is a Path, List, or Map.
+ The `>=` greater-than-or-equal-to operator is supported except when either of the arguments is a Path, List, or Map.
+ `IS NULL`
+ `IS NOT NULL`
+ `STARTS WITH` is supported if the data being searched for is a string.
+ `ENDS WITH` is supported if the data being searched for is a string.
+ `CONTAINS` is supported if the data being searched for is a string.

**Boolean operators**
+ `AND`
+ `OR`
+ `XOR`
+ `NOT`

**String operators**
+ The `+` concatenation operator.

**List operators**
+ The `+` concatenation operator.
+ `IN` (checks for the presence of an item in the list)

## Support for openCypher expressions in Neptune
<a name="opencypher-compliance-expressions"></a>

Neptune supports the following expressions, except as noted:
+ `CASE`
+ The `[]` expression is is **not** currently supported in Neptune for accessing dynamically computed property keys within a node, relationship, or map. For example, the following does not work:

  ```
  MATCH (n)
  WITH [5, n, {key: 'value'}] AS list
  RETURN list[1].name
  ```

## Support for openCypher functions in Neptune
<a name="opencypher-compliance-functions"></a>

Neptune supports the following functions, except as noted:

**Predicate functions**
+ `exists()`

**Scalar functions**
+ `coalesce()`
+ `endNode()`
+ `epochmillis()`
+ `head()`
+ `id()`
+ `last()`
+ `length()`
+ `randomUUID()`
+ `properties()`
+ `removeKeyFromMap`
+ `size()`   –   this overloaded method currently only works for pattern expressions, lists, and strings
+ `startNode()`
+ `timestamp()`
+ `toBoolean()`
+ `toFloat()`
+ `toInteger()`
+ `type()`

**Aggregating functions**
+ `avg()`
+ `collect()`
+ `count()`
+ `max()`
+ `min()`
+ `percentileDisc()`
+ `stDev()`
+ `percentileCont()`
+ `stDevP()`
+ `sum()`

**List functions**
+ [`join()`](access-graph-opencypher-extensions.md#opencypher-compliance-join-function) (concatenates strings in a list into a single string)
+ `keys()`
+ `labels()`
+ `nodes()`
+ `range()`
+ `relationships()`
+ `reverse()`
+ `tail()`

**Mathematical functions – numeric**
+ `abs()`
+ `ceil()`
+ `floor()`
+ `rand()`
+ `round()`
+ `sign()`

**Mathematical functions – logarithmic**
+ `e()`
+ `exp()`
+ `log()`
+ `log10()`
+ `sqrt()`

**Mathematical functions – trigonometric**
+ `acos()`
+ `asin()`
+ `atan()`
+ `atan2()`
+ `cos()`
+ `cot()`
+ `degrees()`
+ `pi()`
+ `radians()`
+ `sin()`
+ `tan()`

**String functions**
+ [`join()`](access-graph-opencypher-extensions.md#opencypher-compliance-join-function) (concatenates strings in a list into a single string)
+ `left()`
+ `lTrim()`
+ `replace()`
+ `reverse()`
+ `right()`
+ `rTrim()`
+ `split()`
+ `substring()`
+ `toLower()`
+ `toString()`
+ `toUpper()`
+ `trim()`

**User-defined functions**

*User-defined functions* are **not** currently supported in Neptune.

## Neptune-specific openCypher implementation details
<a name="opencypher-compliance-differences"></a>

The following sections describe ways in which the Neptune implementation of openCypher may differ from or go beyond the [openCypher spec](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf).

### Variable-length path (VLP) evaluations in Neptune
<a name="opencypher-compliance-differences-vlp"></a>

Variable length path (`VLP`) evaluations discover paths between nodes in the graph. Path length can be unrestricted in a query. To prevent cycles, the [openCypher spec](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf) specifies that each edge must be traversed at most once per solution.

For VLPs, the Neptune implementation deviates from the openCypher spec in that it only supports constant values for property equality filters. Take the following query:

```
MATCH (x)-[:route*1..2 {dist:33, code:x.name}]->(y) return x,y
```

Because the `x.name` property equality filter value is a not a constant, this query results in an `UnsupportedOperationException` with the message: `Property predicate over variable-length relationships with non-constant expression is not supported in this release.`

### Temporal support in the Neptune openCypher implementation (Neptune database 1.3.1.0 and below)
<a name="opencypher-compliance-time"></a>

Neptune currently provides limited support for temporal function in openCypher. It supports the `DateTime` data type for temporal types.

The `datetime()` function can be used to get the current UTC date and time like this:

```
RETURN  datetime() as res
```

Date and time values can be parsed from strings in a `"`*date*`T`*time*`"` format where *date* and *time* are both expressed in one of the supported forms below:

**Supported date formats**
+ `yyyy-MM-dd`
+ `yyyyMMdd`
+ `yyyy-MM`
+ `yyyy-DDD`
+ `yyyyDDD`
+ `yyyy`

**Supported time formats**
+ `HH:mm:ssZ`
+ `HHmmssZ`
+ `HH:mm:ssZ`
+ `HH:mmZ`
+ `HHmmZ`
+ `HHZ`
+ `HHmmss`
+ `HH:mm:ss`
+ `HH:mm`
+ `HHmm`
+ `HH`

For example:

```
RETURN datetime('2022-01-01T00:01')      // or another example:
RETURN datetime('2022T0001')
```

Note that all date/time values in Neptune openCypher are stored and retrieved as UTC values.

Neptune openCypher uses a `statement` clock, meaning that the same instant in time is used throughout the duration of a query. A different query within the same transaction may use a different instant in time.

Neptune doesn't support use of a function within a call to `datetime()`. For example, the following won't work:

```
CREATE (:n {date:datetime(tostring(2021))})  // ---> NOT ALLOWED!
```

Neptune does support the `epochmillis()` function that converts a `datetime` to `epochmillis`. For example:

```
MATCH (n) RETURN epochMillis(n.someDateTime)
1698972364782
```

Neptune doesn't currently support other functions and operations on `DateTime` objects, such as addition and subtraction.

### Temporal support in the Neptune openCypher implementation (Neptune Analytics and Neptune Database 1.3.2.0 and above)
<a name="opencypher-compliance-time-na"></a>

The following datetime functionality for OpenCypher applies to Neptune Analytics. Alternatively, you can use the labmode parameter `DatetimeMillisecond=enabled` for enabling the following datetime functionality on Neptune engine release version 1.3.2.0 and above. For more details about using this functionality in labmode, see [Extended datetime support](features-lab-mode.md#labmode-extended-datetime-support).
+ Support for milliseconds. Datetime literal will always be returned with milliseconds, even if milliseconds is 0. (Previous behavior was to truncate milliseconds.)

  ```
  CREATE (:event {time: datetime('2024-04-01T23:59:59Z')})
  
  # Returning the date returns with 000 suffixed representing milliseconds
  MATCH(n:event)
  RETURN n.time as datetime
  
  {
    "results" : [ {
      "n" : {
        "~id" : "0fe88f7f-a9d9-470a-bbf2-fd6dd5bf1a7d",
        "~entityType" : "node",
        "~labels" : [ "event" ],
        "~properties" : {
          "time" : "2024-04-01T23:59:59.000Z"
        }
      }
    } ]
  }
  ```
+ Support for calling the datetime() function over stored properties or intermediate results. For example, the following queries were not possible prior to this feature.

  Datetime() over properties:

  ```
  // Create node with property 'time' stored as string
  CREATE (:event {time: '2024-04-01T23:59:59Z'})
  
  // Match and return this property as datetime
  MATCH(n:event)
  RETURN datetime(n.time) as datetime
  ```

  Datetime() over intermediate results:

  ```
  // Parse datetime from parameter
  UNWIND $list as myDate
  RETURN datetime(myDate) as d
  ```
+ It is now also possible to save datetime perperties that are created the in cases mentioned above.

  Saving datetime from the string property of one property to another:

  ```
  // Create node with property 'time' stored as string
  CREATE (:event {time: '2024-04-01T23:59:59Z', name: 'crash'})
  
  // Match and update the same property to datetime type
  MATCH(n:event {name: 'crash'})
  SET n.time = datetime(n.time)
  
  // Match and update another node's property
  MATCH(e:event {name: 'crash'})
  MATCH(n:server {name: e.servername})
  SET n.time = datetime(e.time)
  ```

  Batch create nodes from a parameter with a datetime property:

  ```
  // Batch create from parameter
  UNWIND $list as events
  CREATE (n:crash) {time: datetime(events.time)}
  // Parameter value
  {
    "x":[
      {"time":"2024-01-01T23:59:29", "name":"crash1"},
      {"time":"2023-01-01T00:00:00Z", "name":"crash2"}
    ]
  }
  ```
+ Support for a larger subset of ISO8601 datetime formats. See below.

Supported formats

 The format of a datetime value is [Date]T[Time][Timezone], where T is the separator. If an explicit timezone is not provided, UTC (Z) is assumed to be the default. 

Timezone

Supported timezone formats are:
+ \$1/-HH:mm
+ \$1/-HHmm
+ \$1/-HH

 The presence of a timezone in a datetime string is optional. In case the timezone offset is 0, Z can be used instead of the timezone postfix above to indicate UTC time. The supported range of a timezone is from -14:00 to \$114:00. 

Date

If no timezone is present, or the timezone is UTC (Z), the supported date formats are as follows:

**Note**  
DDD refers to an ordinal date, which represents a day of the year from 001 to 365 (366 in leap years). For example, 2024-002 represents Jan 2, 2024.
+ `yyyy-MM-dd`
+ `yyyyMMdd`
+ `yyyy-MM`
+ `yyyyMM`
+ `yyyy-DDD`
+ `yyyyDDD`
+ `yyyy`

If a timezone other than Z is chosen, the supported date formats are limited to the following:
+ `yyyy-MM-dd`
+ `yyyy-DDD`
+ `yyyyDDD`

The supported range for dates is from 1400-01-01 to 9999-12-31.

Time

If no timezaone is present, or the timezone is UTC (Z), the supported time formats are:
+ `HH:mm:ss.SSS`
+ `HH:mm:ss`
+ `HHmmss.SSS`
+ `HHmmss`
+ `HH:mm`
+ `HHmm`
+ `HH`

If a timezone other than Z is chosen, the supported time formats are limited to the following:
+ `HH:mm:ss`
+ `HH:mm:ss.SSS`

### Differences in Neptune openCypher language semantics
<a name="opencypher-compliance-semantics"></a>

Neptune represents node and relationship IDs as strings rather than integers. The ID equals the ID supplied via the data loader. If there is a namespace for the column, the namespace plus the ID. Consequently, the `id` function returns a string instead of an integer.

The `INTEGER` datatype is limited to 64 bits. When converting larger floating point or string values to an integer using the `TOINTEGER` function, negative values are truncated to `LLONG_MIN` and positive values are truncated to `LLONG_MAX`.

For example:

```
RETURN TOINTEGER(2^100)
>  9223372036854775807

RETURN TOINTEGER(-1 * 2^100)
>  -9223372036854775808
```

### Multi-valued properties
<a name="openCypher-compliance-mvp"></a>

 Although openCypher CREATE does not create multi-valued properties, they can exist in data created using Gremlin (Neptune Database) or when loading data (Neptune Database and Neptune Analytics). If Neptune openCypher encounters a multi-value property, one of the values is arbitrarily chosen, creating a non-deterministic result. 

### Handling of NaN valuse
<a name="openCypher-compliance-handling-nan"></a>

 Neptune’s handling of the comparison of `NaN` property values is undefined. Relying on such comparisons may result in unexpected or non-deterministic results. 