Gremlin query

58 views
Skip to first unread message

Alexei Tenitski

unread,
Mar 12, 2012, 5:05:24 PM3/12/12
to ne...@googlegroups.com
Hi there,

I've started playing with Neo4j and Gremlin and here is a query which I
have problems with.

Say we have a following graph

company -> person -> location

People have a relationship with a location node, companies not.

I want to get company location using most common location of company
employee or, slightly different query, get all companies in a specific
location again based on location of majority of people in the company.

Can someone please give me a clue what I could use to achieve this.

Regards,
Alexei

Marko Rodriguez

unread,
Mar 13, 2012, 4:29:36 AM3/13/12
to ne...@googlegroups.com
Hey,

The following query will emit the top 10 company locations based on the location of its employees.

company.out('employee').out('location').groupCount.cap.sort{a,b -> b.value <=> a.value}[0..9]

company: the company vertex
out('employee'): all the company employees
out('location'): all the locations of the employees
groupCount: count the number of locations seen
cap: emit the count, not the location
sort: sort with largest count as highest
[0..9]: clip the sorted map to the first 10 entries

HTH,
Marko.

http://markorodriguez.com

Alexei Tenitski

unread,
Mar 14, 2012, 5:40:48 PM3/14/12
to ne...@googlegroups.com
Hi Marko,

Thanks for the reply. Could you please clarify couple of things for me.

First of all I've got the following problem with the query

==> No signature of method: java.util.ArrayList$ListItr.getAt() is
applicable for argument types: (groovy.lang.IntRange) values: [0..9]
==> Possible solutions: getAt(int), getAt(java.lang.String), next(),
mean(), set(java.lang.Object), putAt(java.lang.String, java.lang.Object)

I'm running 1.6 community edition.

Anyway, if i remove [0..9] i get a list of nodes like this:

{v[3]=1331, v[3287]=1, v[5225]=2, v[1089]=6, v[2017]=3, v[5841]=4,
v[5967]=1, v[261]=2, v[4527]=1, v[2722]=3, v[2031]=2, v[3139]=1,
v[440]=1, v[3314]=2, v[445]=4, v[4920]=3, v[643]=9, v[2701]=2,
v[2975]=1, v[2215]=1, v[1377]=1, v[2688]=3, v[60]=6, v[5918]=1,
v[2673]=3, v[612]=2, v[469]=1, v[1165]=28, v[2257]=7, v[5907]=1,
v[1048]=8, v[2659]=2, v[873]=17, v[2665]=2, v[5547]=1, v[4459]=3,
v[3214]=1, v[4940]=2, v[102]=14, v[4300]=14, v[1461]=3, v[2401]=3,
v[1193]=1, v[5122]=1, v[1198]=10, v[2291]=3, v[2775]=4, v[1927]=9,
v[733]=3, v[5927]=1, v[5382]=2}

which is not sorted for some reason which I was kind of expecting after
doing a sort step.

This list is array of how many companies are in each country.
My original question is more specific: get a country for each company OR
get all companies in specific country (both based on country of
employees). Is something like this easy enough to do using gremlin?

Thanks again for you input

Regards
Alexei

Marko Rodriguez

unread,
Mar 15, 2012, 11:16:53 AM3/15/12
to ne...@googlegroups.com
Hi,

Sorry, I had a bug in the traversal I provided you. Its:

company.out('employee').out('location').groupCount.cap.next().sort{a,b -> b.value<=> a.value}[0..9]

You need the .next() to 'pop' the map out of the pipeline and then you sort it and clip it to the top 10.

> My original question is more specific: get a country for each company OR get all companies in specific country (both based on country of employees). Is something like this easy enough to do using gremlin?


GET ALL COMPANIES IN A SPECIFIC COUNTRY:
country.in('location').in('company')

GET A COUNTRY FOR EACH COMPANY:
g.idx(T.v)[[type:'company']].out('employee').out('location')

For the second, I don't know what your indices look like, but you will want to hit an index to get all companies and then traverse off of each of those. If you want it in a "table" format (like a pattern match), use select().

g.idx(T.v)[[type:'company']].as('company').out('employee').out('location').as('location').select

If you are using Gremlin 1.4 and below, then you can use table:

g.idx(T.v)[[type:'company']].as('company').out('employee').out('location').as('location').table.cap.next()

Hope that works for ya,
Marko.

http://markorodriguez.com

Alexei Tenitski

unread,
Mar 25, 2012, 7:35:43 PM3/25/12
to ne...@googlegroups.com
Hi Marko,

I finally had a chance to try your suggestion plus more reading of docs
and playing with various queries but still unable to solve it.

This query gives me TOP locations of all employees linked to companies:

company.out('employee').out('location').groupCount.cap.next().sort{a,b
-> b.value<=> a.value}[0..9]

Following query:

> GET ALL COMPANIES IN A SPECIFIC COUNTRY:
> country.in('location').in('company')

would give me companies with atleast one person employed located in a
specified country.

This query:

>
> GET A COUNTRY FOR EACH COMPANY:
> g.idx(T.v)[[type:'company']].out('employee').out('location')

would give me a location for each employee in the company.

I need somehow to aggregate all locations of employes, pick the most
common one and use it to decide where company is located.

Regards,
Alexei


What I'm trying to find out is the company location based on where most
of its employees are, not where all companies are located.

I want to be able to filter companies by their location.

Marko Rodriguez

unread,
Mar 26, 2012, 12:30:27 PM3/26/12
to ne...@googlegroups.com
Hi Alexei,

> I need somehow to aggregate all locations of employes, pick the most common one and use it to decide where company is located.

This query will "for each employee, find their location, and count the number of locations. Then sort those and pick the top 1."

g.idx(T.v)[[type:'employee']].out('location').groupCount.cap.next().sort{a,b -> b.value <=> a.value}[0]

From there you can get just the key vertex:

g.idx(T.v)[[type:'employee']].out('location').groupCount.cap.next().sort{a,b -> b.value <=> a.value}[0].scatter.transform{it.key}

That will be the most frequent location. You can then do what you want with that location vertex. In more human readable for, I tend to do this:

m = g.idx(T.v)[[type:'employee']].out('location').groupCount.cap.next(); // rank locations
m = m.sort{a,b -> b.value <=> a.value}[0] // find the highest ranked location (as a single map entry)
m.scatter.transform{it.key} // turn the map entry into a stream and emit only the key (the count no longer matters)

HTH,
Marko.

http://markorodriguez.com

Alexei Tenitski

unread,
Apr 6, 2012, 4:34:12 PM4/6/12
to ne...@googlegroups.com
Hi Marko,

Thanks for helping me, while solving this problem and additional
research i've already have learned alot about how to do various things
in Gremlin.

Anyway, back to the query, when I do

m = g.idx(T.v)[[type:'employee']].out('location').groupCount.cap.next();

m = m.sort{a,b -> b.value<=> a.value}[0..10]

I get an array of entries, however when I do [0] as in your reply it
returns just an empty value (not undefined, simply an empty line) doing
scatter on which returns undefined.


Cheers,
Alexei

Reply all
Reply to author
Forward
0 new messages