Reputation: 16130
I've created a simple graph using the following data:
CREATE (england:Country {Name:"England",Id:1})
CREATE CONSTRAINT ON (c:Country) ASSERT c.ID IS UNIQUE
CREATE (john:King {Name:"John",Id:1})
CREATE (henry3:King {Name:"Henry III",Id:2})
CREATE (edward1:King {Name:"Edward I",Id:3})
CREATE CONSTRAINT ON (k:King) ASSERT k.ID IS UNIQUE
MATCH (country:Country),(king:King) WHERE country.Id = 1 AND king.Id = 1 CREATE (country)<-[r:KING_OF]-(king)
MATCH (country:Country),(king:King) WHERE country.Id = 1 AND king.Id = 2 CREATE (country)<-[r:KING_OF]-(king)
MATCH (country:Country),(king:King) WHERE country.Id = 1 AND king.Id = 3 CREATE (country)<-[r:KING_OF]-(king)
CREATE (cornwall:County {Name:"Cornwall",Id:1})
CREATE (devon:County {Name:"Devon",Id:2})
CREATE (somerset:County {Name:"Somerset",Id:3})
CREATE CONSTRAINT ON (c:County) ASSERT c.ID IS UNIQUE
MATCH (country:Country),(county:County) WHERE country.Id = 1 AND county.Id = 1 CREATE (country)<-[r:COUNTY_IN]-(county)
MATCH (country:Country),(county:County) WHERE country.Id = 1 AND county.Id = 2 CREATE (country)<-[r:COUNTY_IN]-(county)
MATCH (country:Country),(county:County) WHERE country.Id = 1 AND county.Id = 3 CREATE (country)<-[r:COUNTY_IN]-(county)
CREATE (bristol:City {Name:"Bristol",Id:1})
CREATE (london:City {Name:"London",Id:2})
CREATE (york:City {Name:"York",Id:3})
CREATE CONSTRAINT ON (c:City) ASSERT c.ID IS UNIQUE
MATCH (country:Country),(city:City) WHERE country.Id = 1 AND city.Id = 1 CREATE (country)<-[r:CITY_IN]-(city)
MATCH (country:Country),(city:City) WHERE country.Id = 1 AND city.Id = 2 CREATE (country)<-[r:CITY_IN]-(city)
MATCH (country:Country),(city:City) WHERE country.Id = 1 AND city.Id = 3 CREATE (country)<-[r:CITY_IN]-(city)
(Note that I use 'thiscomputer.mydomain.com' as an alias for 'localhost', which SO ridiculously bars me from using)...
If I go to http://thiscomputer.mydomain.com:7474/browser/ and execute the cypher
MATCH cities = (city:City)-[]->(c:Country {Id:1}), counties = (county:County)-[]->(c:Country {Id:1}), kings = (king:King)-[]->(c:Country {Id:1}) RETURN cities, counties, kings
...I get a nice graph centred around the country of England. No nodes are repeated.
If I fire up a REST client and execute the following:
URL: http://thiscomputer.mydomain.com:7474/db/data/transaction/commit
Verb: POST
Body:
{
"statements" : [{
"statement": "MATCH cities = (city:City)-[]->(c:Country {Id:1}), counties = (county:County)-[]->(c:Country {Id:1}), kings = (king:King)-[]->(c:Country {Id:1}) RETURN cities, counties, kings",
"resultDataContents" : [ "graph" ]
}]
}
(Note that the cypher query is identical)
I end up with a set of results that are too large to paste in here.
Basically, I appear to get the cartesian product of the results. Since there are 3 kings, 3 counties and 3 cities, there are 27 results.
This is a fairly simple graph. In the domain in which I work, the graph I want would contain an aggregate root (in this example, England), and many associated nodes of different types. If the REST API returned the cartesian product, I could end up with many thousands of results.
So my question is this: why does the REST API return the cartesian product of all the returned nodes? Is my cypher incorrect, or am I using the REST API incorrectly?
It would be much simpler if I could get results like this (pseudo-JSON):
{
Country:{
Name: "England",
Id: 1,
Cities:[
...etc
],
Counties:[
...etc
],
Kings:[
...etc
]
}
}
Or possibly even this:
{
data:{
nodes:[
{
Name:"England",
Id: 1,
uniqueIdInResults:1
},
...etc
],
relationships:[
uniqueIdInResults1: 1,
uniqueIdInResults2: 2,
type: "KING_OF"
]
}
}
In short, I think denormalising the data in the results like this can quickly result in a response which is too large. Is there any way to structure the cypher or the call to the REST API to give results with less repetition?
Upvotes: 2
Views: 195
Reputation: 7790
The query you are running in the browser is absolutely returning a Cartesian product as well - it just doesn't appear that way because the visual result will only show the nodes once.
Run the following in the browser. You'll see pretty quickly all the overlap you're getting.
MATCH cities = (city:City)-[]->(c:Country {Id:1}),
counties = (county:County)-[]->(c:Country {Id:1}),
kings = (king:King)-[]->(c:Country {Id:1})
RETURN EXTRACT(x IN NODES(cities) | x.Name),
EXTRACT(x IN NODES(counties) |x.Name),
EXTRACT(x IN NODES(kings) | x.Name)
As expected, I get a Cartesian product of 27 rows.
Upvotes: 3