diff --git a/docs/administration-guide/gaffer-deployment/gremlin.md b/docs/administration-guide/gaffer-deployment/gremlin.md
index e21bee5184..c022ced415 100644
--- a/docs/administration-guide/gaffer-deployment/gremlin.md
+++ b/docs/administration-guide/gaffer-deployment/gremlin.md
@@ -1,15 +1,22 @@
-# Connecting Gremlin to Gaffer
+# Using Gremlin in Gaffer
It is possible to use Gremlin as an alternative querying language in Gaffer. To
make Gremlin available however, there are some additional steps that need to be
-taken to connect to a Gaffer graph via this interface.
+taken to ensure it is setup correctly.
## Overview
Gremlin serves as a query layer for a graph that implements the Tinkerpop graph
-structure. As of v2.1.0 Gaffer has made available a library that can be utilised
-to enable Gremlin queries. This library can be included via maven in any project
-using the following dependency definition:
+structure. As of v2.3.0 Gremlin is in the [Gaffer REST API](./gaffer-docker/gaffer-images.md)
+which provides a Websocket based traversal source similar to using a normal
+[Gremlin server](https://tinkerpop.apache.org/docs/current/reference/#connecting-gremlin-server).
+This is the recommended approach and the easiest way to start using Gremlin on
+Gaffer.
+
+If you wish to connect via the Java API, you can utilise the underlying
+'GafferPop' library that can be utilised to enable Gremlin queries. This
+library can be included via maven in any project using the following dependency
+definition:
```xml
@@ -19,193 +26,65 @@ using the following dependency definition:
```
-The library contains the graph implementation that allows Tinkerpop to talk to a
-Gaffer graph and generally is all that is needed to provide the functionality.
-To actually utilise Gremlin queries however, a connection to what's known as a
-`GraphTraversalSource` is required which is the class from which Gremlin
-traversals are spawned. To do this we recommend utilising the provided
-[Gremlin server framework](https://tinkerpop.apache.org/docs/current/reference/#connecting-gremlin-server)
-which can be configured to use the Gaffer Tinkerpop implementation so that a
-endpoint is available for Gremlin queries.
-
-## Connecting to An Existing Accumulo Backed Graph
+Both methods (REST API and Java API) utilise the same library that allows
+Tinkerpop to talk to a Gaffer graph. To actually spawn a Gremlin query a
+reference to a `GraphTraversalSource` is required, the following sections
+outline how to obtain this reference using the REST API.
-The recommended way to provide a Gremlin interface to an existing Gaffer
-instance is to connect directly to the same [Accumulo store](../gaffer-stores/accumulo-store.md).
-Connecting this way means Gremlin communicates in a similar way to the Gaffer
-REST API and ensures the fastest performance when using Gremlin (there may still
-be a performance hit).
-
-!!! note
- It is possible to attach to other store types in a similar manner usually through
- a [proxy store](../gaffer-stores/proxy-store.md) or [federated store](../gaffer-stores/federated-store.md).
-
-The general connection diagram looks something like the following:
-
-```mermaid
-flowchart LR
- A(["User"])
- --> B("Gremlin Server")
- --> C("Accumulo Store")
-```
+## Connecting Gremlin
-To establish this connection you can make use of the existing `gaffer-gremlin`
-OCI image which is an extension of the existing `gremlin-server` image. This
-provides the Tinkerpop library which allows users to connect Gaffer graphs as
-well as some pre installed configuration to get up and running quickly.
+As mentioned previously the recommended way to use Gremlin queries is via the
+Websocket in the Gaffer REST API. To do this you will need to provide a config
+file that sets up the Gaffer Tinkerpop library (a.k.a 'GafferPop'). The file can
+either be added to `/gaffer/gafferpop.properties` in the container, or at a
+ custom path by setting the `gaffer.gafferpop.properties` key in the
+`store.properties` file. This file can be blank but it is still recommended to
+setup some default values.
-```bash
-docker pull gchq/gaffer-gremlin:latest
-```
-
-!!! note
- You will need to configure the default `gaffer-gremlin` image to your
- environment, please continue reading to learn more.
-
-### The `gaffer-gremlin` Image
-
-To use the image you will need to provide the normal Gaffer configuration files
-for to your environment along with a new GafferPop specific file (similar to the
-standard graph config JSON) they are:
-
-- `store.properties` - Gaffer store configuration, this should match the
- existing graph you are connecting to.
-- `elements.json` and `types.json` - The schema files for the graph you wish to
- connect to.
-- `gafferpop.properties` - Configuration for the Gaffer Tinkerpop library
- (Gafferpop).
-
-Please read the subsections below on how to configure these files. Once these
-are configured you can use bind mounts to make them available when running the
-image:
-
-```bash
-docker run \
- --name gaffer-gremlin \
- --publish 8182:8182 \
- --volume store.properties:/opt/gremlin-server/conf/gaffer/store.properties \
- --volume schema:/opt/gremlin-server/conf/gaffer/schema \
- --volume gafferpop.properties:/opt/gremlin-server/conf/gafferpop/gafferpop.properties \
- tinkerpop/gremlin-server:latest gremlin-server.yaml
-```
-
-### Configuring the Store Properties
+!!! tip
+ Please see the [section below](#configuring-the-gafferpop-library) on how to
+ configure the GafferPop properties file.
-Starting with the Store properties, this file should be largely identical to
-the store properties used on the main Gaffer deployment. The main purpose
-of this file is to ensure the same Accumulo cluster is connected to.
+Once the GafferPop properties file has been added, if you start the REST API a
+Gremlin websocket will be available at `localhost:8080/gremlin` by default.
+To connect to this socket you must use the [GraphSON v3](https://tinkerpop.apache.org/docs/current/dev/io/#graphson)
+format. Most standard Gremlin tools already default to this however, if
+connecting using `gremlinpython` you must set it in the driver connection like:
-An example file is given below, please read the specific [Accumulo store](../gaffer-stores/accumulo-store.md)
-documentation for more detail:
+```python
+from gremlin_python.driver.serializer import GraphSONSerializersV3d0
-```properties
-gaffer.store.class=uk.gov.gchq.gaffer.accumulostore.AccumuloStore
-gaffer.store.properties.class=uk.gov.gchq.gaffer.accumulostore.AccumuloProperties
-accumulo.instance=accumulo
-accumulo.zookeepers=zookeeper
-accumulo.user=root
-accumulo.password=secret
-# General store config
-gaffer.cache.service.class=uk.gov.gchq.gaffer.cache.impl.HashMapCacheService
-gaffer.store.job.tracker.enabled=true
+g = traversal().with_remote(DriverRemoteConnection('ws://localhost:8080/gremlin', 'g', message_serializer=GraphSONSerializersV3d0()))
```
-### Configuring the Gafferpop Library
+## Configuring the GafferPop Library
-The `gafferpop.properties`, file is the configuration for the Gaffer
-implementation of Tinkerpop (a.k.a Gafferpop). Most of the set up here is for
-the construction of the Gafferpop Graph instance which we want to make run with
-the `store.properties` we've already configured. An example `gaffer.properties`
-would look like the following:
+The `gafferpop.properties`, file is the configuration for GafferPop. If using
+the REST API there is no mandatory properties you need to set since you already
+will have configured the Graph in the existing `store.properties` file. However,
+adding some default values in for operation modifiers, such as a limit for
+`GetAllElement` operations, is good practice.
```properties
-# The Tinkerpop graph class we should use
-gremlin.graph=uk.gov.gchq.gaffer.tinkerpop.GafferPopGraph
-gaffer.graphId=existingGraph
-gaffer.storeproperties=conf/gaffer/store.properties
-gaffer.userId=user01
-```
-
-!!! note
- It is important the `graphId` here matches the ID of the main graph you
- wish to connect to as this controls which Accumulo table is connected to.
-
-Many of these properties in the example above should be self explanatory, a full breakdown of
-of the available properties is as follows:
-
-| Property Key | Description |
-| --- | --- |
-| `gremlin.graph` | The Tinkerpop graph class we should use |
-| `gaffer.graphId` | The graph ID of the Tinkerpop graph |
-| `gaffer.storeproperties` | The path to the store properties file |
-| `gaffer.schemas` | The path to the directory containing the graph schema files |
-| `gaffer.userId` | The default user ID for the Tinkerpop graph (see the [authentication section](#user-authentication)) |
-| `gaffer.dataAuths` | The default data auths for the user to specify what operations can be performed |
-| `gaffer.operation.options` | Default `Operation` options in the form `key:value` (this can be overridden per query see [here](../../user-guide/query/gremlin/gremlin.md#custom-features)) |
-
-### Configuring the Gremlin Server
-
-The underlying Gremlin server can also be configured if required. The `gaffer-gremlin`
-image comes with an existing YAML configuration based on the example from the
-[Tinkerpop repository](https://github.com/apache/tinkerpop/blob/master/gremlin-server/conf/gremlin-server.yaml).
-This file should be suitable for most use cases but a custom one can be provided
-via a bind mount. If supplying a custom file please ensure you still include the
-following sections:
-
-Ensure the `gafferpop.properties` file is set by modifying the `graphs` section like so:
-
-```yaml
-graphs: {
- graph: conf/gafferpop/gafferpop.properties
-}
+# Default operation config
+gaffer.elements.getalllimit=5000
+gaffer.elements.hasstepfilterstage=PRE_AGGREGATION
```
-Ensure the Gaffer plugin is loaded for Gremlin which is achieved by adding the
-following to the list of plugins in the `plugins` section:
-
-```yaml
-uk.gov.gchq.gaffer.tinkerpop.gremlinplugin.GafferPopGremlinPlugin: {}
-```
-
-!!! tip
- See the [Tinkerpop docs](https://tinkerpop.apache.org/docs/current/reference/#gremlin-server)
- for more information on Gremlin server configuration.
-
-#### User Authentication
-
-Full user authentication is possible with the Gremlin server using the framework
-provided by standard Tinkerpop. The GafferPop implementation provides a
-functional `Authoriser` class that will handle passing the authenticated user to
-the underlying Gaffer graph.
-
-To activate user auth with the Gremlin server you must provide the classes you
-wish to use in the Gremlin server's YAML file like so:
-
-```yaml
-# This should be a deployment specific class
-authentication: {
- authenticator: uk.gov.gchq.gaffer.tinkerpop.server.auth.ExampleGafferPopAuthenticator
-}
-# This class is necessary for correctly forwarding the user to Gaffer
-authorization: {
- authorizer: uk.gov.gchq.gaffer.tinkerpop.server.auth.GafferPopAuthoriser
-}
-```
-
-The `authorizer` should always be the `GafferPopAuthoriser` as this is what
-handles denying invalid queries for GafferPop and passing the user on to the
-Gaffer graph for fine grained security.
+A full breakdown of the available properties is as follows:
!!! note
- The `GafferPopAuthoriser` will deny attempts to set the user ID via a
- `with("userId", )` step in the Gremlin query.
-
-The `authenticator` should be a class specific to the auth mechanism for your
-deployment e.g. LDAP. An example class `ExampleGafferPopAuthenticator` is
-provided as a start point but does not do any actual authenticating so should
-**not** be used in production.
-
-!!! tip
- Tinkerpop provides some implementaions of `Authenticators` for standard
- mechanisms such as [Kerberos](https://tinkerpop.apache.org/javadocs/current/full/org/apache/tinkerpop/gremlin/server/auth/Krb5Authenticator.html).
- Please see the [Tinkerpop documentation](https://tinkerpop.apache.org/docs/current/reference/#security) for more info.
+ Many of these are for standalone GafferPop Graphs so may be ignored if using
+ the REST API.
+
+| Property Key | Description | Used in REST API |
+| --- | --- | --- |
+| `gremlin.graph` | The Tinkerpop graph class we should use for construction. | No |
+| `gaffer.graphId` | The graph ID of the Tinkerpop graph. | No |
+| `gaffer.storeproperties` | The path to the store properties file. | No |
+| `gaffer.schemas` | The path to the directory containing the graph schema files. | No |
+| `gaffer.userId` | The default user ID for the Tinkerpop graph. | No (User is always set via the [`UserFactory`](../security/user-control.md).) |
+| `gaffer.dataAuths` | The default data auths for the user to specify what operations can be performed | No |
+| `gaffer.operation.options` | Default `Operation` options in the form `key:value` (this can be overridden per query see [here](../../user-guide/query/gremlin/custom-features.md)) | Yes |
+| `gaffer.elements.getalllimit` | The default limit for unseeded queries e.g. `g.V()`. | Yes |
+| `gaffer.elements.hasstepfilterstage` | The default stage to apply any `has()` steps e.g. `PRE_AGGREGATION` | Yes |
diff --git a/docs/administration-guide/security/user-control.md b/docs/administration-guide/security/user-control.md
index 7fdf238cfe..b36deba1cc 100644
--- a/docs/administration-guide/security/user-control.md
+++ b/docs/administration-guide/security/user-control.md
@@ -1,3 +1,50 @@
+# User Authentication
+
!!! info "Work in Progress"
- This page is under construction.
\ No newline at end of file
+ This page is under construction.
+
+The user authentication layer for Gaffer is currently only enforced by the REST
+API. We recommend restricting users such that they do not have access to the
+underlying Java API so that all queries are authenticated and executed via the
+REST API.
+
+In the REST API the `User` object is constructed via a [`UserFactory`](https://gchq.github.io/Gaffer/uk/gov/gchq/gaffer/rest/factory/UserFactory.html).
+In the Spring REST API an abstract implementation of this class is used,
+`AbstractUserFactory`, which is then used in the passing of HTTP headers for
+authentication.
+
+Currently, there is a single default implementation of this; the
+`UnknownUserFactory` which simply returns a new `User` with `UNKNOWN` as the
+user ID. To specify the user
+factory class define the `gaffer.user.factory.class` [REST property](../gaffer-config/config.md#application-properties).
+
+## Writing a User Factory
+
+To authenticate your users you will need to extend the `AbstractUserFactory` class
+to add your chosen authentication mechanism. The hooks will already be in the REST API
+to pass the current HTTP headers for each request. Your factory will need to parse these
+to construct a new `User` object via the `createUser()` method that reflects the user
+making the request. This could involve making a call to an LDAP server or similar
+authentication service.
+
+For example, you could use the authorisation header in the request:
+
+```java
+public class LdapUserFactory extends AbstractUserFactory {
+
+ public User createUser() {
+ final String authHeaderValue = this.httpHeaders.get(HttpHeaders.AUTHORIZATION); // add logic to fetch userId
+ final String userId = null; // extract from authHeaderValue
+ final List opAuths = null; // fetch op auths for userId
+ final List dataAuths = null; // fetch op auths for userId
+
+ // Create and return the Gaffer user
+ return new User.Builder()
+ .userId(userId)
+ .opAuths(opAuths)
+ .dataAuths(dataAuths)
+ .build();
+ }
+}
+```
diff --git a/docs/user-guide/query/gremlin/custom-features.md b/docs/user-guide/query/gremlin/custom-features.md
new file mode 100644
index 0000000000..861aa5c855
--- /dev/null
+++ b/docs/user-guide/query/gremlin/custom-features.md
@@ -0,0 +1,182 @@
+# Custom Gremlin Features In Gaffer
+
+The GafferPop implementation provides some extra features on top of the
+standard Tinkerpop framework that you can utilise in your queries. These
+are likely specific to how a Gaffer graph operates and may not be available
+in other graph technologies that support Gremlin queries.
+
+## NamedOperations in Gremlin
+
+The [GafferPopNamedOperationService](https://gchq.github.io/Gaffer/uk/gov/gchq/gaffer/tinkerpop/service/GafferPopNamedOperationService.html)
+allows for the running of Gaffer [Named Operations](../../../administration-guide/named-operations.md) using Tinkerpop.
+Users can run Named Operations and add new Named Operations, deleting Named Operations is not currently possible with Tinkerpop.
+
+!!! example ""
+ Add a simple Named Operation that returns a count of all elements in your graph.
+
+ === "Gremlin"
+
+ ```python
+ operation = gc.OperationChain(
+ operations=[
+ gc.GetAllElements(),
+ gc.Count()
+ ]
+ ).to_json_str()
+
+ params = {"add": {"name": "CountAllElements", "opChain": operation}}
+
+ g.call("namedoperation", params)
+ ```
+
+ === "Java"
+
+ ```java
+ final AddNamedOperation operation = new AddNamedOperation.Builder()
+ .operationChain(new OperationChain.Builder()
+ .first(new GetAllElements()
+ .then(new Count<>())
+ .build())
+ .build())
+ .name("CountAllElements")
+ .build();
+
+ Map addParams = new HashMap<>();
+ addParams.put("name", "CountAllElements");
+ addParams.put("opChain", operation.getOperationChainAsString());
+ Map> params = Collections.singletonMap("add", addParams);
+
+ g.call("namedoperation", params);
+ ```
+
+Users can also run any existing or added Named Operations that are stored in the cache.
+
+!!! example ""
+
+ === "Gremlin"
+
+ ```python
+ g.call("namedoperation", {"execute": "CountAllElements"}).to_list()
+ ```
+
+ === "Java"
+
+ ```java
+ Map params = Collections.singletonMap("execute", "CountAllElements")
+ g.call("namedoperation", params).toList();
+ ```
+
+## Adding Options to Queries
+
+In standard Gremlin syntax it is possible to add additional key value variables
+into a query via a [`with()` step](https://tinkerpop.apache.org/docs/current/reference/#with-step).
+This feature is utilised to allow some custom properties to be passed in
+for Gaffer specific options:
+
+| Key | Example | Description |
+| --- | --- | --- |
+| `operationOptions` | `g.with("operationOptions", "gaffer.federatedstore.operation.graphIds:graphA").V()` | Allows passing options to the underlying Gaffer Operations, this is the same as the `options` field on a standard JSON query. |
+| `getAllElementsLimit` | `g.with("getAllElementsLimit", 100).V()` | Limits the amount of elements returned if performing an unseeded query e.g. a `GetAllElements` operation. |
+| `hasStepFilterStage` | `g.with("hasStepFilterStage", "PRE_AGGREGATION").V()` | Controls which phase the filtering from a Gremlin `has()` stage is applied to the results. |
+| `cypher` | `g.with("cypher", "MATCH (p:person) RETURN p").call()` | Translates the given Cypher query to Gremlin and executes it on the Graph. |
+
+## Gaffer Gremlin Explain
+
+With the Gaffer REST API there are additional endpoints to provide explanations
+of how a given Gremlin query maps to Gaffer operation chains. The two endpoints are:
+
+- `/rest/gremlin/explain` - Accepts plain string Gremlin and will return JSON explain.
+- `/rest/gremlin/cypher/explain` - Accepts plain OpenCypher querys and will return JSON explain.
+
+!!! warning
+ Please be aware that in order to provide an explanation your submitted query will
+ be run against the Graph.
+
+An example of the input and output of a Gremlin explain is as follows:
+
+!!! example ""
+ Using endpoint: `/rest/gremlin/explain`.
+
+ === "Gremlin Query"
+
+ ```groovy
+ g.V().hasLabel('person').toList()
+ ```
+
+ === "Gaffer Explain"
+
+ ```JSON
+ {
+ "overview": "OperationChain[GetAllElements->Limit]",
+ "chain": {
+ "operations": [
+ {
+ "view": {
+ "entities": {
+ "person": {}
+ }
+ },
+ "class": "uk.gov.gchq.gaffer.operation.impl.get.GetAllElements"
+ },
+ {
+ "resultLimit": 5000,
+ "truncate": true,
+ "class": "uk.gov.gchq.gaffer.operation.impl.Limit"
+ }
+ ],
+ "class": "uk.gov.gchq.gaffer.operation.OperationChain"
+ }
+ }
+ ```
+
+An example of the input and output of a Cypher explain is as follows:
+
+!!! example ""
+ Using endpoint: `/rest/gremlin/cypher/explain`.
+
+ === "Gremlin Query"
+
+ ```cypher
+ MATCH (p:person) WHERE ID(p) = '1' RETURN p
+ ```
+
+ === "Gaffer Explain"
+
+ ```JSON
+ {
+ "overview": "OperationChain[GetElements]",
+ "chain": {
+ "operations": [
+ {
+ "input": [
+ {
+ "vertex": "1",
+ "class": "uk.gov.gchq.gaffer.operation.data.EntitySeed"
+ }
+ ],
+ "view": {
+ "entities": {
+ "person": {}
+ }
+ },
+ "class": "uk.gov.gchq.gaffer.operation.impl.get.GetElements"
+ }
+ ],
+ "class": "uk.gov.gchq.gaffer.operation.OperationChain"
+ },
+ "gremlin": "g.V().hasLabel('person').has('~id', eq('1')).project('p').by(__.valueMap().with('~tinkerpop.valueMap.tokens')).toList()"
+ }
+ ```
+Note there are some limitations to be aware of when using these endpoints.
+
+- The mapping of Gremlin to Gaffer operations is not one to one, this means that some
+predicates may appear missing from the operation chain in the explanation. If this
+is the case it means filtering may have occurred in Tinkerpop rather than in the
+Gaffer view.
+- Each Gremlin step is 'lazy' meaning if there is no output from the previous step it
+will not execute the next step. This in essence means if your graph does not have
+data in that reaches the last step then that step will be missing from the explanation.
+- The query needs to be relevant for the data e.g. can't query using a group that isn't
+in the Graph schema.
+- All submitted Cypher explains will be translated to Gremlin first and have a `.toList()`
+appended to the translation so it is actually executed.
diff --git a/docs/user-guide/query/gremlin/gremlin-limits.md b/docs/user-guide/query/gremlin/gremlin-limits.md
index fe21937c01..f1d2c5c0f0 100644
--- a/docs/user-guide/query/gremlin/gremlin-limits.md
+++ b/docs/user-guide/query/gremlin/gremlin-limits.md
@@ -15,8 +15,7 @@ Current TinkerPop features not present in the GafferPop implementation:
Current known limitations or bugs:
-- Proper [user authentication](../../../administration-guide/gaffer-deployment/gremlin.md#user-authentication)
- is only available if using a Gremlin server and the `GafferPopAuthoriser` class.
+- Must use the GraphSON v3 format when connecting via the REST API websocket.
- Performance compared to standard Gaffer `OperationChain`s will likely be
slower as multiple Gaffer `Operations` may utilised to perform one Gremlin
step.
diff --git a/docs/user-guide/query/gremlin/gremlin.md b/docs/user-guide/query/gremlin/gremlin.md
index c45b35b070..b5752f7d02 100644
--- a/docs/user-guide/query/gremlin/gremlin.md
+++ b/docs/user-guide/query/gremlin/gremlin.md
@@ -24,22 +24,23 @@ languages so for example, you can write queries in Python via the [`gremlinpytho
## Using Gremlin Queries in Gaffer
Gremlin was added to Gaffer in version 2.1 as a new graph query language and since
-version 2.2 a container image is provided allowing a Gremlin layer to be added to
-existing 2.x graphs. A full tutorial on setting up this image is provided in the
+version 2.3 it has been added as standard into the Gaffer REST API. A full tutorial
+on the configuration of Gremlin in Gaffer is provided in the
[administration guide](../../../administration-guide/gaffer-deployment/gremlin.md).
This guide will use the [Python API for Gremlin](https://pypi.org/project/gremlinpython/)
to demonstrate some basic capabilities and how they compare to standard Gaffer syntax.
To start querying in Gremlin we first need a reference to what is known as the
-Graph Traversal. To obtain this we need to connect to a running Gremlin server,
-similar to how a connection to the Gaffer REST API is needed if using
-[`gafferpy`](../../apis/python-api.md). We can do this by first importing the required
+Graph Traversal. To obtain this we need to connect to the Gremlin websocket provided
+by the Gaffer REST API (if you have used [`gafferpy`](../../apis/python-api.md)
+before this will be quite similar). We can do this by first importing the required
libraries like so (many of these will be needed later for queries):
```python
from gremlin_python.process.anonymous_traversal import traversal
from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
+from gremlin_python.driver.serializer import GraphSONSerializersV3d0
from gremlin_python.process.graph_traversal import __
```
@@ -47,13 +48,17 @@ We can then establish a connection to the Gremlin server and save a reference to
this (typically called `g`):
```python
-# Setup a connection with the gremlin server running on localhost
-g = traversal().with_remote(DriverRemoteConnection('ws://localhost:8182/gremlin', 'g'))
+# Setup a connection with the REST API running on localhost
+g = traversal().with_remote(DriverRemoteConnection('ws://localhost:8080/gremlin', 'g', message_serializer=GraphSONSerializersV3d0()))
```
Now that we have the traversal reference this can be used to spawn graph traversals
and get results back.
+!!! note
+ Its important to use the GraphSON v3 serialiser if connecting to the Gaffer
+ REST API.
+
### Basic Gremlin Queries
Gremlin queries (similar to Gaffer queries) usually require a starting set of
@@ -259,83 +264,3 @@ In a seeded query these should be formatted like so `g.E("[source, dest]")` or
Note that if using TypeSubTypeValue for seeds or property values these must be in the
format `t:type|st:subtype|v:value`.
-## Custom Features
-
-The GafferPop implementation provides some extra features on top of the
-standard Tinkerpop framework that you can utilise in your queries. These
-are likely specific to how a Gaffer graph operates and may not be available
-in other graph technologies that support Gremlin queries.
-
-### NamedOperations in Gremlin
-
-The [GafferPopNamedOperationService](https://gchq.github.io/Gaffer/uk/gov/gchq/gaffer/tinkerpop/service/GafferPopNamedOperationService.html)
-allows for the running of Gaffer [Named Operations](../../../administration-guide/named-operations.md) using Tinkerpop.
-Users can run Named Operations and add new Named Operations, deleting Named Operations is not currently possible with Tinkerpop.
-
-!!! example ""
- Add a simple Named Operation that returns a count of all elements in your graph.
-
- === "Gremlin"
-
- ```python
- operation = gc.OperationChain(
- operations=[
- gc.GetAllElements(),
- gc.Count()
- ]
- ).to_json_str()
-
- params = {"add": {"name": "CountAllElements", "opChain": operation}}
-
- g.call("namedoperation", params)
- ```
-
- === "Java"
-
- ```java
- final AddNamedOperation operation = new AddNamedOperation.Builder()
- .operationChain(new OperationChain.Builder()
- .first(new GetAllElements()
- .then(new Count<>())
- .build())
- .build())
- .name("CountAllElements")
- .build();
-
- Map addParams = new HashMap<>();
- addParams.put("name", "CountAllElements");
- addParams.put("opChain", operation.getOperationChainAsString());
- Map> params = Collections.singletonMap("add", addParams);
-
- g.call("namedoperation", params);
- ```
-
-Users can also run any existing or added Named Operations that are stored in the cache.
-
-!!! example ""
-
- === "Gremlin"
-
- ```python
- g.call("namedoperation", {"execute": "CountAllElements"}).to_list()
- ```
-
- === "Java"
-
- ```java
- Map params = Collections.singletonMap("execute", "CountAllElements")
- g.call("namedoperation", params).toList();
- ```
-
-### Adding Options to Queries
-
-In standard Gremlin syntax it is possible to add additional key value variables
-into a query via a [`with()` step](https://tinkerpop.apache.org/docs/current/reference/#with-step).
-This feature is utilised to allow some custom properties to be passed in
-for Gaffer specific options:
-
-| Key | Example | Description |
-| --- | --- | --- |
-| `operationOptions` | `g.with("operationOptions", "gaffer.federatedstore.operation.graphIds:graphA").V()` | Allows passing options to the underlying Gaffer Operations, this is the same as the `options` field on a standard JSON query. |
-| `getAllElementsLimit` | `g.with("getAllElementsLimit", 100).V()` | Limits the amount of elements returned if performing an unseeded query e.g. a `GetAllElements` operation. |
-| `hasStepFilterStage` | `g.with("hasStepFilterStage", "PRE_AGGREGATION").V()` | Controls which phase the filtering from a Gremlin `has()` stage is applied to the results. |
diff --git a/mkdocs.yml b/mkdocs.yml
index 47a692ceb6..097bc136ec 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -99,6 +99,7 @@ nav:
- 'Using CSV Data': 'user-guide/query/gaffer-syntax/import-export/csv.md'
- Apache Gremlin:
- 'Gremlin in Gaffer': 'user-guide/query/gremlin/gremlin.md'
+ - 'Custom Features': 'user-guide/query/gremlin/custom-features.md'
- 'GafferPop Limitations': 'user-guide/query/gremlin/gremlin-limits.md'
- 'Graph Schemas': 'user-guide/schema.md'
- Developer Guide:
@@ -145,7 +146,7 @@ nav:
- 'Running Gaffer on Kubernetes': 'administration-guide/gaffer-deployment/kubernetes-guide/running-on-kubernetes.md'
- 'Creating a Simple Deployment': 'administration-guide/gaffer-deployment/kubernetes-guide/simple-deployment.md'
- 'Configuring Gaffer with Helm': 'administration-guide/gaffer-deployment/kubernetes-guide/helm-configuration.md'
- - 'Gremlin Connection': 'administration-guide/gaffer-deployment/gremlin.md'
+ - 'Gremlin': 'administration-guide/gaffer-deployment/gremlin.md'
- Store Types:
- 'Store Guide': 'administration-guide/gaffer-stores/store-guide.md'
- 'Accumulo Store': 'administration-guide/gaffer-stores/accumulo-store.md'