Merging list of maps in gremlin - gremlin

I have this relationship:
person --likes--> subject
This is my query:
g.V().
hasLabel('person').
has('name', 'Joe').
outE('likes').
range(0, 2).
union(identity(), inV().hasLabel('subject')).
valueMap('rating', 'name').
At this point, I get result that looks like this:
[
{
"rating": 3.236155563
},
{
"rating": 3.162886797
},
{
"name": "math"
},
{
"name": "history"
}
]
I'd like to get something like this:
[
{
"rating": 3.236155563,
"name": "math"
},
{
"rating": 3.162886797,
"name": "history"
},
]
I've tried grouping the results - which gives me the structure I want - but because of the identical keys, I only get 1 set of results back.

It always helps when you post the code to create the graph so we can give you a tested answer. Like so
g.addV('person').property('name', 'P1').as('p1').
addV('subject').property('name', 'Math').as('math').
addV('subject').property('name', 'History').as('history').
addV('subject').property('name', 'Geography').as('geography').
addE('likes').from('p1').to('math').property('rating', 1.2).
addE('likes').from('p1').to('history').property('rating', 2.3).
addE('likes').from('p1').to('geography').property('rating', 3.4)
I believe you are trying to write a traversal that starts from a certain person, go out along the first two "likes" edges and get the names of the subjects that he likes and the rating on the corresponding "likes" edge.
g.V().has('person', 'name', 'P1').
outE('likes').
range(0, 2).
project('SubjectName', 'Rating').
by(inV().values('name')).
by(values('rating'))

Related

Get vertices with a simpler format

Is there a way to get a list of vertices with a simpler format?
Currently, the following query:
g.V().has(label, 'Quantity').has('text', '627 km');
returns an object like this:
{
"id": 42545168,
"label": "Quantity",
"type": "vertex",
"properties": {
"sentence": [
{
"id": "pkbgi-pbw28-745",
"value": "null"
}
],
"updated_text": [
{
"id": "pk9vm-pbw28-5j9",
"value": "627 km"
}
],[...]
And when I get a list of edges it is formatted in a simpler format:
g.E().has(label, 'locatedAt').has('out_entity_id','41573-41579');
returns:
{
"id": "ozfnt-ip8o-2mtx-g8vs",
"label": "locatedAt",
"type": "edge",
"inVLabel": "Location",
"outVLabel": "Location",
"inV": 758008,
"outV": 872520,
"properties": {
"sentence": "Bolloré is a corporation (société anonyme) with a Board of Directors whose registered offi ce is located at Odet, 29500 Ergué-Gabéric in France.",
"in_entity_id": "41544-41548",
"score": "0.795793",
"out_entity_id": "41573-41579"
}
}
How so?
Is there a way to get vertices formatted this way?
My advice is to rather than have your query return the whole vertex, return the specific properties that you are interested in. For example the vertex ID or some selected properties that you are interested in or a valueMap. Otherwise what you will get back is essentially everything. This is really the same as in SQL trying to not do a "select *" but selecting only what you really care about.
Edited to add an example that returns the IDs of matching vertices.
g.V().has(label, 'Quantity').has('text', '627 km').id().fold()
Will yield a result that looks like this
{"requestId":"73f40519-87c8-4037-a9fc-41be82b3b227","status":{"message":"","code":200,"attributes":{}},"result":{"data":[[20608,28920,32912,106744,123080,135200,139296,143464,143488,143560,151584,155688,155752,159784,188520,254016,282688,286968,311360,323832,348408,4344,835648,8336,1343616,12352]],"meta":{}}}

Serialized Entities displaying only ID

I'm using JMSSerializer and FOSRestBundle. I have a fairly typical object graph, including some recursion.
What I would like to accomplish is that included objects beyond a certain depth or in general are listed only with their ID, but when serialized directly, with all data.
So, for example:
Users => Groups => Users
when requesting /user/1 the result should be something like
{ "id": 1, "name": "John Doe", "groups": [ { "id": 10 }, { "id": 11 } ] }
While when I request /group/10 it would be:
{ "id": 10, "name": "Groupies", "users": [ { "id": 1 }, { "id": 2 }, { "id": 4 } ] }
With #MaxDeph I can hide the included arrays completely, so I get
{ "id": 1, "name": "John Doe", "groups": [] }
But I would like to include just the IDs so that the REST client can fetch them if it needs them, or consult his cache, or do whatever.
I know I can manually cobble this together using groups, but for consistency reasons I was wondering if I can somehow enable this behaviour in my entire application, maybe even with a reference to maxdepth so I can control where to include IDs and where to include full objects?
For the sake of those finding this:
I found no other solution, but doing this with groups works just fine and gives me the result I was looking for.

Freebase MQL must sort on a single value

I'm trying to learn to use Freebase, however when I try and do a sort by "/people/person/date_of_birth" for a search for actors for a show, it returns:
"code": 400,
"message": "Must sort on a single value, not at /tv/tv_program/regular_cast./tv/regular_tv_appearance/actor./people/person/date_of_birth"
Here is the full MQL query:
[{
"id": "/m/0524b41",
"name": [],
"sort":"/tv/tv_program/regular_cast./tv/regular_tv_appearance/actor./people/person/date_of_birth",
"/tv/tv_program/regular_cast": [{
"/tv/regular_tv_appearance/actor": [{
"name": [],
"/people/person/date_of_birth": []
}]
}]
}]
But you're not asking to sort on /people/person/date_of_birth, you're asking to sort on that long nested expression which goes through multiple intermediary nodes, some of which can appear multiple times (as indicated by the [] array notation). It's this multiplicity that MQL is complaining about.
To fix it, take your query, paste it into the query editor, click on the innermost /person/date_of_birth and then click "Invert Query." That will turn the query inside out and give you something that looks like this:
[{
"name": [],
"/people/person/date_of_birth": [],
"type": "/tv/tv_actor",
"!/tv/regular_tv_appearance/actor": [{
"!/tv/tv_program/regular_cast": [{
"id": "/m/0524b41",
"name": [],
"sort": "/tv/tv_program/regular_cast./tv/regular_tv_appearance/actor./people/person/date_of_birth"
}]
}]
}]
which isn't exactly what you want, but indicates the general shape of your target query.
Getting rid of the array brackets for single valued properties and moving the sort clause to the outside gives us:
[{
"name": null,
"/people/person/date_of_birth": null,
"sort": "/people/person/date_of_birth",
"type": "/tv/tv_actor",
"!/tv/regular_tv_appearance/actor": [{
"!/tv/tv_program/regular_cast": [{
"id": "/m/0524b41",
"name": null
}]
}]
}]
which is functional and returns our 81 regular Game of Thrones actors sorted by birth date, but could still be cleaned up a bit more. The !inverse property notation isn't necessary since we have forward equivalents and we don't really need to get the Game of Thrones info over and over again since it's constant and we really just want to use it as a filter.
Incorporating these final tweaks gives us a final query like this which returns nice compact results:
[{
"name": null,
"/people/person/date_of_birth": null,
"sort": "/people/person/date_of_birth",
"type": "/tv/tv_actor",
"starring_roles": [{
"series": {
"id": "/m/0524b41"
},
"limit": 0
}]
}]
The "limit": 0 clause is a little trick to cause MQL to use that subquery for filtering, but not bother returning any of the (constant) information in the results. The /tv/tv_actor/starring_roles and /tv/regular_tv_appearance/series can be abbreviated to the simple property names because their types are implied by their context.
Since there are only 81 results, MQL's default limit of 100 is plenty and we don't need to worry about increasing it or using cursors.
Oldest Game of Thrones actor: Peter Vaughn, born 1923.
Youngest: Lino Facioli b. 2000
Note that 7 actors don't have birth dates in Freebase, so we don't know where they rank age-wise. Here's a bonus query which returns their names and ids as well as their character's name. If we were running a production system, we might use something like this to feed a human curation queue to fill in the gaps.
[{
"name": null,
"/people/person/date_of_birth": {
"value": null,
"optional": "forbidden"
},
"type": "/tv/tv_actor",
"starring_roles": [{
"series": {
"id": "/m/0524b41"
},
"character":null
}]
}]
The seven character/actor pairs are (were): Roose Bolton - Michael McElhatton,
Gregor Clegane - Conan Stevens,
Hizdahr zo Loraq - Joel Fry,
Rickon Stark - Art Parkinson,
Janos Slynt - Dominic Carter,
Hodor - Kristian Nairn,
Tommen Baratheon - Callum Wharry. I say "were" because I couldn't resist fixing Hodor's birth date. The strange thing is that it was in Wikipedia, so should have been picked up automatically by Freebase. I think there's a bug lurking there somewhere.

Freebase beginner: getting an athlete's sport

I'm trying to use Freebase to find out what team a professional athlete belongs to.
So I'm trying to do something like this
[{
"id": null,
"name": "Kobe Bryant",
"type": "/sports/pro_athlete",
"sports_played": []
}]​
query editor
and then extract the property "sport_played" to find out what sport the player belongs to. My plan is to then do a more specific query for "basketball_player" or so until I finde the team name. (Is a simpler way to do this?)
However, I already fail at the first step, because in the results, while the properties sport_played and sport_played_professionally contain a single entry, that entry is null:
{
"code": "/api/status/ok",
"result": [{
"id": "/en/kobe_bryant",
"name": "Kobe Bryant",
"sports_played": [
null
],
"type": "/sports/pro_athlete"
}],
"status": "200 OK",
"transaction_id": "cache;cache03.p01.sjc1:8101;2012-06-13T13:30:20Z;0053"
}
I'm confused: I know from browsing the database that there should be a sport value for this player. And the result clearly shows that there is a single value in the "sports_played" list in the result.
But why is it null? Shouldn't is rather be a reference to a Basketball object?
Your query is asking for a list of sports_played but since you only used square braces it will only return a list of the names of all the matching topics.
If you add curly braces to the query you'll see that sports_played actually returns one topic with name = null (which is what your previous query was showing)
[{
"id": null,
"name": "Kobe Bryant",
"type": "/sports/pro_athlete",
"sports_played": [{}]
}]
This is because the expected value of sports_played is a CVT called Sports played which links athletes to sports for specific periods of time. This is so that we can keep track of athletes that have played multiple sports and know which one is the most current.
If you want to see the values inside the CVT object, you'll need to drill down further like this:
[{
"id": null,
"name": "Kobe Bryant",
"type": "/sports/pro_athlete",
"sports_played": [{
"type": "/sports/pro_sports_played",
"sport": {
"id": null,
"name": null
},
"career_start": null,
"career_end": null
}]
}]
Try it in the Query Editor
The sports_played property isn't really what you want here since it's not necessarily correlated with the properties which contain the team information.
Instead you want to use something along the lines of:
{
"id": null,
"name": "Kobe Bryant",
"/basketball/basketball_player/team" : [{"team":null}],
}]
}
if you wanted to get all the teams for all the Kobe Bryants you could use something like:
[{
"id": null,
"name": "Kobe Bryant",
"/soccer/football_player/current_team" : [{"team":null,"optional":true}],
"/basketball/basketball_player/team" : [{"team":null,"optional":true}],
"/american_football/football_player/current_team" :[{"team":null,"optional":true}]
}]
}]​
Unfortunately you'll need to go through the schema by hand and pull out the properties of interest by hand since they're not reliably regular enough to query automatically, but there really aren't that many sports to consider, so it shouldn't take very long to assemble your list.

