Beginner problem: out() vs outE().inV()

2,589 views
Skip to first unread message

rsteppac

unread,
Jul 4, 2014, 5:57:45 AM7/4/14
to gremli...@googlegroups.com
I was under the impression that using out("label") was equivalent to outE("label").inV(). However, this seems to be a misconception.
The following will find me the path between two vertices, only following "trust" and "containment" edges:

pipe.start(start).as("startAt").out("TRUSTS", "CONTAINS").loop("startAt", new PipeFunction<LoopBundle<Vertex>, Boolean>() {
  public Boolean compute(LoopBundle<Vertex> lb) {...}
})...


But the following gives me a ClassCastException:

pipe.start(start).as("startAt").outE("TRUSTS", "CONTAINS").inV().loop("startAt", new PipeFunction<LoopBundle<Vertex>, Boolean>() {...})...

--> com.thinkaurelius.titan.graphdb.relations.CacheEdge cannot be cast to com.tinkerpop.blueprints.Vertex
at ch.vivates.poc.titan.Main$2.compute(Main.java:1)

The reason I changed from out() to outE().inV() is that I need to filter on a property of the "containment" edge, that is not follow the edge if a property does not have a certain value:

pipe.as("startAt").outE("TRUSTS", "CONTAINS").or(_().has("VERIFIED", Boolean.TRUE), _().has("TRUST_LEVEL")).inV().loop("startAt", new PipeFunction<LoopBundle<Vertex>, Boolean>() {...})...

with VERIFIED being a property of "containment edges" and "TRUST_LEVEL" being a property of "trust" edges.

How does the edge end up as an argument to my loop function?
Am I going about this the wrong way?

Thanks!
Ralf

Daniel Kuppitz

unread,
Jul 4, 2014, 10:12:04 AM7/4/14
to gremli...@googlegroups.com
Hi Ralf,

I can't reproduce your problem.

gremlin> g = TinkerGraphFactory.createTinkerGraph()
==>tinkergraph[vertices:6 edges:6]
gremlin> g.v(1).as("startAt").outE("knows","created").map()
==>{weight=0.5}
==>{weight=1.0}
==>{weight=0.4}
gremlin> g.v(1).as("startAt").outE("knows","created").or(_().has("weight", T.lt, 0.5f), _().has("weight", T.gt, 0.5f)).inV()
==>v[4]
==>v[3]
gremlin> g.v(1).as("startAt").outE("knows","created").or(_().has("weight", T.lt, 0.5f), _().has("weight", T.gt, 0.5f)).inV().loop("startAt", {true}, {true}).path()
==>[v[1], e[8][1-knows->4], v[4]]
==>[v[1], e[9][1-created->3], v[3]]
==>[v[1], e[8][1-knows->4], v[4], e[11][4-created->3], v[3]]
==>[v[1], e[8][1-knows->4], v[4], e[10][4-created->5], v[5]]

Can you please provide a complete code snippet?

Cheers,
Daniel



--
You received this message because you are subscribed to the Google Groups "Gremlin-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-user...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Message has been deleted

rsteppac

unread,
Jul 4, 2014, 10:38:14 AM7/4/14
to gremli...@googlegroups.com
Daniel,

thank you for your feedback. In that case I will use a filter instead.
I will file a bug with Pipes as well if this is not expected behavior.

Ralf


On Friday, July 4, 2014 4:26:19 PM UTC+2, Daniel Kuppitz wrote:
Nevermind, I just noticed that I actually reproduced the problem. See the difference in the last two lines:

gremlin> g.v(1).as("startAt").outE("knows","created").filter({ w = it.getProperty("weight"); w < 0.5f || w > 0.5f }).inV().loop("startAt", {true}, {true}).path()

==>[v[1], e[8][1-knows->4], v[4]]
==>[v[1], e[9][1-created->3], v[3]]
==>[v[1], e[8][1-knows->4], v[4], e[11][4-created->3], v[3]]
==>[v[1], e[8][1-knows->4], v[4], e[10][4-created->5], v[5]]

The reason why it worked for me was because I didn't explicitly set the types for the loop step (like you did it in Java). So it seems that .loop() and .or() don't play well together. You can use .filter() as a workaround.

Cheers,
Daniel

Daniel Kuppitz

unread,
Jul 4, 2014, 10:40:25 AM7/4/14
to gremli...@googlegroups.com
Ralf,

sorry for the confusion, but I already deleted my second response. I've seen things that were not there. Actually the first example did work as expected. However, I'll also try it in Java in a few minutes.

Cheers,
Daniel

Daniel Kuppitz

unread,
Jul 4, 2014, 11:24:57 AM7/4/14
to gremli...@googlegroups.com
Ok, Java also works as expected for me: https://gist.github.com/dkuppitz/8963875880df87145192
Maybe the problem is the IdentityStep on your side. In Java you shouldn't be able to do a simple _(), hence it must be a custom implementation made by you.

Cheers,
Daniel

rsteppac

