Equivalent of SQL JOIN in Gremlin

2,214 views
Skip to first unread message

Rupesh Khandelwal

unread,
Aug 5, 2013, 8:29:34 AM8/5/13
to gremli...@googlegroups.com
Hello,

I am using Gremlin 2.3.0. I am trying to write a traversal query equivalent to joining more than two tables in SQL. 

Considering simple model below; a movie is related to city where its showing, genre that it belongs to and stars it features. I need to get list of all movies by city, genre and stars. Let's say we have 2 movies having same 3 genres and same 6 stars. I am interested in getting a Cartesian product in the form of a table. 



Two Related Vertices (city -> movie -> genre): record count 6
  • SQL
    select cm.city_id, cm.movie_id, gm.genre_id
    from city_movie cm
    join genre_movie gm on cm.movie_id = gm.movie_id;
  • Gremlin
    g.V('type','city').as('city').out('showing').as('m1').in('in').as('genre')
Three or more related vertices (city -> movie -> genre -> movie -> star). Expected record count 36.
  • SQL
    select cm.movie_id, cm.city_id, gm.genre_id, sm.star_id
    from city_movie cm 
    join genre_movie gm on gm.movie_id = cm.movie_id
    join star_movie sm on sm.movie_id = gm.movie_id;
  • Gremlin
    Options that have not worked
    • back - if I use back to go from genre to movie then the record count goes to 2 and I loose valid combinations. Going to stars from here would result in record count of 12.
      g.V('type','city').as('city').out('showing').as('m1').in('in').as('genre').back('movie')
    • traverse movie again and then go to stars - Traversing movie again results in more combinations than needed and record count up to movies goes to 12 which I would like to keep at 6 as before.
      g.V('type','city').as('city').out('showing').as('m1').in('in').as('genre').out('in')

      I could use this if approach if I had a way to restrict the traversal to the movie that the path saw earlier, something like below. Following query does not compile, however it conveys what I need. 
      g.V('type','city').as('city').out('showing').as('m1').in('in').as('genre').out('in').has('movie_id', m1.movie_id)
I have found examples on following page useful - http://sql2gremlin.com/. Transform is used on this page for a more complicated example, I am not sure how transform can be used to solve problem mentioned above. Would appreciate any help towards solving this problem.  

Thanks,
Rupesh

Daniel Kuppitz

unread,
Aug 5, 2013, 9:01:14 AM8/5/13
to gremli...@googlegroups.com
Hi Rupesh,

