I think there's a bug in mergeE(). Here's my setup in neptune
g.V().hasLabel('mytestlabel').drop()
g.addV('mytestlabel').property(id, 'testA').property('timestamp', 1).as('a')
.addV('mytestlabel').property(id, 'testA2').property('timestamp', 1).as('a2')
.addE('mytestlabel').from('a').to('a2').property('timestamp', 2).valueMap(true)
This generates my simple 2-node graph with an edge, output as expected is:
{<T.label: 4>: 'mytestlabel', <T.id: 1>: 'testA', 'timestamp': [1]}
{<T.label: 4>: 'mytestlabel', <T.id: 1>: 'testA2', 'timestamp': [1]}
{<T.label: 4>: 'mytestlabel', <T.id: 1>: '2cc6d009-4138-8b71-c016-6aa58927fe2f', 'timestamp': 2}}
Now, let's update the edge's timestamp
g.mergeE([(T.label):'mytestlabel', (Direction.from): 'testA', (Direction.to):'testA2'])
.option(onMatch, ['timestamp': 3]).valueMap(true)
As expected we get
{<T.label: 4>: 'mytestlabel', <T.id: 1>: '2cc6d009-4138-8b71-c016-6aa58927fe2f', 'timestamp': 3}
Let's try an incorrect merge syntax; using the cardinality single syntax for vertexes
g.mergeE([(T.label):'mytestlabel', (Direction.from): 'testA', (Direction.to):'testA2'])
.option(onMatch, sideEffect(property(single, 'timestamp', 4)
.property(single, 'edgelabel', 'exists'))
.constant([:])).valueMap(true)
As expected, it errors out:
Property cardinality can only be set for a Vertex but the traversal encountered NeptuneEdge for key: timestamp
Double checking our vertexes, they haven't changed:
{<T.label: 4>: 'mytestlabel', <T.id: 1>: 'testA', 'timestamp': [1]}
{<T.label: 4>: 'mytestlabel', <T.id: 1>: 'testA2', 'timestamp': [1]}
Now, let's add a .V() to the front of the incorrect merge:
g.V().mergeE([(T.label):'mytestlabel', (Direction.from): 'testA', (Direction.to):'testA2'])
.option(onMatch, sideEffect(property(single, 'timestamp', 4)
.property(single, 'edgelabel', 'exists'))
.constant([:])).valueMap(true)
This works! But in a weird way, our edge hasn't changed, but our vertexes have. A g.V() and g.E() gives us:
{<T.label: 4>: 'mytestlabel', <T.id: 1>: 'testA', 'edgelabel': ['exists'], 'timestamp': [4]}
{<T.label: 4>: 'mytestlabel', <T.id: 1>: 'testA2', 'edgelabel': ['exists'], 'timestamp': [4]}
{<T.label: 4>: 'mytestlabel', <T.id: 1>: '2cc6d009-4138-8b71-c016-6aa58927fe2f', 'timestamp': 3}
It also seems that this "incorrect" query executed once per node, I'm guessing because of the V(). Doing a g.V().count gave me 1280 exactly:

I've fixed my code so that I'm not doing .V().mergeE() and it works fine now, but I wanted to know what was happening; I think this is a bug? I can't think of why mergeEdge would ever update a vertex.
Originally I did .V().mergeE() since I was doing a big batch query and just left the .V() in there. I was getting performance issues (I'm guessing because it was executing per node in the graph) as well as incorrect values on my vertex+edges.
edit: If you try this incorrect syntax when the edge doesn't exist, it will create the edge with no properties other than label/id. If you have a 3 node graph (a-a2, a-a3), then it executes nodecount^2:
