Rexster create edge error with OrientDB

434 views Asked by At

I'm using python bulbs with Rexster and OrientDB. I'm trying to create an edge, but I get this error:

>> g.edges.create(g.V[0], "aoeu", g.V[1])
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/bulbs/element.py", line 879, in create
    resp = self.client.create_edge(outV, label, inV, data, keys=_keys)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rexster/client.py", line 454, in create_edge
    return self.create_indexed_edge(outV,label,inV,data,index_name,keys=keys)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rexster/client.py", line 990, in create_indexed_edge
    resp = self.gremlin(script,params)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rexster/client.py", line 356, in gremlin
    return self.request.post(gremlin_path, params)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rest.py", line 131, in post
    return self.request(POST, path, params)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rest.py", line 186, in request
    return self.response_class(http_resp, self.config)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rexster/client.py", line 198, in __init__
    self.handle_response(response)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rexster/client.py", line 222, in handle_response
    response_handler(http_resp)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rest.py", line 50, in server_error
    raise SystemError(http_resp)
SystemError: ({'status': '500', 'transfer-encoding': 'chunked', 'server': 'grizzly/2.2.16', 'connection': 'close', 'date': 'Fri, 24 Jan 2014 19:49:10 GMT', 'access-control-allow-origin': '*', 'content-type':
 'application/json'}, '{"message":"","error":"javax.script.ScriptException: java.lang.ClassCastException: com.orientechnologies.orient.core.id.ORecordId cannot be cast to com.orientechnologies.orient.core.re
cord.ORecord","api":{"description":"evaluate an ad-hoc Gremlin script for a graph.","parameters":{"rexster.returnKeys":"an array of element property keys to return (default is to return all element propertie
s)","rexster.showTypes":"displays the properties of the elements with their native data type (default is false)","load":"a list of \'stored procedures\' to execute prior to the \'script\' (if \'script\' is n
ot specified then the last script in this argument will return the values","rexster.offset.end":"end index for a paged set of data to be returned","rexster.offset.start":"start index for a paged set of data
to be returned","params":"a map of parameters to bind to the script engine","language":"the gremlin language flavor to use (default to groovy)","script":"the Gremlin script to be evaluated"}},"success":false
}')

The funny thing is when I execute the command again, it works, BUT I get 2 edges created, which is WRONG.

On my Rexster server,

I get this error

....
at Script5.run(Script5.groovy:23)
    at com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine.eval(GremlinGroovyScriptEngine.java:219)
    ... 58 more
[WARN] GraphResource - The [tp:gremlin+*] extension raised an error response.

my graph config

    <graph>
        <graph-enabled>true</graph-enabled>
        <graph-name>orientdb</graph-name>
        <graph-type>orientgraph</graph-type>
        <graph-location>local:/tmp/orientdb</graph-location>
        <properties>
            <username>admin</username>
            <password>admin</password>
        </properties>
        <extensions>
            <allows>
                <allow>tp:gremlin</allow>
            </allows>
        </extensions>
    </graph>

What is the error I keep getting, and how do I fix it?

Added DEBUG info:

