blob: d24a1a6e3bbd3c64dfa44e4b906c68943dea1c7c [file]
////
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
////
= TinkerPop 4.0.0
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/images/gremlin-standing.png[width=185]
*4.0.0*
== TinkerPop 4.0.0
*Release Date: NOT OFFICIALLY RELEASED YET*
Please see the link:https://github.com/apache/tinkerpop/blob/4.0.0/CHANGELOG.asciidoc#release-4-0-0[changelog] for a
complete list of all the modifications that are part of this release.
=== Upgrading for Users
==== BulkSet Behavior Changes
Starting with 4.0, steps which return BulkSet (e.g. `aggregate()`) will have results returned in different format
depending on embedded or remote usage.
For embedded cases, a BulkSet will be returned as before.
For remote cases, BulkSets will now be expanded into Lists upon deserialization with `gremlin-driver`. All other GLVs already expanded BulkSet to List prior to TinkerPop 4.
Each element in the BulkSet will appear in the list the same number of times as specified by its bulk value.
==== Configuration changes
This is a placeholder to summarize configuration-related changes.
* `maxContentLength` setting for Gremlin Driver has been renamed to `maxResponseContentLength` and now blocks incoming responses that are too large based on total response size.
* `maxContentLength` setting for Gremlin Server has been renamed to `maxRequestContentLength`.
==== Simplification to g creation
The creation of "g" is the start point to writing Gremlin. There are a number of ways to create it, but TinkerPop has
long recommended the use of the anonymous `traversal()` function for this creation.
[source,groovy]
----
// for embedded cases
graph = TinkerGraph.open()
g = traversal().withEmbedded(graph)
// for remote cases
g = traversal().withRemote(DriverRemoteConnection.using(...)))
----
As of this release, those two methods have been deprecated in favor of just `with()` which means you could simply write:
[source,groovy]
----
// for embedded cases
graph = TinkerGraph.open()
g = traversal().with(graph)
// for remote cases
g = traversal().with(DriverRemoteConnection.using(...)))
----
That's a bit less to type, but also removes need to programmatically decide which function to call which hopefully
strengthens the abstraction further. To demonstrate this further consider this next example:
[source,groovy]
----
g = traversal().with("config.properties")
----
The properties file in the above example can either point to a remote configuration or a embedded configuration allowing
"g" to be switched as needed without code changes.
See: link:https://issues.apache.org/jira/browse/TINKERPOP-3017[TINKERPOP-3017]
==== Changes to Java RequestInterceptor
Because the underlying transport has been changed from WebSockets to HTTP, the usage of the `RequestInterceptor` has
changed as well. The `RequestInterceptor` will now be run per request and will allow you to completely modify the HTTP
request that is sent to the server. `Cluster` has four new methods added to it: `addInterceptorAfter`,
`addInterceptorBefore`, `removeInterceptor` and `addInterceptor`. Each interceptor requires a name as it will be used
to insert new interceptors in different positions.
The interceptors work with a new class called HttpRequest. This is just a basic abstraction over a request but it also
contains some useful strings for common headers. The initial `HttpRequest` that is passed to the first interceptor will
contain a `RequestMessage`. `RequestMessage` is immutable and only certain keys can be added to them. If you want to
customize the body by adding other fields, you will need to make a different copy of the `RequestMessage` or completely
change the body to contain a different data type. The final interceptor must return a `HttpRequest` whose body contains
a `byte[]`.
After the initial HTTP request is generated, the interceptors will be called in order to allow the request to be
modified. After each `RequestInterceptor` is run, the request is updated with the data from the final `HttpRequest` and
that is sent to the endpoint. There is a default interceptor added to every `Cluster` called "serializer". This
interceptor is responsible for serializing the request body is which what the server normally expects. This is intended
to be an advanced customization technique that should only be used when needed.
==== Addition of Python interceptor
HTTP interceptors have been added to `gremlin-python` to enable capability similar to that of Java GLV. These
interceptors can be passed into either a `DriverRemoteConnection` or a `Client` using the interceptors parameter. An
interceptor is a `Callable` that accepts one argument which is the HTTP request (dictionary containing header, payload
and auth) or a list/tuple of these functions. The interceptors will run after the request serializer has run but before
any auth functions run so the HTTP request may still get modified after your interceptors are run. In situations where
you don't want the payload to be serialized, the `message_serializer` has been split into a `request_serializer` and a
`response_serializer`. Simply set the `request_serializer` to `None` and this will prevent the `RequestMessage` from
being serialized. Again, this is expected to be an advanced feature so some knowledge of implementation details will be
required to make this work. For example, you'll need to know what payload formats are accepted by `aiohttp` for the
request to be sent.
==== Changes to deserialization for gremlin-javascript
Starting from this version, `gremlin-javascript` will deserialize `Set` data into a ECMAScript 2015 Set. Previously,
these were deserialized into arrays.
==== Gremlin Grammar Changes
A number of changes have been introduced to the Gremlin grammar to help make it be more consistent and easier to use.
*`new` keyword is now optional*
The `new` keyword is now optional in all cases where it was previously used. Both of the following examples are now
valid syntax with the second being the preferred form going forward:
[source,groovy]
----
g.V().withStrategies(new SubgraphStrategy(vertices: __.hasLabel('person')))
g.V().withStrategies(SubgraphStrategy(vertices: __.hasLabel('person')))
----
In a future version, it is likely that the `new` keyword will be removed entirely from the grammar.
*Supports withoutStrategies()*
The `withoutStrategies()` configuration step is now supported syntax for the grammar. While this option is not commonly
used it is still a part of the Gremlin language and there are times where it is helpful to have this fine grained
control over how a traversal works.
[source,groovy]
----
g.V().withoutStrategies(CountStrategy)
----
See: link:https://issues.apache.org/jira/browse/TINKERPOP-2862[TINKERPOP-2862],
link:https://issues.apache.org/jira/browse/TINKERPOP-3046[TINKERPOP-3046]
==== Renaming none() to discard()
The `none()` step, which was primarily used by `iterate()` to discard traversal results in remote contexts, has been
renamed to `discard()`. In its place is a new list filtering step `none()`, which takes a predicate as an argument and
passes lists with no elements matching the predicate.
==== Splitting a string into characters using split()
The `split()` step will now split a string into a list of its characters if the given separator is an empty string.
[source,groovy]
----
// previous implementation
g.inject("Hello").split("")
==>[Hello]
// new implementation
g.inject("Hello").split("")
==>[H,e,l,l,o]
----
See: link:https://issues.apache.org/jira/browse/TINKERPOP-3083[TINKERPOP-3083]
==== Improved handling of integer overflows
Integer overflows caused by addition and multiplication operations will throw an exception instead of being silently
skipped with incorrect result.
==== SeedStrategy Construction
The `SeedStrategy` public constructor has been removed for Java and has been replaced by the builder pattern common
to all strategies. This change was made to ensure that the `SeedStrategy` could be constructed in a consistent manner.
==== Removal of `gremlin-archetype`
`gremlin-archetype`, which contained example projects demonstrating the use cases of TinkerPop, has been removed in
favor of newer sample applications which can be found in each GLV's `examples` folder.
==== Improved Translators
The various Java `Translator` implementations allowing conversion of Gremlin traversals to string forms in various
languages have been modified considerably. First, they have been moved from to the
`org.apache.tinkerpop.gremlin.language.translator` package, because they now depend on the ANTLR grammar in
`gremlin-language` to handled the translation process. Making this change allowed for a more accurate translation of
Gremlin that doesn't need to rely on reflection and positional arguments to determine which step was intended for use.
Another important change was the introduction of specific translators for Groovy and Java. While Groovy translation
tends to work for most Java cases, there is syntax specific to Groovy where it does not. With a specific Java
translator, the translation process can be more accurate and less error prone.
The syntax for the translators has simplified as well. The translator function now takes a Gremlin string and a target
language to translate to. Consider the following example:
[source,text]
----
gremlin> GremlinTranslator.translate("g.V().out('knows')", Translator.GO)
==>g.V().Out("knows")
----
Further note that Gremlin language variants produce `gremlin-language` compliant strings directly since bytecode was
removed. As a result, all translators in .NET, Python, Go and Javascript have been removed.
See: link:https://issues.apache.org/jira/browse/TINKERPOP-3028[TINKERPOP-3028]
==== Change to `OptionsStrategy` in `gremlin-python`
The `\\__init__()` syntax has been updated to be both more pythonic and more aligned to the `gremlin-lang` syntax.
Previously, `OptionsStrategy()` took a single argument `options` which was a `dict` of all options to be set.
Now, all options should be set directly as keyword arguments.
For example:
[source,python]
----
# 3.7 and before:
g.with_strategies(OptionsStrategy(options={'key1': 'value1', 'key2': True}))
# 4.x and newer:
g.with_strategies(OptionsStrategy(key1='value1', key2=True))
myOptions = {'key1': 'value1', 'key2': True}
# 3.7 and before:
g.with_strategies(OptionsStrategy(options=myOptions))
# 4.x and newer:
g.with_strategies(OptionsStrategy(**myOptions))
----
==== Custom Traversal Strategy Construction
Traversal strategy construction has been updated such that it is no longer required to have concrete classes for each
strategy being added to a graph traversal (use of concrete classes remains viable and is recommended for "native"
TinkerPop strategies). To use strategies without a concrete class, `TraversalStrategyProxy` can be used in Java, and
`TraversalStrategy` in Python.
All the following examples will produce the script `g.withStrategies(new MyStrategy(config1:'my value',config2:123))`:
[source,java]
----
Map<String, Object> configMap = new LinkedHashMap<>();
configMap.put("config1", "my value");
configMap.put("config2", 123);
TraversalStrategy strategyProxy = new TraversalStrategyProxy("MyStrategy", new MapConfiguration(configMap));
GraphTraversal traversal = g.withStrategies(strategyProxy);
----
[source,python]
----
g.with_strategies(TraversalStrategy(
strategy_name='MyStrategy',
config1='my value',
config2=123
))
----
==== Changes to Serialization
The GLVs will only support GraphBinary V4 and GraphSON support has been removed. This means that the serializer option
that was available in most GLVs has been removed. GraphBinary is a more compact format and has support for the same
types. This should lead to increased performance for users upgrading from any version of GraphSON to GraphBinary.
The number of serializable types has been reduced in V4. For example, only a single temporal type remains. You have two
options when trying to work with data types whose serializer has been removed: first, you can attempt to convert the
data to another type that still have a serializer or, second, the type may have been too specific and therefore removed
in which case your provider should have a Provider Defined Type (PDT) for it. See the next paragraph for information on
PDTs.
Custom serializers have also been removed so if you previously included those as part of your application, they should
now be removed. In its place, PDTs have been introduced. In particular, there is the Primitive PDT and the Composite
PDT. Primitive PDTs are string-based representations of a primitive type supported by your provider. Composite types
contain a map of fields. You should consult your provider's documentation to determine what types of fields a
particular PDT may contain.
=== Upgrading for Providers
==== Renaming NoneStep to DiscardStep
NoneStep, which was primarily used by `iterate()` to discard traversal results in remote contexts, has been renamed to
DiscardStep. In its place is a new list filtering NoneStep, which takes a predicate as an argument and passes lists with
no elements matching the predicate.
==== Changes to Serialization
The V4 versions of GraphBinary and GraphSON are being introduced. Support for the older versions of GraphBinary (V1)
and GraphSON (V1-3) is removed. Additionally, the GLVs will only use GraphBinary, the Gremlin Server, however, can
still serialize both GraphSON and GraphBinary. The following is a list of the major changes to the GraphBinary format:
* Removed type serializers:
** Period
** Date
** TimeStamp
** Instant
** ZonedDateTime
** OffsetTime
** LocalDateTime
** LocalDate
** LocalTime
** MonthDay
** YearMonth
** Year
** ZoneOffset
** BulkSet
** Class
** Binding
** Bytecode
** Barrier
** Cardinality
** Column
** Operator
** Order
** Pick
** Pop
** Scope
** Merge
** DT
** Lambda
** P
** Traverser
** TextP
** TraversalStrategy
** Metrics
** TraversalMetrics
** InetAddress
* Byte is redefined from being unsigned byte to a signed byte.
* List has a `0x02` value_flag used to denote bulking.
* Map has a `0x02` value_flag used to denote ordering.
* `Element` (Vertex, Edge, VertexProperty) labels have been changed from `String` to `List` of `String`.
* `Element` (Vertex, Edge, VertexProperty) properties are no longer null and are `List` of `Property`.
* Custom is replaced with Provider Defined Types
==== Graph System Providers
===== AbstractAuthenticatorHandler Constructor
The deprecated one-arg constructor for `AbstractAuthenticationHandler` has been removed along with two-arg constructors
for the implementations. Gremlin Server formerly supported the two-arg `Authenticator`, and `Settings` constructor for
instantiating new custom instances. It now expects implementations of `AbstractAuthenticationHandler` to use a
three-arg constructor that takes `Authenticator`, `Authorizer`, and `Settings`.
==== Graph Driver Providers