| //// |
| 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 3.5.0 |
| |
| image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/images/gremlin-sleeping-beauty.png[width=225] |
| |
| *The Sleeping Gremlin: No. 18 Entr'acte symphonique* |
| |
| == TinkerPop 3.5.0 |
| |
| *Release Date: NOT OFFICIALLY RELEASED YET* |
| |
| Please see the link:https://github.com/apache/tinkerpop/blob/3.5.0/CHANGELOG.asciidoc#release-3-5-0[changelog] for a complete list of all the modifications that are part of this release. |
| |
| === Upgrading for Users |
| |
| ==== Gryo Usage |
| |
| Since the first release of TinkerPop 3.x, Gryo has been the default serialization format for Gremlin Server and |
| Java Driver. It was also used as the default serialization format for Gremlin Console remote connectivity to Gremlin |
| Server. As of this release, Gryo has been replaced as the default by GraphBinary. All packaged configuration files |
| and programmatic defaults have been modified as such. |
| |
| It is still possible to utilize Gryo as a message serialization format by modifying Gremlin Server configuration files |
| to include the appropriate Gryo configurations. If using Gryo, do not user earlier versions of the driver and server |
| with 3.5.0. Use a 3.5.0 client to connect to a 3.5.0 server. Generally speaking, mixed version combinations will |
| appear to work properly, but problems will likely occur during general course of usage and it is therefore not |
| advisable to take this approach. |
| |
| For best compatibility between 3.4.x and 3.5.x, please use GraphBinary. |
| |
| link:https://issues.apache.org/jira/browse/TINKERPOP-2259[TINKERPOP-2259] |
| |
| ==== Configuration Upgrade |
| |
| There is a major breaking change in the use of `Configuration` objects. Prior to 3.5.0, `Configuration` objects were |
| from the Apache Commons `commons-configuration` library, but in this version, they are of `commons-configuration2`. |
| While this is a breaking change, the fix for most implementations will be quite simple, Simply, change the import |
| statements from: |
| |
| [source,text] |
| ---- |
| org.apache.commons.configuration.* |
| ---- |
| |
| to |
| |
| [source,text] |
| ---- |
| org.apache.commons.configuration2.* |
| ---- |
| |
| It is also worth noting that default list handling in configurations is treated differently. TinkerPop largely |
| disabled the default list handling approach in `Configuration` 1.x, but if that functionality is still needed, it can |
| be reclaimed by setting the `LegacyListDelimiterHandler` - details for doing taking this step and other relevant |
| upgrade information can be found in the link:https://commons.apache.org/proper/commons-configuration/userguide/upgradeto2_0.html[2.x Upgrade Documentation]. |
| |
| See: link:https://issues.apache.org/jira/browse/TINKERPOP-2185[TINKERPOP-2185] |
| |
| ==== Use of null |
| |
| Gremlin has traditionally disallowed `null` as a value in traversals and not always in consistent ways: |
| |
| [source,text] |
| ---- |
| gremlin> g.inject(1, null, null, 2, null) |
| java.lang.NullPointerException |
| Type ':help' or ':h' for help. |
| Display stack trace? [yN]n |
| gremlin> g.V().has('person','name','marko').property('age', null) |
| The AddPropertyStep does not have a provided value: AddPropertyStep({key=[age]}) |
| Type ':help' or ':h' for help. |
| Display stack trace? [yN] |
| gremlin> g.addV("person").property("name", 'stephen').property("age", null) |
| ==>v[13] |
| gremlin> g.V().has('person','name','stephen').elementMap() |
| ==>[id:13,label:person,name:stephen] |
| gremlin> g.V().constant(null) |
| gremlin> |
| ---- |
| |
| Note how `null` can produce exception behavior or act as a filter. For 3.5.0, TinkerPop has not only made `null` usage |
| consistent, but has also made it an allowable value within a `Traversal`: |
| |
| [source,text] |
| ---- |
| gremlin> g.inject(1, null, null, 2, null) |
| ==>1 |
| ==>null |
| ==>null |
| ==>null |
| ==>2 |
| gremlin> g.V().constant(null) |
| ==>null |
| ==>null |
| ==>null |
| ==>null |
| ==>null |
| ==>null |
| ---- |
| |
| TinkerGraph can be configured to support `null` as a property value and all graphs may not support this feature (for |
| example, Neo4j does not). Please be sure to check the new `supportsNullPropertyValues()` feature (or the documentation |
| of the graph provider) to determine if the `Graph` implementation allows `null` as a property value. |
| |
| With respect to `null` in relation to properties, there was a bit of inconsistency in the handling of `null` in calls |
| to `property()` depending on the type of mutation being executed demonstrated as follows in earlier versions: |
| |
| [source,text] |
| ---- |
| gremlin> g.V(1).property("x", 1).property("y", null).property("z", 2) |
| The AddPropertyStep does not have a provided value: AddPropertyStep({key=[y]}) |
| Type ':help' or ':h' for help. |
| Display stack trace? [yN]N |
| gremlin> g.addV("test").property("x", 1).property("y", null).property("z", 2) |
| ==>v[13] |
| gremlin> g.V(13).properties() |
| ==>vp[x->1] |
| ==>vp[z->2] |
| ---- |
| |
| This behavior has been altered to become consistent. First, assuming `null` is not supported as a property value, the |
| setting of a property to `null` should have the behavior of removing the property in the same way in which you might |
| do `g.V().properties().drop()`: |
| |
| [source,text] |
| ---- |
| gremlin> g.V(1).property("x", 1).property("y", null).property("z", 2) |
| ==>v[1] |
| gremlin> g.V(1).elementMap() |
| ==>[id:1,label:person,name:marko,x:1,z:2,age:29] |
| gremlin> g.V().hasLabel('person').property('age',null).iterate() |
| gremlin> g.V().hasLabel('person').elementMap() |
| ==>[id:1,label:person,name:marko] |
| ==>[id:2,label:person,name:vadas] |
| ==>[id:4,label:person,name:josh] |
| ==>[id:6,label:person,name:peter] |
| ---- |
| |
| Then, assuming `null` is supported as a property value: |
| |
| [source,text] |
| ---- |
| gremlin> g.addV("person").property("name", 'stephen').property("age", null) |
| ==>v[13] |
| gremlin> g.V().has('person','name','stephen').elementMap() |
| ==>[id:13,label:person,name:stephen,age:null] |
| gremlin> g.V().has('person','age',null) |
| ==>v[13] |
| ---- |
| |
| In conclusion, this change in greater support of `null` may affect the behavior of existing traversals written in past |
| versions of TinkerPop as it is no longer possible to rely on `null` to expect a filtering action for traversers. |
| Please review existing Gremlin carefully to ensure that there are no unintended consequences of this change and that |
| there are no opportunities to improve existing logic to take greater advantage of this expansion of `null` semantics. |
| |
| See: link:https://issues.apache.org/jira/browse/TINKERPOP-2235[TINKERPOP-2235], |
| link:https://issues.apache.org/jira/browse/TINKERPOP-2099[TINKERPOP-2099] |
| |
| ==== Remote SideEffects |
| |
| Remote traversals no longer support the retrieval of remote side-effects. Users must therefore directly return |
| side-effects as part of their query if they need that data. Note that server settings for `TraversalOpProcessor`, which |
| formerly held the cache for these side-effects, no longer have any effect and can be removed. |
| |
| See: link:https://issues.apache.org/jira/browse/TINKERPOP-2269[TINKERPOP-2269] |
| |
| ==== Python 2.x Support |
| |
| The gremlinpython module no longer supports Python 2.x. Users must use Python 3 going forward. For the most part, from |
| a user's perspective, there are no specific API changes to consider as a result of this change. It is also worth |
| noting that Jython support has been removed and that `gremlin-python` no longer produces a JVM-based artifact. This |
| change means that the `GremlinJythonScriptEngine` no longer exists and there is no way to write native Python lambdas. |
| All lambdas should be written using `gremlin-groovy` if they are needed. |
| |
| See: link:https://issues.apache.org/jira/browse/TINKERPOP-2317[TINKERPOP-2317] |
| |
| ==== Neo4j Changes |
| |
| There were two key changes to the neo4j-gremlin module: |
| |
| * The underlying Neo4j version moved from the 3.2.x line to 3.4.x line. Please see the |
| link:https://neo4j.com/guides/upgrade-archive/[Neo4j Upgrade FAQ] for more information as features and |
| configuration options may have changed. |
| * Experimental support for multi/meta-properties in Neo4j which were previously deprecated have now been permanently |
| removed. |
| |
| ==== Deprecation Removal |
| |
| The following deprecated classes, methods or fields have been removed in this version: |
| |
| * `gremlin-core` |
| ** `org.apache.tinkerpop.gremlin.process.computer.bulkdumping.BulkDumperVertexProgram` |
| ** `org.apache.tinkerpop.gremlin.process.computer.bulkloading.BulkLoader` |
| ** `org.apache.tinkerpop.gremlin.process.computer.bulkloading.BulkLoaderVertexProgram` |
| ** `org.apache.tinkerpop.gremlin.process.computer.bulkloading.IncrementalBulkLoader` |
| ** `org.apache.tinkerpop.gremlin.process.computer.bulkloading.OneTimeBulkLoader` |
| ** `org.apache.tinkerpop.gremlin.process.computer.clustering.peerpressure.PeerPressureVertexProgram.Builder#traversal(*)` |
| ** `org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank.PageRankVertexProgram.Builder#traversal(*)` |
| ** `org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank.PageRankVertexProgram.Builder#vertexCount()` |
| ** `org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRankVertexProgramStep.modulateBy(*)` |
| ** `org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRankVertexProgramStep.modulateTimes()` |
| ** `org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PeerPressureVertexProgramStep.modulateBy(*)` |
| ** `org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PeerPressureVertexProgramStep.modulateTimes()` |
| ** `org.apache.tinkerpop.gremlin.process.remote.traversal.AbstractRemoteTraversalSideEffects` |
| ** `org.apache.tinkerpop.gremlin.process.remote.traversal.EmbeddedRemoteTraversalSideEffects` |
| ** `org.apache.tinkerpop.gremlin.process.remote.traversal.RemoteTraversalSideEffects` |
| ** `org.apache.tinkerpop.gremlin.process.remote.traversal.RemoteTraversal#getSideEffects()` |
| ** `org.apache.tinkerpop.gremlin.process.traversal.Order.decr` |
| ** `org.apache.tinkerpop.gremlin.process.traversal.Order.incr` |
| ** `org.apache.tinkerpop.gremlin.process.traversal.TraversalSource#withRemote(*)` |
| ** `org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource#withRemote(*)` |
| ** `org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertyMapStep(Traversal.Admin, boolean, PropertyType, String...)` |
| ** `org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertyMapStep#isIncludeTokens()` |
| ** `org.apache.tinkerpop.gremlin.structure.util.star.StarGraph#builder()` |
| ** `org.apache.tinkerpop.gremlin.structure.util.star.StarGraph.Builder#create()` |
| * `gremlin-driver` |
| ** `org.apache.tinkerpop.gremlin.driver.Tokens#ARGS_SCRIPT_EVAL_TIMEOUT` |
| ** `org.apache.tinkerpop.gremlin.driver.Cluster.Builder#keyCertChainFile(String)` |
| ** `org.apache.tinkerpop.gremlin.driver.Cluster.Builder#keyFile(String)` |
| ** `org.apache.tinkerpop.gremlin.driver.Cluster.Builder#keyPassword(String)` |
| ** `org.apache.tinkerpop.gremlin.driver.Cluster.Builder#trustCertificateChainFile(String)` |
| ** `org.apache.tinkerpop.gremlin.driver.handler.NioGremlinRequestEncoder` |
| ** `org.apache.tinkerpop.gremlin.driver.handler.NioGremlinResponseDecoder` |
| ** `org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTraversalSideEffects` |
| ** `org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTraversal#getSideEffects()` |
| ** `org.apache.tinkerpop.gremlin.driver.simple.NioClient` |
| * `gremlin-python` |
| ** `org.apache.tinkerpop.gremlin.python.jsr223.*` |
| * `gremlin-server` |
| ** `org.apache.tinkerpop.gremlin.server.Settings.scriptEvaluationTimeout` |
| ** `org.apache.tinkerpop.gremlin.server.Settings.SslSettings.keyCertChainFile` |
| ** `org.apache.tinkerpop.gremlin.server.Settings.SslSettings.keyFile` |
| ** `org.apache.tinkerpop.gremlin.server.Settings.SslSettings.keyPassword` |
| ** `org.apache.tinkerpop.gremlin.server.Settings.SslSettings.trustCertificateChainFile` |
| ** `org.apache.tinkerpop.gremlin.server.ResponseHandlerContext` |
| ** `org.apache.tinkerpop.gremlin.server.channel.NioChannelizer` |
| ** `org.apache.tinkerpop.gremlin.server.handler.NioGremlinBinaryRequestDecoder` |
| ** `org.apache.tinkerpop.gremlin.server.handler.NioGremlinResponseFrameEncoder` |
| ** `org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor.evalOpInternal(ResponseHandlerContext, Supplier, BindingSupplier)` |
| ** `org.apache.tinkerpop.gremlin.server.op.AbstractOpProcessor.generateMetaData(ChannelHandlerContext, RequestMessage, ResponseStatusCode, Iterator)` |
| ** `org.apache.tinkerpop.gremlin.server.op.AbstractOpProcessor.handleIterator(ResponseHandlerContext, Iterator)` |
| ** `org.apache.tinkerpop.gremlin.server.op.AbstractOpProcessor.makeFrame(ChannelHandlerContext, RequestMessage, MessageSerializer, boolean, List, ResponseStatusCode, Map)` |
| ** `org.apache.tinkerpop.gremlin.server.op.AbstractOpProcessor.makeFrame(Context, RequestMessage, MessageSerializer, boolean, List, ResponseStatusCode, Map)` |
| ** `org.apache.tinkerpop.gremlin.server.op.AbstractOpProcessor.makeFrame(ResponseHandlerContext, RequestMessage, MessageSerializer, boolean, List, ResponseStatusCode, Map)` |
| ** `org.apache.tinkerpop.gremlin.server.op.AbstractOpProcessor.makeFrame(ResponseHandlerContext, RequestMessage, MessageSerializer, boolean, List, ResponseStatusCode, Map, Map)` |
| ** `org.apache.tinkerpop.gremlin.server.util.SideEffectIterator` |
| * `neo4j-gremlin` |
| ** `org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph#getTrait()` |
| ** `org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph#CONFIG_META_PROPERTIES` |
| ** `org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph#CONFIG_MULTI_PROPERTIES` |
| ** `org.apache.tinkerpop.gremlin.neo4j.structure.trait.MultiMetaNeo4jTrait` |
| ** `org.apache.tinkerpop.gremlin.neo4j.structure.trait.NoMultiNoMetaNeo4jTrait` |
| ** `org.apache.tinkerpop.gremlin.neo4j.structure.trait.Neo4jTrait` |
| |
| Certain elements of the API were not or could not be deprecated in prior versions and were simply renamed for this |
| release: |
| |
| * `org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode#SERVER_ERROR_SCRIPT_EVALUATION` became `SERVER_ERROR_EVALUATION` |
| |
| See: link:https://issues.apache.org/jira/browse/TINKERPOP-2080[TINKERPOP-2080], |
| link:https://issues.apache.org/jira/browse/TINKERPOP-2231[TINKERPOP-2231], |
| link:https://issues.apache.org/jira/browse/TINKERPOP-2233[TINKERPOP-2233], |
| link:https://issues.apache.org/jira/browse/TINKERPOP-2239[TINKERPOP-2239], |
| link:https://issues.apache.org/jira/browse/TINKERPOP-2269[TINKERPOP-2269], |
| link:https://issues.apache.org/jira/browse/TINKERPOP-2273[TINKERPOP-2273], |
| link:http://tinkerpop.apache.org/docs/3.5.0/upgrade/#_ssl_security[3.2.10 Upgrade Documentation for SSL] |
| |
| === Upgrading for Provider |
| |
| ==== Graph System Providers |
| |
| ===== ScalarMapStep |
| |
| `MapStep` had a single abstract method that needed to be implemented: |
| |
| [source,java] |
| ---- |
| protected abstract E map(final Traverser.Admin<S> traverser); |
| ---- |
| |
| This method made it easy to implement new implementations because it hid certain processing logic and made it so that |
| the implementer only had to reason about how to take the current object from the `Traverser` and transform it to a |
| new value. As 3.5.0 changed semantics around how `null` is processed, this method became a bit of a hindrance to the |
| more complex logic which those semantics entailed. Specifically, this method could not easily communicate to underlying |
| processing what a `null` might mean - is the `null` the end of the traversal stream or should the `null` be promoted |
| down the stream as a value to be processed. |
| |
| Interestingly, the method that enabled the handling of this more complex decision making already existed in |
| `AbstractStep`: |
| |
| [source,java] |
| ---- |
| protected Traverser.Admin<E> processNextStart() |
| ---- |
| |
| It returns a whole `Traverser` object and forces manual retrieval of the "next" `Traverser`. At this level it becomes |
| possible to make choices on `null` and return it if it should be propagated or dismiss it and return an |
| `EmptyTraverser`. To better accommodate the `MapStep` which provides the nice helper `map(Traverser)` method as well |
| as the more flexible version that doesn't need that infrastructure, `ScalarMapStep` was added to extend `MapStep`. The |
| `map(Traverser)` was then moved to `ScalarMapStep` and those steps that could rely on that helper method now extend |
| from it. All other steps of this sort still extend `MapStep` and directly implement `processNextStart()`. |
| |
| Providers will get compile errors if they extended `MapStep`. The easy solution will be to simply modify that code so |
| that their step instead extends `ScalarMapStep`. As a secondary task, providers should then examine their step |
| implementation to ensure that `null` semantics as presented in 3.5.0 apply properly. If they do not, then it is likely |
| that the step should simply implement `MapStep` directly and former `map(Traverser)` logic should be migrated to |
| `processNextStart()`. |
| |
| See: link:https://issues.apache.org/jira/browse/TINKERPOP-2235[TINKERPOP-2235], |
| link:https://issues.apache.org/jira/browse/TINKERPOP-2099[TINKERPOP-2099] |
| |
| ===== TraversalStrategy Application |
| |
| The methodology for strategy application has been altered and the change is most easily described by example. Given a |
| traversal with the structure: |
| |
| [source,text] |
| ---- |
| a(b(),c(d())) |
| ---- |
| |
| Strategies were formerly applied in the following order: |
| |
| [source,text] |
| ---- |
| StrategyA on a |
| StrategyB on a |
| StrategyA on b |
| StrategyB on b |
| StrategyA on c |
| StrategyB on c |
| StrategyA on d |
| StrategyB on d |
| ---- |
| |
| This approach has always prevented strategies from performing global operations across the traversal and all decedents |
| effectively as children will not have been processed by preceding strategies yet. As of this release, the approach |
| has been altered to apply strategies as follows: |
| |
| [source,text] |
| ---- |
| StrategyA on a |
| StrategyA on b |
| StrategyA on c |
| StrategyA on d |
| StrategyB on a |
| StrategyB on b |
| StrategyB on c |
| StrategyB on d |
| ---- |
| |
| In this way, strategy B can check if it is being applied to the root traversal and if it is it knows that A has been |
| applied globally. |
| |
| This revised methodology could represent a breaking change for `TraversalStrategy` implementations if they somehow |
| relied on the old ordering of application. It may also present an opportunity to revise how a `TraversalStrategy` is |
| written to gain some processing benefit to the new order. Please be sure to review any custom strategies carefully |
| when upgrading to this version. |
| |
| As part of this change, there have been some adjustments to the `Traversal` and `Traversal.Admin` interfaces which have |
| helped to clarify coding intent. There is now an `isRoot()` method which determines whether or not the traversal has a |
| parent or not. Under revised semantics for 3.5.0, a traversal's parent must be an `EmptyStep` instance and should not |
| be `null`. With this change, provider `TraversalStrategy` implementations should be reviewed to evaluate if `isRoot()` |
| semantics cause any breaks in logic to existing code. |
| |
| In addition, `TraversalStrategies` now implements `Iterable` and exposes an `iterator()` method which may be preferred |
| over the old `toList()` style construction for getting the list of configured strategies. |
| |
| See: link:https://issues.apache.org/jira/browse/TINKERPOP-1568[TINKERPOP-1568], |
| link:https://issues.apache.org/jira/browse/TINKERPOP-2310[TINKERPOP-2310], |
| link:https://issues.apache.org/jira/browse/TINKERPOP-2311[TINKERPOP-2311] |
| |
| ===== Null Semantics |
| |
| Graph providers should take note of the changes to `null` semantics described in the "users" section of these upgrade |
| notes. As `null` is now acceptable as a `Traverser` object, this change may affect custom steps. Further note that |
| `null` now works more consistently with mutation steps and graph providers may need to include additional logic to |
| deal with those possible conditions. Please see the console sessions below which uses TinkerGraph to demonstrate the |
| current behavioral expectations. |
| |
| [source,text] |
| ---- |
| gremlin> g.getGraph().features().vertex().supportsNullPropertyValues() |
| ==>false |
| gremlin> g.addV(null).property(id, null).property('name',null) |
| ==>v[0] |
| gremlin> g.V().elementMap() |
| ==>[id:0,label:vertex] |
| ... |
| gremlin> g.getGraph().features().vertex().supportsNullPropertyValues() |
| ==>true |
| gremlin> g.addV(null).property(id, null).property('name',null) |
| ==>v[0] |
| gremlin> g.V().elementMap() |
| ==>[id:0,label:vertex,name:null] |
| ---- |
| |
| In the above example, `addV()` defaults to `Vertex.DEFAULT_LABEL`, the `id` is generated and setting the "name" |
| property to `null` results in the value not being set. If the property value is set to an actual value and then set |
| to `null` TinkerGraph will remove the property key all together: |
| |
| [source,text] |
| ---- |
| gremlin> g.getGraph().features().vertex().supportsNullPropertyValues() |
| ==>false |
| gremlin> g.addV().property('name','stephen') |
| ==>v[0] |
| gremlin> g.V().elementMap() |
| ==>[id:0,label:vertex,name:stephen] |
| gremlin> g.V().has('vertex','name','stephen').property('name',null) |
| ==>v[0] |
| gremlin> g.V().elementMap() |
| ==>[id:0,label:vertex] |
| ... |
| gremlin> g.getGraph().features().vertex().supportsNullPropertyValues() |
| ==>true |
| gremlin> g.addV().property('name','stephen') |
| ==>v[2] |
| gremlin> g.V().has('vertex','name','stephen').property('name',null) |
| ==>v[2] |
| gremlin> g.V().elementMap() |
| ==>[id:2,label:vertex,name:null] |
| ---- |
| |
| The above examples point out the default operations of TinkerGraph, but it can be configured to actually accept the |
| `null` as a property value and it is up to graph providers to decided how they wish to treat a `null` property value. |
| Providers should use the new `supportsNullPropertyValues()` feature to indicate to users how `null` is handled. |
| |
| For edges, the `label` still cannot be defaulted and must be specified, therefore: |
| |
| [source,text] |
| ---- |
| gremlin> g.V(0L).as('a').addE(null).to('a') |
| Label can not be null |
| Type ':help' or ':h' for help. |
| Display stack trace? [yN]n |
| gremlin> g.V(0L).as('a').addE(constant(null)).to('a') |
| Label can not be null |
| Type ':help' or ':h' for help. |
| Display stack trace? [yN] |
| ---- |
| |
| Also, edges have similar behavior to vertices when it comes to setting properties (again, the default configuration for |
| TinkerGraph is being used here): |
| |
| [source,text] |
| ---- |
| gremlin> g.getGraph().features().vertex().supportsNullPropertyValues() |
| ==>false |
| gremlin> g.addV().property('name','stephen') |
| ==>v[0] |
| gremlin> g.V().has('vertex','name','stephen').as('a').addE('knows').to('a').property(id,null).property('weight',null) |
| ==>e[2][0-knows->0] |
| gremlin> g.E().elementMap() |
| ==>[id:2,label:knows,IN:[id:0,label:vertex],OUT:[id:0,label:vertex]] |
| gremlin> g.E().property('weight',0.5) |
| ==>e[2][0-knows->0] |
| gremlin> g.E().elementMap() |
| ==>[id:2,label:knows,IN:[id:0,label:vertex],OUT:[id:0,label:vertex],weight:0.5] |
| gremlin> g.E().property('weight',null) |
| ==>e[2][0-knows->0] |
| gremlin> g.E().elementMap() |
| ==>[id:2,label:knows,IN:[id:0,label:vertex],OUT:[id:0,label:vertex]] |
| ... |
| gremlin> g.getGraph().features().vertex().supportsNullPropertyValues() |
| ==>true |
| gremlin> g.addV().property('name','stephen') |
| ==>v[8] |
| gremlin> g.V().has('vertex','name','stephen').as('a').addE('knows').to('a').property(id,null).property('weight',null) |
| ==>e[10][8-knows->8] |
| gremlin> g.E().elementMap() |
| ==>[id:10,label:knows,IN:[id:8,label:vertex],OUT:[id:8,label:vertex],weight:null] |
| gremlin> g.E().property('weight',0.5) |
| ==>e[10][8-knows->8] |
| gremlin> g.E().elementMap() |
| ==>[id:10,label:knows,IN:[id:8,label:vertex],OUT:[id:8,label:vertex],weight:0.5] |
| gremlin> g.E().property('weight',null) |
| ==>e[10][8-knows->8] |
| gremlin> g.E().elementMap() |
| ==>[id:10,label:knows,IN:[id:8,label:vertex],OUT:[id:8,label:vertex],weight:null] |
| ---- |
| |
| Graphs that support multi/meta-properties have some issues to consider as well as demonstrated with TinkerGraph: |
| |
| [source,text] |
| ---- |
| gremlin> g.getGraph().features().vertex().supportsNullPropertyValues() |
| ==>false |
| gremlin> g.addV().property(list,'foo',"x").property(list,"foo", null).property(list,'foo','bar') |
| ==>v[0] |
| gremlin> g.V().elementMap() |
| ==>[id:0,label:vertex,foo:bar] |
| gremlin> g.V().valueMap() |
| ==>[foo:[x,bar]] |
| gremlin> g.V().property('foo',null) |
| ==>v[0] |
| gremlin> g.V().valueMap(true) |
| ==>[id:0,label:vertex] |
| ... |
| gremlin> g.addV().property(list,'foo','bar','x',1,'y',null) |
| ==>v[0] |
| gremlin> g.V().properties('foo').valueMap(true) |
| ==>[id:1,key:foo,value:bar,x:1] |
| gremlin> g.V().properties('foo').property('x',null) |
| ==>vp[foo->bar] |
| gremlin> g.V().properties('foo').valueMap(true) |
| ==>[id:1,key:foo,value:bar] |
| ... |
| gremlin> g.getGraph().features().vertex().supportsNullPropertyValues() |
| ==>false |
| gremlin> g.addV().property(list,'foo',"x").property(list,"foo", null).property(list,'foo','bar') |
| ==>v[11] |
| gremlin> g.V().elementMap() |
| ==>[id:11,label:vertex,foo:bar] |
| gremlin> g.V().valueMap() |
| ==>[foo:[x,null,bar]] |
| ... |
| gremlin> g.addV().property(list,'foo','bar','x',1,'y',null) |
| ==>v[0] |
| gremlin> g.V().properties('foo').valueMap(true) |
| ==>[id:1,key:foo,value:bar,x:1,y:null] |
| gremlin> g.V().properties('foo').property('x',null) |
| ==>vp[foo->bar] |
| gremlin> g.V().properties('foo').valueMap(true) |
| ==>[id:1,key:foo,value:bar,x:null,y:null] |
| ---- |
| |
| See: link:https://issues.apache.org/jira/browse/TINKERPOP-2235[TINKERPOP-2235], |
| link:https://issues.apache.org/jira/browse/TINKERPOP-2099[TINKERPOP-2099] |
| |
| ===== AbstractOpProcessor API Change |
| |
| The `generateMetaData()` method was removed as it was deprecated in a previous version. There already was a preferred |
| method called `generateResultMetaData()` that took an extra `Settings` parameter. To fix compilation issues simply |
| replace implementations of the `generateMetaData()` method with `generateResultMetaData()`. Gremlin Server has |
| only been calling `generateResultMetaData()` since the deprecation, so this correction should be straightforward. |
| |
| ===== StoreStep and AggregateStep |
| |
| Note that `StoreStep` has been renamed to `AggregateLocalStep` and `AggregateStep` has been renamed to |
| `AggregateGlobalStep`. The renaming is important to consider if any custom `TraversalStrategies` have been written |
| that rely on the old step names. |
| |
| See: link:https://issues.apache.org/jira/browse/TINKERPOP-2254[TINKERPOP-2254] |
| |
| ==== Graph Driver Providers |
| |
| ===== TraversalOpProcessor Side-effects |
| |
| `TraversalOpProcessor` no longer holds a cache of side-effects and more generally the entire side-effect protocol has |
| been removed and is no longer supported in the server or drivers. |
| |
| See: link:https://issues.apache.org/jira/browse/TINKERPOP-2269[TINKERPOP-2269] |