>>> from bulbs.rexster import DEBUG
>>> g.config.set_logger(DEBUG)
>>> g.edges.create(g.V[0], "a", g.V[1])
POST url:  http://localhost:8182/graphs/orientdb/tp/gremlin  
POST url:  http://localhost:8182/graphs/orientdb/tp/gremlin  
POST url:  http://localhost:8182/graphs/orientdb/tp/gremlin  
POST url:  http://localhost:8182/graphs/orientdb/tp/gremlin  
POST body: {"params": null, "script": "g.getVertices()"} 
POST body: {"params": null, "script": "g.getVertices()"} 
POST body: {"params": null, "script": "g.getVertices()"} 
POST body: {"params": null, "script": "g.getVertices()"} 
POST url:  http://localhost:8182/graphs/orientdb/tp/gremlin  
POST url:  http://localhost:8182/graphs/orientdb/tp/gremlin  
POST url:  http://localhost:8182/graphs/orientdb/tp/gremlin  
POST url:  http://localhost:8182/graphs/orientdb/tp/gremlin  
POST body: {"params": null, "script": "g.getVertices()"} 
POST body: {"params": null, "script": "g.getVertices()"} 
POST body: {"params": null, "script": "g.getVertices()"} 
POST body: {"params": null, "script": "g.getVertices()"} 
POST url:  http://localhost:8182/graphs/orientdb/tp/gremlin  
POST url:  http://localhost:8182/graphs/orientdb/tp/gremlin  
POST url:  http://localhost:8182/graphs/orientdb/tp/gremlin  
POST url:  http://localhost:8182/graphs/orientdb/tp/gremlin  
POST body: {"params": {"label_var": "label", "outV": "#9:0", "keys": null, "data": {}, "inV": "#9:1", "index_name": "edge", "label": "a"}, "script": "def createIndexedEdge = {\n    index = g.idx(index_name)\n    edge = g.addEdge(g.v(outV),g.v(inV),label)\n    for (entry in data.entrySet()) {\n      if (entry.value == null) continue;\n      edge.setProperty(entry.key,entry.value)\n      if (keys == null || keys.contains(entry.key))\n\tindex.put(entry.key,String.valueOf(entry.value),edge)\n    }\n    index.put(label_var,String.valueOf(label),edge)\n    return edge\n  }\n  def transaction = { final Closure closure ->\n    try {\n      results = closure();\n      g.commit();\n      return results; \n    } catch (e) {\n      g.rollback();\n      throw e;\n    }\n  }\n  return transaction(createIndexedEdge);"} 
POST body: {"params": {"label_var": "label", "outV": "#9:0", "keys": null, "data": {}, "inV": "#9:1", "index_name": "edge", "label": "a"}, "script": "def createIndexedEdge = {\n    index = g.idx(index_name)\n    edge = g.addEdge(g.v(outV),g.v(inV),label)\n    for (entry in data.entrySet()) {\n      if (entry.value == null) continue;\n      edge.setProperty(entry.key,entry.value)\n      if (keys == null || keys.contains(entry.key))\n\tindex.put(entry.key,String.valueOf(entry.value),edge)\n    }\n    index.put(label_var,String.valueOf(label),edge)\n    return edge\n  }\n  def transaction = { final Closure closure ->\n    try {\n      results = closure();\n      g.commit();\n      return results; \n    } catch (e) {\n      g.rollback();\n      throw e;\n    }\n  }\n  return transaction(createIndexedEdge);"} 
POST body: {"params": {"label_var": "label", "outV": "#9:0", "keys": null, "data": {}, "inV": "#9:1", "index_name": "edge", "label": "a"}, "script": "def createIndexedEdge = {\n    index = g.idx(index_name)\n    edge = g.addEdge(g.v(outV),g.v(inV),label)\n    for (entry in data.entrySet()) {\n      if (entry.value == null) continue;\n      edge.setProperty(entry.key,entry.value)\n      if (keys == null || keys.contains(entry.key))\n\tindex.put(entry.key,String.valueOf(entry.value),edge)\n    }\n    index.put(label_var,String.valueOf(label),edge)\n    return edge\n  }\n  def transaction = { final Closure closure ->\n    try {\n      results = closure();\n      g.commit();\n      return results; \n    } catch (e) {\n      g.rollback();\n      throw e;\n    }\n  }\n  return transaction(createIndexedEdge);"} 
POST body: {"params": {"label_var": "label", "outV": "#9:0", "keys": null, "data": {}, "inV": "#9:1", "index_name": "edge", "label": "a"}, "script": "def createIndexedEdge = {\n    index = g.idx(index_name)\n    edge = g.addEdge(g.v(outV),g.v(inV),label)\n    for (entry in data.entrySet()) {\n      if (entry.value == null) continue;\n      edge.setProperty(entry.key,entry.value)\n      if (keys == null || keys.contains(entry.key))\n\tindex.put(entry.key,String.valueOf(entry.value),edge)\n    }\n    index.put(label_var,String.valueOf(label),edge)\n    return edge\n  }\n  def transaction = { final Closure closure ->\n    try {\n      results = closure();\n      g.commit();\n      return results; \n    } catch (e) {\n      g.rollback();\n      throw e;\n    }\n  }\n  return transaction(createIndexedEdge);"} 
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/bulbs/element.py", line 879, in create
    resp = self.client.create_edge(outV, label, inV, data, keys=_keys)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rexster/client.py", line 454, in create_edge
    return self.create_indexed_edge(outV,label,inV,data,index_name,keys=keys)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rexster/client.py", line 990, in create_indexed_edge
    resp = self.gremlin(script,params)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rexster/client.py", line 356, in gremlin
    return self.request.post(gremlin_path, params)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rest.py", line 131, in post
    return self.request(POST, path, params)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rest.py", line 186, in request
    return self.response_class(http_resp, self.config)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rexster/client.py", line 198, in __init__
    self.handle_response(response)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rexster/client.py", line 222, in handle_response
    response_handler(http_resp)
  File "/usr/local/lib/python2.7/dist-packages/bulbs/rest.py", line 50, in server_error
    raise SystemError(http_resp)
SystemError: ({'status': '500', 'transfer-encoding': 'chunked', 'server': 'grizzly/2.2.16', 'connection': 'close', 'date': 'Mon, 27 Jan 2014 18:33:00 GMT', 'access-control-allow-origin': '*', 'content-type': 'application/json'}, '{"message":"","error":"javax.script.ScriptException: java.lang.ClassCastException: com.orientechnologies.orient.core.id.ORecordId cannot be cast to com.orientechnologies.orient.core.record.ORecord","api":{"description":"evaluate an ad-hoc Gremlin script for a graph.","parameters":{"rexster.returnKeys":"an array of element property keys to return (default is to return all element properties)","rexster.showTypes":"displays the properties of the elements with their native data type (default is false)","load":"a list of \'stored procedures\' to execute prior to the \'script\' (if \'script\' is not specified then the last script in this argument will return the values","rexster.offset.end":"end index for a paged set of data to be returned","rexster.offset.start":"start index for a paged set of data to be returned","params":"a map of parameters to bind to the script engine","language":"the gremlin language flavor to use (default to groovy)","script":"the Gremlin script to be evaluated"}},"success":false}')
2

