[Neo4j] Execute cypher query from shell on Linux
Hi I installed database on Linux server via ssh. I have a list query and I want to test the performance. I can run the query from neo4j shell. But I want to write the result (time of running query )to text file because I have many query+want to compare it later. -- You received this message because you are subscribed to the Google Groups "Neo4j" group. To unsubscribe from this group and stop receiving emails from it, send an email to neo4j+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [Neo4j] Problem relates to relationship index,schema index
Thanks. I found that: - there is timeout for batch inserter( but i didn't find any information about how to set time out for this) - another problem is because my data is quite big and the storage is not enough for batch inserter use to insert. Anyway, I have questions: - As I found on Internet, we can't update data with batchinserter? Is this right? (My situation is when I create a node I didn't have enough information for this node but after that I look up from other thing so I have more information for this node) - in the example: docs.neo4j.org/chunked/stable/batchinsert-examples.html " Map properties = new HashMap<>();properties.put( "name", "Mattias" );long mattiasNode = inserter.createNode( properties, personLabel );properties.put( "name", "Chris" );long chrisNode = inserter.createNode( properties, personLabel ); " I test this example and it is ok but I don't understand why you don't need create new instance of Properties, and inserter put only the last value? Could I do this for big hashmap? Thanks in advance On Thursday, July 31, 2014 4:49:40 PM UTC+2, Michael Hunger wrote: > > Seems that your store is not ok. > > Can you try to run the consistency checker on your store? > > Download Neo4j Enterprise, and see > http://www.markhneedham.com/blog/2014/01/22/neo4j-backup-store-copy-and-consistency-check > > You can run > > java -cp 'lib/*:system/lib/*' org.neo4j.consistency.ConsistencyCheckTool > *data/graph.db* > > > > > On Thu, Jul 31, 2014 at 3:36 PM, Alex winter > wrote: > >> Thanks >> But I didn't find data/log or data/graph.db/message.log. >> I only see file message.log in the neo4j database directory. >> When I run create index on command, I found that a new folder is created >> in schema/index/lucene. >> And I found file "failure-message". And that is the content: >> org.neo4j.kernel.impl.nioneo.store.InvalidRecordException: >> PropertyRecord[136728222] not in use >> at >> org.neo4j.kernel.impl.nioneo.store.PropertyStore.getRecord(PropertyStore.java:423) >> at >> org.neo4j.kernel.impl.nioneo.store.PropertyStore.getLightRecord(PropertyStore.java:289) >> at >> org.neo4j.kernel.impl.nioneo.store.PropertyStore.getPropertyRecordChain(PropertyStore.java:728) >> at >> org.neo4j.kernel.impl.nioneo.xa.NeoStoreIndexStoreView$PropertyBlockIterator.(NeoStoreIndexStoreView.java:286) >> at >> org.neo4j.kernel.impl.nioneo.xa.NeoStoreIndexStoreView$3.iterator(NeoStoreIndexStoreView.java:221) >> at >> org.neo4j.kernel.impl.nioneo.xa.NeoStoreIndexStoreView$1.read(NeoStoreIndexStoreView.java:89) >> at >> org.neo4j.kernel.impl.nioneo.xa.NeoStoreIndexStoreView$1.read(NeoStoreIndexStoreView.java:80) >> at >> org.neo4j.kernel.impl.nioneo.xa.NeoStoreIndexStoreView$NodeStoreScan.run(NeoStoreIndexStoreView.java:330) >> at >> org.neo4j.kernel.impl.api.index.IndexPopulationJob.indexAllNodes(IndexPopulationJob.java:212) >> at >> org.neo4j.kernel.impl.api.index.IndexPopulationJob.run(IndexPopulationJob.java:107) >> at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) >> at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source) >> at java.util.concurrent.FutureTask.run(Unknown Source) >> at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) >> at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) >> at java.lang.Thread.run(Unknown Source) >> Nul Nul.. >> >> Do you know why I can't create index from this log file? >> Thanks >> >> >> On Wednesday, July 30, 2014 4:27:18 AM UTC+2, Michael Hunger wrote: >> >>> Legacy indexes can be listed in the neo4j-shell or in the >>> localhost:7474/webadmin console with index --list (see help index) >>> Schema indexes with :schema in the browser or "schema" in the shell >>> >>> Logs are in data/log/* or data/graph.db/messages.log >>> >>> >>> On Tue, Jul 29, 2014 at 8:26 AM, Alex winter >>> wrote: >>> Hi. I have some problem relates to index: - When I use the statement " create index on .. " I got error: " "Index entered a FAILED state. Please see database logs." So what is a database logs in neo4j database? So I could know why I can't create index. - When I imported data to neo4j, i setup the property: auto relationship index is true. So I know that it is created or not?The same question for other legacy index. Thanks -- You received this message because you are subscribed to the Google Groups "Neo4j" group. To unsubscribe from this group and stop receiving emails from it, send an email to neo4j+un...@googlegroups.com. For more options, visit https://groups.google.com/d/optout. >>> >>> -- >> You received this message because you are subscribed to the Google Groups >> "Neo4j" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to neo4j+u
Re: [Neo4j] Re: Returning items regarding the degree of separations between users.
Yep probably Sent from mobile device Am 01.08.2014 um 14:51 schrieb Michael Azerhad : > I had to add the keyword DISTINCT in my return clause like this: > ... > UNWIND cars as extractedCars > RETURN DISTINCT(extractedCars) > > It took now about 150ms that is pretty fast. > Is DISTINCT the best strategy in this case to avoid duplicates? > > Michael > > On Friday, August 1, 2014 2:26:19 PM UTC+2, Michael Azerhad wrote: >> >> I guess I found the reason of the slowness: >> >> If Person A is friend with B, and B is friend with C and C is friend with A >> (cyclic), then the query returns duplicated cars. >> I end up with 180 cars instead of 51 .. > > -- > You received this message because you are subscribed to the Google Groups > "Neo4j" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to neo4j+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "Neo4j" group. To unsubscribe from this group and stop receiving emails from it, send an email to neo4j+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[Neo4j] Re: Better docs please
Anders: Glad you like the suggestion. Dave: That source code from the bubble is really useful. Thanks! https://github.com/neo4j/neo4j/blob/2.1.2/community/embedded-examples/src/main/java/org/neo4j/examples/EmbeddedNeo4j.java Interesting that Java dependencies are so complex, that we actually need an internet connected software, Maven, to resolve them. And java is so complex, that we need an IDE such as Netbeans to manage it. Netbeans, being a complex software by itself. When I took the java course, many of the issues were not so much java, as they were how to use Netbeans. Often the best part of the course for me was being able to ask the instructor, "what's wrong here?". This is so different from when I first learned to program. When we did the exams, we wrote programs from memory, longhand, in paper booklets. As I look back on when I learned other technologies, such as PLSQL, and ProC (Oracle queries from within a C program), a simple tutorial/example that worked, integrating the technology stack, was one key for me to get going and out of first gear. I'm really big on clear and simple docs that communicate. In one of my very first blog posts, I touched on this: http://rodgersnotes.wordpress.com/2010/05/24/foryoureyesonly/ And I've made jokes about bad docs: http://rodgersnotes.wordpress.com/2012/01/15/joke-how-many-people-does-it-take-to-install-an-oracle-product/ :) I do think that the better the docs, the bigger will be the adoption of NEO4J. Thanks for all your help through the learning curves! On Saturday, July 26, 2014 9:11:57 PM UTC-5, Rodger wrote: > > Dear NEO4J documentation staff: > > > -- You received this message because you are subscribed to the Google Groups "Neo4j" group. To unsubscribe from this group and stop receiving emails from it, send an email to neo4j+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [Neo4j] Re: Returning items regarding the degree of separations between users.
I had to add the keyword DISTINCT in my return clause like this: ... UNWIND cars as extractedCars RETURN DISTINCT(extractedCars) It took now about 150ms that is pretty fast. Is DISTINCT the best strategy in this case to avoid duplicates? Michael On Friday, August 1, 2014 2:26:19 PM UTC+2, Michael Azerhad wrote: > > I guess I found the reason of the slowness: > > If Person A is friend with B, and B is friend with C and C is friend with > A (cyclic), then the query returns duplicated cars. > I end up with 180 cars instead of 51 .. > -- You received this message because you are subscribed to the Google Groups "Neo4j" group. To unsubscribe from this group and stop receiving emails from it, send an email to neo4j+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [Neo4j] Re: Returning items regarding the degree of separations between users.
I guess I found the reason of the slowness: If Person A is friend with B, and B is friend with C and C is friend with A (cyclic), then the query returns duplicated cars. I end up with 180 cars instead of 51 .. -- You received this message because you are subscribed to the Google Groups "Neo4j" group. To unsubscribe from this group and stop receiving emails from it, send an email to neo4j+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [Neo4j] Do I have to split relations of a node into domains?
The two approaches are essentially them same, although in 2.1 the "meta node" benefits are built into the store format. If you're querying relationships that are in a minority group (type+direction) there's a good benefit, but if you query relationships in a majority group, i.e. the most common type+direction, the benefit is not as good. On Sun, Jul 20, 2014 at 1:46 AM, Frandro wrote: > In my case, as the edges of a node grow the performance becomes worse. > My use case includes traversing all neighbor nodes and their neighbor > nodes. But the problem is that their relations of two types are growing. > > I've read the following board. > > https://groups.google.com/forum/#!searchin/neo4j/performance/neo4j/g63fTmPM4GE/vdSy5whsWgoJ > > There's a comment that recommends creating a meta node to have the most > edges of the node. > Another one is saying the problem will be mitigated in Neo4j 2.1. > > Any helpful comments will be appreciated. > > -- > You received this message because you are subscribed to the Google Groups > "Neo4j" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to neo4j+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- Mattias Persson Neo4j Hacker at Neo Technology -- You received this message because you are subscribed to the Google Groups "Neo4j" group. To unsubscribe from this group and stop receiving emails from it, send an email to neo4j+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [Neo4j] Re: Returning items regarding the degree of separations between users.
I tried one of the query you suggested: MATCH (loggedUser:Person{id: 123})-[:KNOWS]-(p1:Person) OPTIONAL MATCH (p1)-[:SELLS]->(c1:Car) WITH p1, collect(c1)[0..{limit}] as cars OPTIONAL MATCH (p1)-[:KNOWS]-(p2:Person) OPTIONAL MATCH (p2)-[:SELLS]->(c2:Car:Degree2) WITH p2, case when length(cars) < {limit} then cars + collect(c2)[0..({limit}-length(cars))] else cars end as cars OPTIONAL MATCH (p2)-[:KNOWS]-(p3:Person) OPTIONAL MATCH (p3)-[:SELLS]->(c3:Car:Degree3) WITH p3, case when length(cars) < {limit} then cars + collect(c3)[0..({limit}-length(cars))] else cars end as cars OPTIONAL MATCH (p3)-[:KNOWS]-(p4:Person) OPTIONAL MATCH (p4)-[:SELLS]->(c4:Car:Degree4) RETURN case when length(cars) < {limit} then cars + collect(c4)[0..({limit}-length(cars))] else cars end as cars It takes more than 2 seconds to execute :s When I opened each node like I did before (evoked above), the query took 150 ms. I have only 51 cars in the graph and 15 persons ... Would the collect function impact the performance? Thanks :) Michael On Friday, August 1, 2014 10:56:04 AM UTC+2, Michael Hunger wrote: > > You can sort on the client or use this at the end: > > unwind cars as car > return car > order by car.name asc > > Michael > > > On Fri, Aug 1, 2014 at 9:41 AM, Michael Azerhad > wrote: > >> Hello Michael, >> >> Thanks for this really great detailed answer ! Like it :) >> >> However I have a question : >> >> I do really prefer the last way (at the very bottom) using cypher and >> expressions to lazily limit results. >> I wonder whether it's also possible to order by car's name (not only >> limiting) the whole final collection. >> Indeed, as far as I know, order by could not be applied on Collect >> aggregate function directly. >> We would have to use With before collecting.. but the case here is that I >> end up with a collection incrementally built, so I'm forced to order a >> collection. >> Obviously, I can't incrementally build ordered collection since order >> should be applied on the whole directly. >> Is there a trick I may ignore to achieve global ordering ? >> >> Thanks a lot again :), >> >> Michael >> >> Le 1 août 2014 à 07:03, Michael Hunger > > a écrit : >> >> Not sure if I'd use cypher for those data volumes. >> >> I think in this case some imperative code filling a set of cars might be >> more sensible (i.e. a server extension) >> And using a label for the Car-Degree. (Alternatively you could also use a >> SELL1, SELL2 rel-type for the degrees, and then check if it has SELL(n..4) >> as sell relationships, that would probably be fastest. >> >> Set getCars(Node person, int level) { >> Label degree = DynamicLabel.label("Degree"+level); >> for (Relationship knows = person.getRelationships(KNOWS)) { >> Node friend = knows.getOtherNode(person); >> for (Relationship sells : >> friend.getRelationships(SELLS,OUTGOING)) { >> Node car = sells.getEndNode(); >> if (car.hasLabel(degree)) { >>cars.add(car); >>if (cars.size() > limit) return cars; >> } >> } >> } >> return cars; >> } >> >> Make sure to do real-sized load tests. >> >> Something I thought could work is incrementally building up the data. >> >> MATCH (loggedUser:Person{id: 123})-[:KNOWS]-(p1:Person) >> OPTIONAL MATCH (p1)-[:SELLS]->(c1:Car) >> WITH p1, collect(c1) as cars >> OPTIONAL MATCH (p1)-[:KNOWS]-(p2:Person) >> OPTIONAL MATCH (p2)-[:SELLS]->(c2:Car:Degree2) >> WITH p2, cars + collect(c2) as cars >> OPTIONAL MATCH (p2)-[:KNOWS]-(p3:Person) >> OPTIONAL MATCH (p3)-[:SELLS]->(c3:Car:Degree3) >> WITH p3, cars + collect(c3) as cars >> OPTIONAL MATCH (p3)-[:KNOWS]-(p4:Person) >> OPTIONAL MATCH (p4)-[:SELLS]->(c4:Car:Degree4) >> WITH cars + collect(c4) as cars >> >> If you want to limit the cars, it would probably be more complicated. >> >> Something like this: >> >> MATCH (loggedUser:Person{id: 123})-[:KNOWS]-(p1:Person) >> OPTIONAL MATCH (p1)-[:SELLS]->(c1:Car) >> WITH p1, collect(c1)[0..{limit}] as cars >> OPTIONAL MATCH (p1)-[:KNOWS]-(p2:Person) >> OPTIONAL MATCH (p2)-[:SELLS]->(c2:Car:Degree2) >> WITH p2, case when length(cars) < {limit} then cars + >> collect(c2)[0..({limit}-length(cars))] else cars end as cars >> OPTIONAL MATCH (p2)-[:KNOWS]-(p3:Person) >> OPTIONAL MATCH (p3)-[:SELLS]->(c3:Car:Degree3) >> WITH p3, case when length(cars) < {limit} then cars + >> collect(c3)[0..({limit}-length(cars))] else cars end as cars >> OPTIONAL MATCH (p3)-[:KNOWS]-(p4:Person) >> OPTIONAL MATCH (p4)-[:SELLS]->(c4:Car:Degree4) >> RETURN case when length(cars) < {limit} then cars + >> collect(c4)[0..({limit}-length(cars))] else cars end as cars >> >> it might even be more sensible to do the matches as expressions and only >> collect as few as you need. >> >> Like this: >> >> MATCH (loggedUser:Person{id: 123})-[:KNOWS]-(p1:Person) >> // iterate over all paths in the collection, extracting only the last node >> // b
Re: [Neo4j] Re: Returning items regarding the degree of separations between users.
wow! I wasn't aware of 'unwind' keyword, perfect ! And backported to 2.0.4 :) Thanks a lot Michael, really appreciate :) Michael Le 1 août 2014 à 10:56, Michael Hunger a écrit : You can sort on the client or use this at the end: unwind cars as car return car order by car.name asc Michael On Fri, Aug 1, 2014 at 9:41 AM, Michael Azerhad wrote: > Hello Michael, > > Thanks for this really great detailed answer ! Like it :) > > However I have a question : > > I do really prefer the last way (at the very bottom) using cypher and > expressions to lazily limit results. > I wonder whether it's also possible to order by car's name (not only > limiting) the whole final collection. > Indeed, as far as I know, order by could not be applied on Collect > aggregate function directly. > We would have to use With before collecting.. but the case here is that I > end up with a collection incrementally built, so I'm forced to order a > collection. > Obviously, I can't incrementally build ordered collection since order > should be applied on the whole directly. > Is there a trick I may ignore to achieve global ordering ? > > Thanks a lot again :), > > Michael > > Le 1 août 2014 à 07:03, Michael Hunger > a écrit : > > Not sure if I'd use cypher for those data volumes. > > I think in this case some imperative code filling a set of cars might be > more sensible (i.e. a server extension) > And using a label for the Car-Degree. (Alternatively you could also use a > SELL1, SELL2 rel-type for the degrees, and then check if it has SELL(n..4) > as sell relationships, that would probably be fastest. > > Set getCars(Node person, int level) { > Label degree = DynamicLabel.label("Degree"+level); > for (Relationship knows = person.getRelationships(KNOWS)) { > Node friend = knows.getOtherNode(person); > for (Relationship sells : > friend.getRelationships(SELLS,OUTGOING)) { > Node car = sells.getEndNode(); > if (car.hasLabel(degree)) { >cars.add(car); >if (cars.size() > limit) return cars; > } > } > } > return cars; > } > > Make sure to do real-sized load tests. > > Something I thought could work is incrementally building up the data. > > MATCH (loggedUser:Person{id: 123})-[:KNOWS]-(p1:Person) > OPTIONAL MATCH (p1)-[:SELLS]->(c1:Car) > WITH p1, collect(c1) as cars > OPTIONAL MATCH (p1)-[:KNOWS]-(p2:Person) > OPTIONAL MATCH (p2)-[:SELLS]->(c2:Car:Degree2) > WITH p2, cars + collect(c2) as cars > OPTIONAL MATCH (p2)-[:KNOWS]-(p3:Person) > OPTIONAL MATCH (p3)-[:SELLS]->(c3:Car:Degree3) > WITH p3, cars + collect(c3) as cars > OPTIONAL MATCH (p3)-[:KNOWS]-(p4:Person) > OPTIONAL MATCH (p4)-[:SELLS]->(c4:Car:Degree4) > WITH cars + collect(c4) as cars > > If you want to limit the cars, it would probably be more complicated. > > Something like this: > > MATCH (loggedUser:Person{id: 123})-[:KNOWS]-(p1:Person) > OPTIONAL MATCH (p1)-[:SELLS]->(c1:Car) > WITH p1, collect(c1)[0..{limit}] as cars > OPTIONAL MATCH (p1)-[:KNOWS]-(p2:Person) > OPTIONAL MATCH (p2)-[:SELLS]->(c2:Car:Degree2) > WITH p2, case when length(cars) < {limit} then cars + > collect(c2)[0..({limit}-length(cars))] else cars end as cars > OPTIONAL MATCH (p2)-[:KNOWS]-(p3:Person) > OPTIONAL MATCH (p3)-[:SELLS]->(c3:Car:Degree3) > WITH p3, case when length(cars) < {limit} then cars + > collect(c3)[0..({limit}-length(cars))] else cars end as cars > OPTIONAL MATCH (p3)-[:KNOWS]-(p4:Person) > OPTIONAL MATCH (p4)-[:SELLS]->(c4:Car:Degree4) > RETURN case when length(cars) < {limit} then cars + > collect(c4)[0..({limit}-length(cars))] else cars end as cars > > it might even be more sensible to do the matches as expressions and only > collect as few as you need. > > Like this: > > MATCH (loggedUser:Person{id: 123})-[:KNOWS]-(p1:Person) > // iterate over all paths in the collection, extracting only the last node > // but only taking the first 0..{limit} ones lazily from that collection > WITH p1, [path in (p1)-[:SELLS]->(:Car) | last(path)][0..{limit}] > ... > > > On Fri, Aug 1, 2014 at 4:28 AM, Michael Azerhad > wrote: > >> Fix of my query above, I missed to specify the logged user node: >> >> >> MATCH (d:Degree {id: 1})<-[:TARGET_TO]-(c:Car)<-[:SELLS]-(p:Person)-[ >> KNOWS]-(loggedUser:Person{id: 123}) >> RETURN c >> UNION >> MATCH (d:Degree {id: 2})<-[:TARGET_TO]-(c:Car)<-[:SELLS]-(p:Person)-[ >> KNOWS*..2]-(loggedUser:Person{id: 123}) >> RETURN c >> UNION >> MATCH (d:Degree {id: 3})<-[:TARGET_TO]-(c:Car)<-[:SELLS]-(p:Person)-[ >> KNOWS*..3]-(loggedUser:Person{id: 123}) >> RETURN c >> UNION >> MATCH (d:Degree {id: 4})<-[:TARGET_TO]-(c:Car)<-[:SELLS]-(p:Person)-[ >> KNOWS*..4]-(loggedUser:Person{id: 123}) >> RETURN c >> >> It's important :) >> >> On Friday, August 1, 2014 4:24:41 AM UTC+2, Michael Azerhad wrote: >>> >>> Hi, >>> >>> I really think about making the following scenario optimal using Cypher >>> and Neo4j 2.X.X: >>> >>> Let's suppose this classic person
Re: [Neo4j] Re: Returning items regarding the degree of separations between users.
You can sort on the client or use this at the end: unwind cars as car return car order by car.name asc Michael On Fri, Aug 1, 2014 at 9:41 AM, Michael Azerhad wrote: > Hello Michael, > > Thanks for this really great detailed answer ! Like it :) > > However I have a question : > > I do really prefer the last way (at the very bottom) using cypher and > expressions to lazily limit results. > I wonder whether it's also possible to order by car's name (not only > limiting) the whole final collection. > Indeed, as far as I know, order by could not be applied on Collect > aggregate function directly. > We would have to use With before collecting.. but the case here is that I > end up with a collection incrementally built, so I'm forced to order a > collection. > Obviously, I can't incrementally build ordered collection since order > should be applied on the whole directly. > Is there a trick I may ignore to achieve global ordering ? > > Thanks a lot again :), > > Michael > > Le 1 août 2014 à 07:03, Michael Hunger > a écrit : > > Not sure if I'd use cypher for those data volumes. > > I think in this case some imperative code filling a set of cars might be > more sensible (i.e. a server extension) > And using a label for the Car-Degree. (Alternatively you could also use a > SELL1, SELL2 rel-type for the degrees, and then check if it has SELL(n..4) > as sell relationships, that would probably be fastest. > > Set getCars(Node person, int level) { > Label degree = DynamicLabel.label("Degree"+level); > for (Relationship knows = person.getRelationships(KNOWS)) { > Node friend = knows.getOtherNode(person); > for (Relationship sells : > friend.getRelationships(SELLS,OUTGOING)) { > Node car = sells.getEndNode(); > if (car.hasLabel(degree)) { >cars.add(car); >if (cars.size() > limit) return cars; > } > } > } > return cars; > } > > Make sure to do real-sized load tests. > > Something I thought could work is incrementally building up the data. > > MATCH (loggedUser:Person{id: 123})-[:KNOWS]-(p1:Person) > OPTIONAL MATCH (p1)-[:SELLS]->(c1:Car) > WITH p1, collect(c1) as cars > OPTIONAL MATCH (p1)-[:KNOWS]-(p2:Person) > OPTIONAL MATCH (p2)-[:SELLS]->(c2:Car:Degree2) > WITH p2, cars + collect(c2) as cars > OPTIONAL MATCH (p2)-[:KNOWS]-(p3:Person) > OPTIONAL MATCH (p3)-[:SELLS]->(c3:Car:Degree3) > WITH p3, cars + collect(c3) as cars > OPTIONAL MATCH (p3)-[:KNOWS]-(p4:Person) > OPTIONAL MATCH (p4)-[:SELLS]->(c4:Car:Degree4) > WITH cars + collect(c4) as cars > > If you want to limit the cars, it would probably be more complicated. > > Something like this: > > MATCH (loggedUser:Person{id: 123})-[:KNOWS]-(p1:Person) > OPTIONAL MATCH (p1)-[:SELLS]->(c1:Car) > WITH p1, collect(c1)[0..{limit}] as cars > OPTIONAL MATCH (p1)-[:KNOWS]-(p2:Person) > OPTIONAL MATCH (p2)-[:SELLS]->(c2:Car:Degree2) > WITH p2, case when length(cars) < {limit} then cars + > collect(c2)[0..({limit}-length(cars))] else cars end as cars > OPTIONAL MATCH (p2)-[:KNOWS]-(p3:Person) > OPTIONAL MATCH (p3)-[:SELLS]->(c3:Car:Degree3) > WITH p3, case when length(cars) < {limit} then cars + > collect(c3)[0..({limit}-length(cars))] else cars end as cars > OPTIONAL MATCH (p3)-[:KNOWS]-(p4:Person) > OPTIONAL MATCH (p4)-[:SELLS]->(c4:Car:Degree4) > RETURN case when length(cars) < {limit} then cars + > collect(c4)[0..({limit}-length(cars))] else cars end as cars > > it might even be more sensible to do the matches as expressions and only > collect as few as you need. > > Like this: > > MATCH (loggedUser:Person{id: 123})-[:KNOWS]-(p1:Person) > // iterate over all paths in the collection, extracting only the last node > // but only taking the first 0..{limit} ones lazily from that collection > WITH p1, [path in (p1)-[:SELLS]->(:Car) | last(path)][0..{limit}] > ... > > > On Fri, Aug 1, 2014 at 4:28 AM, Michael Azerhad > wrote: > >> Fix of my query above, I missed to specify the logged user node: >> >> >> MATCH (d:Degree {id: 1})<-[:TARGET_TO]-(c:Car)<-[:SELLS]-(p:Person)-[ >> KNOWS]-(loggedUser:Person{id: 123}) >> RETURN c >> UNION >> MATCH (d:Degree {id: 2})<-[:TARGET_TO]-(c:Car)<-[:SELLS]-(p:Person)-[ >> KNOWS*..2]-(loggedUser:Person{id: 123}) >> RETURN c >> UNION >> MATCH (d:Degree {id: 3})<-[:TARGET_TO]-(c:Car)<-[:SELLS]-(p:Person)-[ >> KNOWS*..3]-(loggedUser:Person{id: 123}) >> RETURN c >> UNION >> MATCH (d:Degree {id: 4})<-[:TARGET_TO]-(c:Car)<-[:SELLS]-(p:Person)-[ >> KNOWS*..4]-(loggedUser:Person{id: 123}) >> RETURN c >> >> It's important :) >> >> On Friday, August 1, 2014 4:24:41 AM UTC+2, Michael Azerhad wrote: >>> >>> Hi, >>> >>> I really think about making the following scenario optimal using Cypher >>> and Neo4j 2.X.X: >>> >>> Let's suppose this classic person knowledge pattern: >>> >>> (a:Person)-[:KNOWS]-(b:Person) >>> >>> >>> Each person can sell his car by specifying its visibility according to >>> the degree of separation of its choi
Re: [Neo4j] Re: Returning items regarding the degree of separations between users.
Hello Michael, Thanks for this really great detailed answer ! Like it :) However I have a question : I do really prefer the last way (at the very bottom) using cypher and expressions to lazily limit results. I wonder whether it's also possible to order by car's name (not only limiting) the whole final collection. Indeed, as far as I know, order by could not be applied on Collect aggregate function directly. We would have to use With before collecting.. but the case here is that I end up with a collection incrementally built, so I'm forced to order a collection. Obviously, I can't incrementally build ordered collection since order should be applied on the whole directly. Is there a trick I may ignore to achieve global ordering ? Thanks a lot again :), Michael Le 1 août 2014 à 07:03, Michael Hunger a écrit : Not sure if I'd use cypher for those data volumes. I think in this case some imperative code filling a set of cars might be more sensible (i.e. a server extension) And using a label for the Car-Degree. (Alternatively you could also use a SELL1, SELL2 rel-type for the degrees, and then check if it has SELL(n..4) as sell relationships, that would probably be fastest. Set getCars(Node person, int level) { Label degree = DynamicLabel.label("Degree"+level); for (Relationship knows = person.getRelationships(KNOWS)) { Node friend = knows.getOtherNode(person); for (Relationship sells : friend.getRelationships(SELLS,OUTGOING)) { Node car = sells.getEndNode(); if (car.hasLabel(degree)) { cars.add(car); if (cars.size() > limit) return cars; } } } return cars; } Make sure to do real-sized load tests. Something I thought could work is incrementally building up the data. MATCH (loggedUser:Person{id: 123})-[:KNOWS]-(p1:Person) OPTIONAL MATCH (p1)-[:SELLS]->(c1:Car) WITH p1, collect(c1) as cars OPTIONAL MATCH (p1)-[:KNOWS]-(p2:Person) OPTIONAL MATCH (p2)-[:SELLS]->(c2:Car:Degree2) WITH p2, cars + collect(c2) as cars OPTIONAL MATCH (p2)-[:KNOWS]-(p3:Person) OPTIONAL MATCH (p3)-[:SELLS]->(c3:Car:Degree3) WITH p3, cars + collect(c3) as cars OPTIONAL MATCH (p3)-[:KNOWS]-(p4:Person) OPTIONAL MATCH (p4)-[:SELLS]->(c4:Car:Degree4) WITH cars + collect(c4) as cars If you want to limit the cars, it would probably be more complicated. Something like this: MATCH (loggedUser:Person{id: 123})-[:KNOWS]-(p1:Person) OPTIONAL MATCH (p1)-[:SELLS]->(c1:Car) WITH p1, collect(c1)[0..{limit}] as cars OPTIONAL MATCH (p1)-[:KNOWS]-(p2:Person) OPTIONAL MATCH (p2)-[:SELLS]->(c2:Car:Degree2) WITH p2, case when length(cars) < {limit} then cars + collect(c2)[0..({limit}-length(cars))] else cars end as cars OPTIONAL MATCH (p2)-[:KNOWS]-(p3:Person) OPTIONAL MATCH (p3)-[:SELLS]->(c3:Car:Degree3) WITH p3, case when length(cars) < {limit} then cars + collect(c3)[0..({limit}-length(cars))] else cars end as cars OPTIONAL MATCH (p3)-[:KNOWS]-(p4:Person) OPTIONAL MATCH (p4)-[:SELLS]->(c4:Car:Degree4) RETURN case when length(cars) < {limit} then cars + collect(c4)[0..({limit}-length(cars))] else cars end as cars it might even be more sensible to do the matches as expressions and only collect as few as you need. Like this: MATCH (loggedUser:Person{id: 123})-[:KNOWS]-(p1:Person) // iterate over all paths in the collection, extracting only the last node // but only taking the first 0..{limit} ones lazily from that collection WITH p1, [path in (p1)-[:SELLS]->(:Car) | last(path)][0..{limit}] ... On Fri, Aug 1, 2014 at 4:28 AM, Michael Azerhad wrote: > Fix of my query above, I missed to specify the logged user node: > > > MATCH (d:Degree {id: 1})<-[:TARGET_TO]-(c:Car)<-[:SELLS]-(p:Person)-[KNOWS > ]-(loggedUser:Person{id: 123}) > RETURN c > UNION > MATCH (d:Degree {id: 2})<-[:TARGET_TO]-(c:Car)<-[:SELLS]-(p:Person)-[KNOWS > *..2]-(loggedUser:Person{id: 123}) > RETURN c > UNION > MATCH (d:Degree {id: 3})<-[:TARGET_TO]-(c:Car)<-[:SELLS]-(p:Person)-[KNOWS > *..3]-(loggedUser:Person{id: 123}) > RETURN c > UNION > MATCH (d:Degree {id: 4})<-[:TARGET_TO]-(c:Car)<-[:SELLS]-(p:Person)-[KNOWS > *..4]-(loggedUser:Person{id: 123}) > RETURN c > > It's important :) > > On Friday, August 1, 2014 4:24:41 AM UTC+2, Michael Azerhad wrote: >> >> Hi, >> >> I really think about making the following scenario optimal using Cypher >> and Neo4j 2.X.X: >> >> Let's suppose this classic person knowledge pattern: >> >> (a:Person)-[:KNOWS]-(b:Person) >> >> >> Each person can sell his car by specifying its visibility according to >> the degree of separation of its choice. >> Example: >> >> Person A wants to sell a car. >> He expects people distant of 2 degrees maximum to "see" his sale >> announcement. (friends of friends maximum, including his direct friends) >> >> Therefore, when Person B logs on and click on "list all the sales", only >> sales that concerns him (according to the specified degree of separation by >> the seller previously). >> >> So