freebase city regions above neighborhood

Using freebase how can I find say, all the burrows/subcities of NY? (queens, brooklyn, etc.)
And will it be similar to other cities? Say if I want to know the subdivisions of Prague (Zizkov, Old Town, etc.) or Berlin, etc?
I've tried various combos but haven't hit one yet.
{
"id": "/en/new_york",
"guid": null,
"name": null,
"/location/location/containedby": [
],
"/location/location/contains" : [],
"/location/place_with_neighborhoods/neighborhoods": [
]
}​
The property /location/location/contains is the one that you want, but you're going to have two problems:
It's only sparsely populated
It has multiple levels of containment as a hack to work around API limitations
There's not much you can do about #1 unless you want to work on improving the data yourself. For #2, you can subtract the set of locations which are contained in another location in the "contains" set.
Someone might be able to give a better answer but this will get major districts like in NY but probably not for smaller cities which are more like regions.
{
"id": "/en/new_york",
"guid": null,
"name": null,
"/location/location/containedby": [
],
"/location/location/contains" : [
"name": null,
"type": "/location/citytown"
]
}​
or to select multiple items that might be it
{
"id": "/en/new_york",
"guid": null,
"name": null,
"/location/location/containedby": [
],
"/location/location/contains" : [
"name": null,
"type|=" : [
"/location/citytown",
"/location/neighborhood",
"/location/administrative_division",
"/location/de_borough",
"/location/place_with_neighborhoods/neighborhoods"
]
]
}​

Resources