gremlin> city.as("city").out("showing").as("movie").in("in").as("genre").out("in").retain("movie").in("acted").as("star").table().cap().next()
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #1], star:v[star #6]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #1], star:v[star #5]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #1], star:v[star #4]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #1], star:v[star #1]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #1], star:v[star #3]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #1], star:v[star #2]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #3], star:v[star #6]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #3], star:v[star #5]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #3], star:v[star #4]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #3], star:v[star #1]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #3], star:v[star #3]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #3], star:v[star #2]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #2], star:v[star #6]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #2], star:v[star #5]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #2], star:v[star #4]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #2], star:v[star #1]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #2], star:v[star #3]]
==>[city:v[city #1], movie:v[movie #2], genre:v[genre #2], star:v[star #2]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #1], star:v[star #2]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #1], star:v[star #6]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #1], star:v[star #5]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #1], star:v[star #1]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #1], star:v[star #4]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #1], star:v[star #3]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #3], star:v[star #2]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #3], star:v[star #6]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #3], star:v[star #5]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #3], star:v[star #1]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #3], star:v[star #4]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #3], star:v[star #3]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #2], star:v[star #2]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #2], star:v[star #6]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #2], star:v[star #5]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #2], star:v[star #1]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #2], star:v[star #4]]
==>[city:v[city #1], movie:v[movie #1], genre:v[genre #2], star:v[star #3]]

To reproduce it, initialize your graph with the following script:

g = new TinkerGraph()

city = g.addVertex('city #1')
movie1 = g.addVertex('movie #1')
movie2 = g.addVertex('movie #2')
genre1 = g.addVertex('genre #1')
genre2 = g.addVertex('genre #2')
genre3 = g.addVertex('genre #3')
star1 = g.addVertex('star #1')
star2 = g.addVertex('star #2')
star3 = g.addVertex('star #3')
star4 = g.addVertex('star #4')
star5 = g.addVertex('star #5')
star6 = g.addVertex('star #6')
city.addEdge("showing", movie1)
city.addEdge("showing", movie2)
genre1.addEdge("in", movie1)
genre1.addEdge("in", movie2)
genre2.addEdge("in", movie1)
genre2.addEdge("in", movie2)
genre3.addEdge("in", movie1)
genre3.addEdge("in", movie2)
star1.addEdge("acted", movie1)
star1.addEdge("acted", movie2)
star2.addEdge("acted", movie1)
star2.addEdge("acted", movie2)
star3.addEdge("acted", movie1)
star3.addEdge("acted", movie2)
star4.addEdge("acted", movie1)
star4.addEdge("acted", movie2)
star5.addEdge("acted", movie1)
star5.addEdge("acted", movie2)
star6.addEdge("acted", movie1)
star6.addEdge("acted", movie2)

Does that help?

Cheers,
Daniel



2013/8/5 Rupesh Khandelwal <rupesh.k...@gmail.com>

--
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/groups/opt_out.
 
 

Daniel Kuppitz

unread,
Aug 5, 2013, 9:10:00 AM8/5/13
to gremli...@googlegroups.com
A solution with transform:

city.as("city").out("showing").transform({ movie,m ->
  movie.in("in").transform({ genre ->
    movie.in("acted").transform({ star ->
      [ "city"  : m.city
      , "movie" : movie
      , "genre" : genre
      , "star"  : star ]
    })
  }).scatter()
}).scatter()

This one could be faster when genre nodes are supernodes.

Cheers,
Daniel



2013/8/5 Daniel Kuppitz <daniel....@shoproach.com>

Rupesh Khandelwal

unread,
Aug 5, 2013, 2:20:46 PM8/5/13
to gremli...@googlegroups.com
Daniel,

Excellent response! It helps. It shows that I can use potentially use retain to solve such problems. However I am not able to use it in my current environment - Gremlin 2.3.0 with Orient DB 1.3.0. I get following exception on calling retain. Is this expected to work with Gremlin 2.3.0? 

No signature of method: com.tinkerpop.gremlin.groovy.GremlinGroovyPipeline.retain() is applicable for argument types: (java.lang.String) values: [movie]
Possible solutions: retain(java.util.Collection), getAt(java.lang.String), join(java.lang.String), wait(), remove(), reset()
Display stack trace? [yN] y
groovy.lang.MissingMethodException: No signature of method: com.tinkerpop.gremlin.groovy.GremlinGroovyPipeline.retain() is applicable for argument types: (java.lang.String) values: [movie]
Possible solutions: retain(java.util.Collection), getAt(java.lang.String), join(java.lang.String), wait(), remove(), reset()
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55)
        at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:46)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
        at groovysh_evaluate.run(groovysh_evaluate:44)
        at groovysh_evaluate$run.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
        at groovysh_evaluate$run.call(Unknown Source)
        at org.codehaus.groovy.tools.shell.Interpreter.evaluate(Interpreter.groovy:67)
        at org.codehaus.groovy.tools.shell.Interpreter$evaluate.call(Unknown Source)
        at org.codehaus.groovy.tools.shell.Groovysh.execute(Groovysh.groovy:152)
        at org.codehaus.groovy.tools.shell.Shell.leftShift(Shell.groovy:114)
        at org.codehaus.groovy.tools.shell.Shell$leftShift$0.call(Unknown Source)
        at org.codehaus.groovy.tools.shell.ShellRunner.work(ShellRunner.groovy:88)
        at org.codehaus.groovy.tools.shell.InteractiveShellRunner.super$2$work(InteractiveShellRunner.groovy)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1047)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuperN(ScriptBytecodeAdapter.java:128)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuper0(ScriptBytecodeAdapter.java:148)
        at org.codehaus.groovy.tools.shell.InteractiveShellRunner.work(InteractiveShellRunner.groovy:100)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:267)
        at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:52)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:137)
        at org.codehaus.groovy.tools.shell.ShellRunner.run(ShellRunner.groovy:57)
        at org.codehaus.groovy.tools.shell.InteractiveShellRunner.super$2$run(InteractiveShellRunner.groovy)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1047)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuperN(ScriptBytecodeAdapter.java:128)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuper0(ScriptBytecodeAdapter.java:148)
        at org.codehaus.groovy.tools.shell.InteractiveShellRunner.run(InteractiveShellRunner.groovy:66)
        at com.tinkerpop.gremlin.groovy.console.Console.<init>(Console.java:50)
        at com.tinkerpop.gremlin.groovy.console.Console.<init>(Console.java:57)
        at com.tinkerpop.gremlin.groovy.console.Console.main(Console.java:62)