unread,
Jul 4, 2014, 1:38:33 PM7/4/14
to gremli...@googlegroups.com
Hm... So this is my code:

    private static GremlinPipeline<Edge, Edge> _E() {
        return new GremlinPipeline<Edge, Edge>(new IdentityPipe<Edge>());
    }

    private static List<List<String>> findPathsBetween(final Graph graph, final Vertex start, final Vertex end, final int maxTreeDepth) {
        final Long end_id = (Long) end.getId();

        GremlinPipeline<Vertex, List<String>> pipe = new GremlinPipeline<>(start);
        pipe.as("startAt").outE(TRUSTS, CONTAINS).or(_E().has(VERIFIED, Boolean.TRUE), _E().has(TRUST_LEVEL)).inV().loop("startAt", new PipeFunction<LoopBundle<Vertex>, Boolean>() {
            @Override

            public Boolean compute(LoopBundle<Vertex> lb) {
                boolean doContinue = true;
                LOG.debug("Loop cnt: " + lb.getLoops() + "; vertex id: " + lb.getObject().getId() + "; OU name: " + lb.getObject().getProperty(ORG_NAME) + "; HPI ID: " + lb.getObject().getProperty(HPI_ID));
                if (lb.getLoops() > maxTreeDepth) {
                    throw new RuntimeException("Path too long. Caught in cyclical sub-graph? Path: " + lb.getPath());
                } else if (end_id.equals(lb.getObject().getId())) {
                    doContinue = false;
                }
                return doContinue;
            }
        }).path(new PipeFunction<Vertex, String>() {
            @Override
            public String compute(Vertex v) {
                String result = null;
                if (v.getProperty(ORG_NAME) != null) {
                    result = v.getProperty(ORG_NAME).toString();
                } else if (v.getProperty(HPI_ID) != null) {
                    result = v.getProperty(HPI_ID).toString();
                } else if (v.getProperty(MPI_ID) != null) {
                    result = v.getProperty(MPI_ID).toString();
                }
                return result;
            }
        });

        LOG.debug("The pipeline: " + pipe.toString());

        return pipe.toList();
    }



Ralf

Daniel Kuppitz

unread,
Jul 4, 2014, 6:23:03 PM7/4/14
to gremli...@googlegroups.com
Hi Ralf,

now it makes sense. Your path-closure only accepts vertices, but the path contains vertices and edges, hence the type conversion error. Try this:

.path(new PipeFunction<Element, String>() {
    @Override
    public String compute(Element e) {
        String result = null;
        if (e.getProperty(ORG_NAME) != null) {
            result = e.getProperty(ORG_NAME).toString();
        } else if (e.getProperty(HPI_ID) != null) {
            result = e.getProperty(HPI_ID).toString();
        } else if (e.getProperty(MPI_ID) != null) {
            result = e.getProperty(MPI_ID).toString();
        }
        return result;
    }
})

Cheers,
Danel



rsteppac

unread,
Jul 5, 2014, 4:11:27 AM7/5/14
to gremli...@googlegroups.com
Danel,

thanks for your answer. I know that the path contains vertices and edges. I got that from the error message. :-)  What I do not understand is why that is so. I loop after the pipe element inV(). So the pipe that feeds elements into the loop should only emit vertices, should it not? Could you tell me where my misunderstanding in the workings of pipes is?

Thanks!
Ralf

Daniel Kuppitz

unread,
Jul 5, 2014, 8:16:53 AM7/5/14
to gremli...@googlegroups.com
 I loop after the pipe element inV()

Yes, but the whole traversal (the path to inV) also touches edges. See, this traversal touches only vertices:

gremlin> g.v(1).out().out().path()
==>[v[1], v[4], v[3]]
==>[v[1], v[4], v[5]]


...but this traversal on the other hand touches the same vertices, but also the edges between them:

gremlin> g.v(1).outE().inV().outE().inV().path()

==>[v[1], e[8][1-knows->4], v[4], e[11][4-created->3], v[3]]
==>[v[1], e[8][1-knows->4], v[4], e[10][4-created->5], v[5]]


If you only need the vertices, but the edges are required for filtering, you'll have to remove the edges from the paths:

gremlin> g.v(1).outE().inV().outE().inV().path().transform({ it.grep(Vertex.class) })
==>[v[1], v[4], v[3]]
==>[v[1], v[4], v[5]]

Cheers,
Daniel



rsteppac

unread,
Jul 6, 2014, 3:33:38 AM7/6/14
to gremli...@googlegroups.com
Daniel,

thanks again for your help.

Ralf
Message has been deleted

Daniel Kuppitz

unread,
Jul 7, 2014, 9:59:48 AM7/7/14
to gremli...@googlegroups.com
Hi Ralf,

then the question is: why am I not able to reproduce it? Which graph database +  version do you use? Can you provide a full data set and complete query to reproduce the error? It would be great, if you can reproduce it on the Tinkergraph.

Cheers,
Daniel



2014-07-07 9:09 GMT+02:00 rsteppac <ralf.st...@vivates.ch>:
Daniel,

that does not work. The exception is raised in the compute function of loop(), not path(). At the same time, because loop follows the call to inV(), I am forced by the compiler to parametrize the pipe function as <Vertex,Boolean>. But the pipe element receives an Edge nevertheless. This still looks like a bug in Pipes to me.


Ralf


On Saturday, July 5, 2014 12:23:03 AM UTC+2, Daniel Kuppitz wrote:
Reply all
Reply to author
Forward
0 new messages