Can't make the pattern matching with a single gremlin statement

130 views
Skip to first unread message

Prjio San

unread,
Mar 27, 2013, 10:28:39 AM3/27/13
to gremli...@googlegroups.com
I have a graph with dependencies:

    dep1 -> dep2 -> ... -> dep3 -> ...
        |                   ^
        +-> dep4            |
        |                   |
        +-------------------+

I'm looking for unnecessary dependencies, which are those where a direct link exists, but also a link through a sub-dependency. In the above example, the link "dep1 -> dep3" is unnecessary.

The cypher statement to find those would be:

    start n = node(*)
    match n -[:dependency]-> n2,
     n -[:dependency*2..]-> n2
     with n, n2
    return distinct id(n), n.name, id(n2), n2.name

I tried to solve this issue with a single gremlin statement (with the "table"-step), but I just couldn't make it work. Is this even possible or do I have to solve this with multiple statements?

Any hints, tips, ideas would be appreciated.

Thanks in advance

Marko Rodriguez

unread,
Mar 27, 2013, 12:24:25 PM3/27/13
to gremli...@googlegroups.com
Hi,

For a single vertex, lets say g.v(1), its:
x = [];
g.v(1).out('dependency').aggregate(x).out('dependency').loop(1){true}{true}.retain(x)

If you want this in a table-form, then do:

g.v(1).as('a').out('dependency').aggregate(x).out.loop(1){true}{true}.retain(x).as('b').select

With the select you can also provide closures to get whatever other metadata you want from the two emitted vertices.

Finally, if you want to do this for the whole graph, do:

g.V.transform {
x = []
it.as('a').out('dependency').aggregate(x).out('dependency').loop(1){true}{true}.retain(x).as('b').select
}

HTH,
Marko.


--
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.
 
 

Prjio San

unread,
Mar 28, 2013, 11:09:40 AM3/28/13
to gremli...@googlegroups.com
Hi Marko,

thanks for the reply, but unfortunately it doesn't work yet :(. I've created an example-graph (with yEd): https://gist.github.com/am-jo/b7e489dec05e88ff9a62
The edgeLabelKey is "d11":

g = new Neo4jGraph('/tmp/dependencies.db');
gr = new GraphMLReader(g);
gr.setEdgeLabelKey('d11');
gr.inputGraph(new FileInputStream('/tmp/gistfile1.xml'));

The expected result would be the dependency between foo(14) and bar(23).

Thanks for your time and effort.

PS: I tried to attach the file, but google just wouldn't let me upload it. That's why I'm posting the sample as gist.

Stephen Mallette

unread,
Mar 28, 2013, 3:08:38 PM3/28/13
to gremli...@googlegroups.com
I loaded your graphml into a tinkergraph and used Marko's gremlin with
just a few edits (all trivial):

gremlin> x=[];g.v("n13").as('a').out.aggregate(x).out.loop(1){true}{true}.retain(x).as('b').select{it.name}
==>[a:foo, b:bar]

His approach seems to find foo and bar which is what i understood you expected.

Stephen

Prjio San

unread,
Mar 28, 2013, 3:57:47 PM3/28/13
to gremli...@googlegroups.com
The single search works, but the search over the whole graph doesn't work yet. My apologies, for being unclear.
I receive a list of string representations of paths, after the transform.

Stephen Mallette

unread,
Mar 28, 2013, 4:18:20 PM3/28/13
to gremli...@googlegroups.com
You just need to iterate the pipe inside the transform:

gremlin> g.V.as('start').transform{s->x=[];s.as('a').out.aggregate(x).out.loop(1){true}{true}.retain(x).as('b').select{it.name}.toList()}.as('dependencies').select{it.name}{it}
==>[start:bob, dependencies:[]]
==>[start:a, dependencies:[]]
==>[start:a, dependencies:[]]
==>[start:bar, dependencies:[]]
==>[start:baz, dependencies:[]]
==>[start:a, dependencies:[]]
==>[start:a, dependencies:[]]
==>[start:a, dependencies:[]]
==>[start:bert, dependencies:[]]
==>[start:a, dependencies:[[a:a, b:ben]]]
==>[start:a, dependencies:[]]
==>[start:ben, dependencies:[]]
==>[start:a, dependencies:[]]
==>[start:a, dependencies:[]]
==>[start:mike, dependencies:[]]
==>[start:a, dependencies:[]]
==>[start:a, dependencies:[]]
==>[start:a, dependencies:[[a:a, b:a]]]
==>[start:a, dependencies:[[a:a, b:jim], [a:a, b:noodle], [a:a,
b:jim], [a:a, b:noodle], [a:a, b:jim], [a:a, b:foo], [a:a, b:a], [a:a,
b:noodle], [a:a, b:noodle], [a:a, b:jim], [a:a, b:jim]]]
==>[start:jim, dependencies:[]]
==>[start:foo, dependencies:[[a:foo, b:bar]]]
==>[start:a, dependencies:[]]
==>[start:noodle, dependencies:[[a:noodle, b:ben]]]
==>[start:a, dependencies:[]]

you may want to tweak that a bit depending on your result needs, but
note that I just added a toList() within the transform operation to
iterate the pipe.

Stephen

Prjio San

unread,
Mar 29, 2013, 1:13:10 PM3/29/13
to gremli...@googlegroups.com
Yes, this is pretty much it:

g.V.transform{
    s -> singleStep = [];
    s.as('origin')
        .out('dependency').aggregate(singleStep)
        .out('dependency')
            .loop(1){ true }{ true }
        .retain(singleStep).as('redundant')
        .dedup()
        .table(new Table(), ['origin', 'redundant']){ it.name + '(' + it.id + ')' }
        .cap().next()
}.filter{ it.size() > 0 }

Thanks a lot, guys.
Reply all
Reply to author
Forward
0 new messages