Thanks,
Rupesh

Daniel Kuppitz

unread,
Aug 5, 2013, 2:48:44 PM8/5/13
to gremli...@googlegroups.com
Referring to named steps in the retain step should definitely work since 2.3.0. I have no clue why OrientDB complains about it.

Luca, any idea?

Cheers,
Daniel

Luca Garulli

unread,
Aug 5, 2013, 3:01:45 PM8/5/13
to gremlin-users
Hi,
that seems an error of Gremlin Groovy. Try to update Gremlin jars.

groovy.lang.MissingMethodException: No signature of method: com.tinkerpop.gremlin.groovy.GremlinGroovyPipeline.retain() is applicable for argument types: (java.lang.String) values: [movie]

Lvc@

Rupesh Khandelwal

unread,
Aug 5, 2013, 3:14:50 PM8/5/13
to gremli...@googlegroups.com
Daniel & Luca,

Retain did not work on Gremlin console and OrientDB studio. However when I fired it through Java it went fine. So retain is a viable option for me. I will check it again after updating Gremlin jars.

On a different note I did not understand the expectation for transform approach to work faster if genre nodes are super nodes. In my environment nodes equivalent to movies can grow up to 50,000 and related vertex types (3 in example above - genre, city, star)  can go up to 15 each having nodes ranging from 1 to a couple thousands. A single query may need to use retain/transform logic 0 to 3/4 times depending upon user selection.  

Thanks,
Rupesh

Daniel Kuppitz

unread,
Aug 5, 2013, 3:44:05 PM8/5/13
to gremli...@googlegroups.com
Does the second query work you? I think retain will be too slow, because genre.out("in") will always iterate over all 50.000 movies.

Cheers,
Daniel

Luca Garulli

unread,
Aug 5, 2013, 5:11:20 PM8/5/13
to gremlin-users
OrientDB 1.4+ has many improvements on this, so I suggest you to upgrade to use all the new features. Why using an old version if you're in development phase yet? :-)

Lvc@

Rupesh Khandelwal

unread,
Aug 5, 2013, 7:05:16 PM8/5/13
to gremli...@googlegroups.com
Daniel,

As you may expect I would choose the faster query. Can you point me to or provide any example of doing similar transform function in Java. So far I have written basic pipe functions. This transform function seems to emit, traverse and prepare a table. An example will help in verifying this approach. Gremlin test class TransformStepTest.java has some basic examples, I need something that does traversal as well.  

Thanks,
Rupesh

Rupesh Khandelwal

unread,
Aug 5, 2013, 7:38:25 PM8/5/13
to gremli...@googlegroups.com
Luca,

We are under a tight schedule and about to wrap up development for graph related functionality. However work would continue in building automated functional test suite. It would be less costly for us to validate functionality with new OrientDB version after functional test suite is automated. And we plan to do it sometime down the line. 

Thanks,
Rupesh

Daniel Kuppitz

unread,
Aug 6, 2013, 3:37:00 AM8/6/13
to gremli...@googlegroups.com
Hi Rupesh,