There are 2 answers

0
Derek On BEST ANSWER

Fixed in OrientDB 1.7, see https://github.com/tinkerpop/rexster/issues/341 for more info.

2
espeed On

If you turn debugging on in Bulbs, you can see the command and params Bulbs is sending to Rexster:

>>> from bulbs.rexster import Graph, DEBUG
>>> g = Graph()
>>> g.config.set_logger(DEBUG)
>>> g.edges.create(g.V[0], "aoeu", g.V[1])

Here g.edges.create()...

https://github.com/espeed/bulbs/blob/master/bulbs/element.py#L854

def create(self, outV, label, inV, _data=None, _keys=None, **kwds):
    """
    Creates an edge in the database and returns it.

    :param outV: The outgoing vertex. 
    :type outV: Vertex or int

    :param label: The edge's label.
    :type label: str

    :param inV: The incoming vertex. 
    :type inV: Vertex or int

    :param _data: Optional property data dict.
    :type _data: dict

    :param kwds: Optional property data keyword pairs. 
    :type kwds: dict

    :rtype: Edge

    """ 
    assert label is not None
    data = build_data(_data, kwds)
    outV, inV = coerce_vertices(outV, inV)
    resp = self.client.create_edge(outV, label, inV, data, keys=_keys)
    return initialize_element(self.client, resp.results)

...is calling the low-level client.create_edge() method...

https://github.com/espeed/bulbs/blob/master/bulbs/rexster/client.py#L433

# Edge Proxy

def create_edge(self, outV, label, inV, data={}, keys=None): 
    """
    Creates a edge and returns the Response.

    :param outV: Outgoing vertex ID.
    :type outV: int

    :param label: Edge label.
    :type label: str

    :param inV: Incoming vertex ID.
    :type inV: int

    :param data: Property data.
    :type data: dict or None

    :rtype: RexsterResponse

    """
    if keys or self.config.autoindex is True:
        index_name = self.config.edge_index
        return self.create_indexed_edge(outV,label,inV,data,index_name,keys=keys)
    data = self._remove_null_values(data)
    edge_data = dict(_outV=outV,_label=label,_inV=inV)
    data.update(edge_data)
    return self.request.post(edge_path, data)

...and if you have config.autoindex set to True (which is the default), then it ultimately calls client.create_indexed_edge()...

https://github.com/espeed/bulbs/blob/master/bulbs/rexster/client.py#L960

def create_indexed_edge(self, outV, label, inV, data, index_name, keys=None):
    """
    Creates a edge, indexes it, and returns the Response.

    :param outV: Outgoing vertex ID.
    :type outV: int

    :param label: Edge label.
    :type label: str

    :param inV: Incoming vertex ID.
    :type inV: int

    :param data: Property data.
    :type data: dict

    :param index_name: Name of the index.
    :type index_name: str

    :param keys: Property keys to index. Defaults to None (indexes all properties).
    :type keys: list

    :rtype: RexsterResponse

    """
    data = self._remove_null_values(data)
    edge_params = dict(outV=outV,label=label,inV=inV,label_var=self.config.label_var)
    params = dict(data=data,index_name=index_name,keys=keys)
    params.update(edge_params)
    script = self.scripts.get("create_indexed_edge")
    resp = self.gremlin(script,params)
    resp.results = resp.one()
    return resp

...notice the client.create_indexed_edge() Python method sends the body of the create_indexed_edge() Gremlin script to Rexster...

https://github.com/espeed/bulbs/blob/master/bulbs/rexster/gremlin.groovy#L75

// from Bulbs/Rexster gremlin.groovy

def create_indexed_edge(outV,label,inV,data,index_name,keys,label_var) {
  def createIndexedEdge = {
    index = g.idx(index_name)
    edge = g.addEdge(g.v(outV),g.v(inV),label)
    for (entry in data.entrySet()) {
      if (entry.value == null) continue;
      edge.setProperty(entry.key,entry.value)
      if (keys == null || keys.contains(entry.key))
        index.put(entry.key,String.valueOf(entry.value),edge)
    }
    index.put(label_var,String.valueOf(label),edge)
    return edge
  }
  def transaction = { final Closure closure ->
    try {
      results = closure();
      g.commit();
      return results; 
    } catch (e) {
      g.rollback();
      throw e;
    }
  }
  return transaction(createIndexedEdge);
}