I would write my second query in Java like this:

final PipesFunction<Vertex, List<Map<String, Object>>> transformer;
transformer = new PipesFunction<Vertex, List<Map<String, Object>>>() {
    @Override
    public final List<Map<String, Object>> compute(final Vertex movie) {
        final List<Map<String, Object>> result = new ArrayList<>();
        final Vertex city = (Vertex)this.asMap.get("city");
        final Iterable<Vertex> genres = movie.query().direction(Direction.IN).labels("in").vertices();
        final Iterable<Vertex> stars = movie.query().direction(Direction.IN).labels("acted").vertices();
        for (final Vertex genre : genres) {
            for (final Vertex star : stars) {
                result.add(new HashMap<String, Object>() {{
                    put("city", city);
                    put("movie", movie);
                    put("genre", genre);
                    put("star", star);
                }});
            }
        }
        return result;
    }
};
final GremlinPipeline pipe = new GremlinPipeline(city).as("city")
        .out("showing").transform(transformer).scatter();

for (Object row : pipe) {
    System.out.println(row);
}

Output:

{genre=v[genre #1], star=v[star #6], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #1], star=v[star #5], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #1], star=v[star #4], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #1], star=v[star #1], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #1], star=v[star #3], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #1], star=v[star #2], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #3], star=v[star #6], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #3], star=v[star #5], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #3], star=v[star #4], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #3], star=v[star #1], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #3], star=v[star #3], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #3], star=v[star #2], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #2], star=v[star #6], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #2], star=v[star #5], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #2], star=v[star #4], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #2], star=v[star #1], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #2], star=v[star #3], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #2], star=v[star #2], movie=v[movie #2], city=v[city #1]}
{genre=v[genre #1], star=v[star #2], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #1], star=v[star #6], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #1], star=v[star #5], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #1], star=v[star #1], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #1], star=v[star #4], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #1], star=v[star #3], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #3], star=v[star #2], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #3], star=v[star #6], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #3], star=v[star #5], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #3], star=v[star #1], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #3], star=v[star #4], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #3], star=v[star #3], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #2], star=v[star #2], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #2], star=v[star #6], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #2], star=v[star #5], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #2], star=v[star #1], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #2], star=v[star #4], movie=v[movie #1], city=v[city #1]}
{genre=v[genre #2], star=v[star #3], movie=v[movie #1], city=v[city #1]}

Cheers,
Daniel

Rupesh Khandelwal

unread,
Aug 6, 2013, 9:54:21 AM8/6/13
to gremli...@googlegroups.com
Daniel,

Thank you very much. Your responses have been very helpful and timely. 

Transform approach is clearer to me now. Retain approach seems to have one advantage over transform in my case. I am programatically building the gremlin query as per meta data. The nodes I traverse and columns I emit are driven from meta data. When I get to this join part I have emitted few vertices on pipeline. Through retain approach I can emit city, genre and star also and they are handled through my current design which gets data on all emitted vertices in a table by a call like below - 
pipeline.table(table, columnFunctions).toList();

Can I use the transform step to emit city, genre and star on pipeline, so that these vertices are also populated in above table?

Thanks,
Rupesh

Daniel Kuppitz

unread,
Aug 6, 2013, 10:37:55 AM8/6/13
to gremli...@googlegroups.com
Well, no, I don't think it's possible with transform. However, as always there isn't just one way of doing it. Solution #3:

final PipeFunction[] columnFunctions = new PipeFunction[] {
    new PipeFunction<Vertex, Object>() {
        @Override
        public final Object compute(Vertex v) {
            final String id = (String)v.getId();
            final int hashIndex = id.indexOf('#');
            return id.substring(hashIndex);
        }
    },
    new PipeFunction<Vertex, Object>() {
        @Override
        public final Object compute(Vertex v) {
            final String id = (String)v.getId();
            final int hashIndex = id.indexOf('#');
            return id.substring(hashIndex + 1);
        }
    },
    new PipeFunction<Vertex, Object>() {
        @Override
        public final Object compute(Vertex v) {
            return v.getId();
        }
    },
    new PipeFunction<Vertex, Object>() {
        @Override
        public final Object compute(Vertex v) {
            return ((String)v.getId()).toUpperCase();
        }
    }
};

final Table table = new Table();
new GremlinPipeline(city).as("city")
        .out("showing").as("movie")
        .in("in").as("genre").transform(new PipesFunction<Vertex, Vertex>() {
            @Override
            public final Vertex compute(final Vertex v) {
                return (Vertex)this.asMap.get("movie");
            }
        }).in("acted").as("star").table(table, columnFunctions).iterate();

for (Object row : table) {
    System.out.println(row);
}

Output:

[city:#1, movie:2, genre:genre #1, star:STAR #6]
[city:#1, movie:2, genre:genre #1, star:STAR #5]
[city:#1, movie:2, genre:genre #1, star:STAR #4]
[city:#1, movie:2, genre:genre #1, star:STAR #1]
[city:#1, movie:2, genre:genre #1, star:STAR #3]
[city:#1, movie:2, genre:genre #1, star:STAR #2]
[city:#1, movie:2, genre:genre #3, star:STAR #6]
[city:#1, movie:2, genre:genre #3, star:STAR #5]
[city:#1, movie:2, genre:genre #3, star:STAR #4]
[city:#1, movie:2, genre:genre #3, star:STAR #1]
[city:#1, movie:2, genre:genre #3, star:STAR #3]
[city:#1, movie:2, genre:genre #3, star:STAR #2]
[city:#1, movie:2, genre:genre #2, star:STAR #6]
[city:#1, movie:2, genre:genre #2, star:STAR #5]
[city:#1, movie:2, genre:genre #2, star:STAR #4]
[city:#1, movie:2, genre:genre #2, star:STAR #1]
[city:#1, movie:2, genre:genre #2, star:STAR #3]
[city:#1, movie:2, genre:genre #2, star:STAR #2]
[city:#1, movie:1, genre:genre #1, star:STAR #2]
[city:#1, movie:1, genre:genre #1, star:STAR #6]
[city:#1, movie:1, genre:genre #1, star:STAR #5]
[city:#1, movie:1, genre:genre #1, star:STAR #1]
[city:#1, movie:1, genre:genre #1, star:STAR #4]
[city:#1, movie:1, genre:genre #1, star:STAR #3]
[city:#1, movie:1, genre:genre #3, star:STAR #2]
[city:#1, movie:1, genre:genre #3, star:STAR #6]
[city:#1, movie:1, genre:genre #3, star:STAR #5]
[city:#1, movie:1, genre:genre #3, star:STAR #1]
[city:#1, movie:1, genre:genre #3, star:STAR #4]
[city:#1, movie:1, genre:genre #3, star:STAR #3]
[city:#1, movie:1, genre:genre #2, star:STAR #2]
[city:#1, movie:1, genre:genre #2, star:STAR #6]
[city:#1, movie:1, genre:genre #2, star:STAR #5]
[city:#1, movie:1, genre:genre #2, star:STAR #1]
[city:#1, movie:1, genre:genre #2, star:STAR #4]
[city:#1, movie:1, genre:genre #2, star:STAR #3]

Does that help?

Cheers,
Daniel



2013/8/6 Rupesh Khandelwal <rupesh.k...@gmail.com>

Rupesh Khandelwal

unread,
Aug 6, 2013, 12:29:18 PM8/6/13
to gremli...@googlegroups.com
Oh I see! This should work just fine. Transform function in solution #3 brings pipeline to earlier emitted movie node. That means I can use this.asMap in PipeFunction to access any of the emitted vertices. I believe this should be very fast and should outperform solution #1 with retain. 

Thanks,
Rupesh

Rupesh Khandelwal

unread,
Aug 7, 2013, 12:47:13 AM8/7/13
to gremli...@googlegroups.com
Daniel,

I have verified solution #3. It is working fine. Appreciate your help with this.

Thanks,
Rupesh
Reply all
Reply to author
Forward
0 new messages