optimizing cypher queries in neo4j
DESCRIPTION
Mark and Wes will talk about Cypher optimization techniques based on real queries as well as the theoretical underlying processes. They'll start from the basics of "what not to do", and how to take advantage of indexes, and continue to the subtle ways of ordering MATCH/WHERE/WITH clauses for optimal performance as of the 2.0.0 release.TRANSCRIPT
![Page 1: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/1.jpg)
Optimizing Cypher Queries in Neo4j
Wes Freeman (@wefreema)
Mark Needham (@markhneedham)
![Page 2: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/2.jpg)
Today's schedule
• Brief overview of cypher syntax
• Graph global vs Graph local queries
• Labels and indexes
• Optimization patterns
• Profiling cypher queries
• Applying optimization patterns
![Page 3: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/3.jpg)
Cypher Syntax
• Statement partso Optional: Querying part (MATCH|WHERE)o Optional: Updating part (CREATE|MERGE)o Optional: Returning part (WITH|RETURN)
• Parts can be chained together
![Page 4: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/4.jpg)
Cypher Syntax - Refresher
MATCH (n:Label)-[r:LINKED]->(m)WHERE n.prop = "..."RETURN n, r, m
![Page 5: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/5.jpg)
Starting points
• Graph scan (global; potentially slow)
• Label scan (usually reserved for aggregation queries; not ideal)
• Label property index lookup (local; good!)
![Page 6: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/6.jpg)
Introducing the football dataset
![Page 7: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/7.jpg)
The 1.9 global scanO(n)
n = # of nodes
START pl = node(*) MATCH (pl)-[:played]->(stats) WHERE pl.name = "Wayne Rooney" RETURN stats
150ms w/ 30k nodes, 120k rels
![Page 8: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/8.jpg)
The 2.0 global scan
MATCH (pl)-[:played]->(stats) WHERE pl.name = "Wayne Rooney" RETURN stats
130ms w/ 30k nodes, 120k rels
O(n)n = # of nodes
![Page 9: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/9.jpg)
Why is it a global scan?
• Cypher is a pattern matching language
• It doesn't discriminate unless you tell it too It must try to start at all nodes to find this
pattern, as specified
![Page 10: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/10.jpg)
Introduce a label
Label your starting points
CREATE (player:Player {name: "Wayne Rooney"} )
![Page 11: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/11.jpg)
O(k)k = # of nodes with that labelLabel scan
MATCH (pl:Player)-[:played]->(stats) WHERE pl.name = "Wayne Rooney" RETURN stats
80ms w/ 30k nodes, 120k rels (~900 :Player nodes)
![Page 12: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/12.jpg)
Indexes don't come for free
CREATE INDEX ON :Player(name)
OR
CREATE CONSTRAINT ON pl:PlayerASSERT pl.name IS UNIQUE
![Page 13: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/13.jpg)
O(log k)k = # of nodes with that labelIndex lookup
MATCH (pl:Player)-[:played]->(stats) WHERE pl.name = "Wayne Rooney" RETURN stats
6ms w/ 30k nodes, 120k rels (~900 :Player nodes)
![Page 14: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/14.jpg)
Optimization Patterns
• Avoid cartesian products
• Avoid patterns in the WHERE clause
• Start MATCH patterns at the lowest cardinality and expand outward
• Separate MATCH patterns with minimal expansion at each stage
![Page 15: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/15.jpg)
Introducing the movie data set
![Page 16: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/16.jpg)
Anti-pattern: Cartesian Products
MATCH (m:Movie), (p:Person)
![Page 17: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/17.jpg)
Subtle Cartesian Products
MATCH (p:Person)-[:KNOWS]->(c)WHERE p.name="Tom Hanks"WITH cMATCH (k:Keyword)RETURN c, k
![Page 18: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/18.jpg)
Counting Cartesian Products
MATCH (pl:Player),(t:Team),(g:Game)RETURN COUNT(DISTINCT pl), COUNT(DISTINCT t), COUNT(DISTINCT g)
80000 ms w/ ~900 players, ~40 teams, ~1200 games
![Page 19: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/19.jpg)
MATCH (pl:Player)WITH COUNT(pl) as playersMATCH (t:Team)WITH COUNT(t) as teams, playersMATCH (g:Game)RETURN COUNT(g) as games, teams, players8ms w/ ~900 players, ~40 teams, ~1200 games
Better Counting
![Page 20: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/20.jpg)
Directions on patterns
MATCH (p:Person)-[:ACTED_IN]-(m)WHERE p.name = "Tom Hanks"RETURN m
![Page 21: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/21.jpg)
Parameterize your queries
MATCH (p:Person)-[:ACTED_IN]-(m)WHERE p.name = {name}RETURN m
![Page 22: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/22.jpg)
Fast predicates first
Bad:MATCH (t:Team)-[:played_in]->(g)WHERE NOT (t)-[:home_team]->(g) AND g.away_goals > g.home_goals RETURN t, COUNT(g)
![Page 23: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/23.jpg)
Better:MATCH (t:Team)-[:played_in]->(g)WHERE g.away_goals > g.home_goals AND NOT (t)-[:home_team]->()RETURN t, COUNT(g)
Fast predicates first
![Page 24: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/24.jpg)
Patterns in WHERE clauses
• Keep them in the MATCH
• The only pattern that needs to be in a WHERE clause is a NOT
![Page 25: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/25.jpg)
MERGE and CONSTRAINTs
• MERGE is MATCH or CREATE
• MERGE can take advantage of unique constraints and indexes
![Page 26: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/26.jpg)
MERGE (without index)MERGE (g:Game
{date:1290257100,
time: 1245,
home_goals: 2,
away_goals: 3,
match_id: 292846,
attendance: 60102})
RETURN g
188 ms w/ ~400 games
![Page 27: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/27.jpg)
Adding an index
CREATE INDEX ON :Game(match_id)
![Page 28: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/28.jpg)
MERGE (with index)MERGE (g:Game
{date:1290257100,
time: 1245,
home_goals: 2,
away_goals: 3,
match_id: 292846,
attendance: 60102})
RETURN g
6 ms w/ ~400 games
![Page 29: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/29.jpg)
Alternative MERGE approachMERGE (g:Game { match_id: 292846 })ON CREATESET g.date = 1290257100
SET g.time = 1245SET g.home_goals = 2SET g.away_goals = 3SET g.attendance = 60102RETURN g
![Page 30: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/30.jpg)
Profiling queries
• Use the PROFILE keyword in front of the queryo from webadmin or shell - won't work in
browser
• Look for db_hits and rows
• Ignore everything else (for now!)
![Page 31: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/31.jpg)
Reviewing the football dataset
![Page 32: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/32.jpg)
Football OptimizationMATCH (game)<-[:contains_match]-(season:Season),
(team)<-[:away_team]-(game),
(stats)-[:in]->(game),
(team)<-[:for]-(stats)<-[:played]-(player)
WHERE season.name = "2012-2013"
RETURN player.name,
COLLECT(DISTINCT team.name),
SUM(stats.goals) as goals
ORDER BY goals DESC
LIMIT 103137 ms w/ ~900 players, ~20 teams, ~400 games
![Page 33: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/33.jpg)
Football Optimization==> ColumnFilter(symKeys=["player.name", " INTERNAL_AGGREGATEe91b055b-a943-4ddd-9fe8-e746407c504a", "
INTERNAL_AGGREGATE240cfcd2-24d9-48a2-8ca9-fb0286f3d323"], returnItemNames=["player.name", "COLLECT(DISTINCT team.name)", "goals"], _rows=10, _db_hits=0)
==> Top(orderBy=["SortItem(Cached( INTERNAL_AGGREGATE240cfcd2-24d9-48a2-8ca9-fb0286f3d323 of type Number),false)"], limit="Literal(10)", _rows=10, _db_hits=0)
==> EagerAggregation(keys=["Cached(player.name of type Any)"], aggregates=["( INTERNAL_AGGREGATEe91b055b-a943-4ddd-9fe8-e746407c504a,Distinct(Collect(Property(team,name(0))),Property(team,name(0))))", "( INTERNAL_AGGREGATE240cfcd2-24d9-48a2-8ca9-fb0286f3d323,Sum(Property(stats,goals(13))))"], _rows=503, _db_hits=10899)
==> Extract(symKeys=["stats", " UNNAMED12", " UNNAMED108", "season", " UNNAMED55", "player", "team", " UNNAMED124", " UNNAMED85", "game"], exprKeys=["player.name"], _rows=5192, _db_hits=5192)
==> PatternMatch(g="(player)-[' UNNAMED124']-(stats)", _rows=5192, _db_hits=0)
==> Filter(pred="Property(season,name(0)) == Literal(2012-2013)", _rows=5192, _db_hits=15542)
==> TraversalMatcher(trail="(season)-[ UNNAMED12:contains_match WHERE true AND true]->(game)<-[ UNNAMED85:in WHERE true AND true]-(stats)-[ UNNAMED108:for WHERE true AND true]->(team)<-
[ UNNAMED55:away_team WHERE true AND true]-(game)", _rows=15542, _db_hits=1620462)
![Page 34: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/34.jpg)
Break out the match statements
MATCH (game)<-[:contains_match]-(season:Season)
MATCH (team)<-[:away_team]-(game)
MATCH (stats)-[:in]->(game)
MATCH (team)<-[:for]-(stats)<-[:played]-(player)
WHERE season.name = "2012-2013"
RETURN player.name,
COLLECT(DISTINCT team.name),
SUM(stats.goals) as goals
ORDER BY goals DESCLIMIT 10200 ms w/ ~900 players, ~20 teams, ~400 games
![Page 35: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/35.jpg)
Start small
• Smallest cardinality label first
• Smallest intermediate result set first
![Page 36: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/36.jpg)
Exploring cardinalitiesMATCH (game)<-[:contains_match]-(season:Season)
RETURN COUNT(DISTINCT game), COUNT(DISTINCT season)
1140 games, 3 seasons
MATCH (team)<-[:away_team]-(game:Game)
RETURN COUNT(DISTINCT team), COUNT(DISTINCT game)
25 teams, 1140 games
![Page 37: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/37.jpg)
Exploring cardinalitiesMATCH (stats)-[:in]->(game:Game)
RETURN COUNT(DISTINCT stats), COUNT(DISTINCT game)
31117 stats, 1140 games
MATCH (stats)<-[:played]-(player:Player)
RETURN COUNT(DISTINCT stats), COUNT(DISTINCT player)
31117 stats, 880 players
![Page 38: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/38.jpg)
Look for teams firstMATCH (team)<-[:away_team]-(game:Game)MATCH (game)<-[:contains_match]-(season)
WHERE season.name = "2012-2013"
MATCH (stats)-[:in]->(game)
MATCH (team)<-[:for]-(stats)<-[:played]-(player)
RETURN player.name,
COLLECT(DISTINCT team.name),
SUM(stats.goals) as goals
ORDER BY goals DESC
LIMIT 10162 ms w/ ~900 players, ~20 teams, ~400 games
![Page 39: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/39.jpg)
==> ColumnFilter(symKeys=["player.name", " INTERNAL_AGGREGATEbb08f36b-a70d-46b3-9297-b0c7ec85c969", " INTERNAL_AGGREGATE199af213-e3bd-400f-aba9-8ca2a9e153c5"], returnItemNames=["player.name", "COLLECT(DISTINCT team.name)", "goals"], _rows=10, _db_hits=0)
==> Top(orderBy=["SortItem(Cached( INTERNAL_AGGREGATE199af213-e3bd-400f-aba9-8ca2a9e153c5 of type Number),false)"], limit="Literal(10)", _rows=10, _db_hits=0)
==> EagerAggregation(keys=["Cached(player.name of type Any)"], aggregates=["( INTERNAL_AGGREGATEbb08f36b-a70d-46b3-9297-b0c7ec85c969,Distinct(Collect(Property(team,name(0))),Property(team,name(0))))", "( INTERNAL_AGGREGATE199af213-e3bd-400f-aba9-8ca2a9e153c5,Sum(Property(stats,goals(13))))"], _rows=503, _db_hits=10899)
==> Extract(symKeys=["stats", " UNNAMED12", " UNNAMED168", "season", " UNNAMED125", "player", "team", " UNNAMED152", " UNNAMED51", "game"], exprKeys=["player.name"], _rows=5192, _db_hits=5192)
==> PatternMatch(g="(stats)-[' UNNAMED152']-(team),(player)-[' UNNAMED168']-(stats)", _rows=5192, _db_hits=0)
==> PatternMatch(g="(stats)-[' UNNAMED125']-(game)", _rows=10394, _db_hits=0)
==> Filter(pred="Property(season,name(0)) == Literal(2012-2013)", _rows=380, _db_hits=380)
==> PatternMatch(g="(season)-[' UNNAMED51']-(game)", _rows=380, _db_hits=1140)
==> TraversalMatcher(trail="(game)-[ UNNAMED12:away_team WHERE true AND true]->(team)", _rows=1140,
_db_hits=1140)
Look for teams first
![Page 40: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/40.jpg)
Filter games a bit earlierMATCH (game)<-[:contains_match]-(season:Season)
WHERE season.name = "2012-2013"MATCH (team)<-[:away_team]-(game)
MATCH (stats)-[:in]->(game)
MATCH (team)<-[:for]-(stats)<-[:played]-(player)
RETURN player.name,
COLLECT(DISTINCT team.name),
SUM(stats.goals) as goals
ORDER BY goals DESC
LIMIT 10148 ms w/ ~900 players, ~20 teams, ~400 games
![Page 41: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/41.jpg)
Filter out stats with no goalsMATCH (game)<-[:contains_match]-(season:Season)
WHERE season.name = "2012-2013"MATCH (team)<-[:away_team]-(game)
MATCH (stats)-[:in]->(game)WHERE stats.goals > 0MATCH (team)<-[:for]-(stats)<-[:played]-(player)RETURN player.name, COLLECT(DISTINCT team.name), SUM(stats.goals) as goalsORDER BY goals DESCLIMIT 10
59 ms w/ ~900 players, ~20 teams, ~400 games
![Page 42: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/42.jpg)
Movie query optimizationMATCH (movie:Movie {title: {title} })
MATCH (genre)<-[:HAS_GENRE]-(movie)MATCH (director)-[:DIRECTED]->(movie)MATCH (actor)-[:ACTED_IN]->(movie)MATCH (writer)-[:WRITER_OF]->(movie)MATCH (actor)-[:ACTED_IN]->(actormovies)MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword) as weight, count(DISTINCT actormovies) as actormoviesweight, movie, collect(DISTINCT genre.name) as genres, collect(DISTINCT director.name) as directors, actor, collect(DISTINCT writer.name) as writersORDER BY weight DESC, actormoviesweight DESCWITH collect(DISTINCT {name: actor.name, weight: actormoviesweight}) as actors, movie, collect(DISTINCT {related: {title: related.title}, weight: weight}) as related, genres, directors, writersMATCH (movie)-[:HAS_KEYWORD]->(keyword:Keyword)<-[:HAS_KEYWORD]-(movies)WITH keyword.name as keyword, count(movies) as keyword_weight, movie, related, actors, genres, directors, writersORDER BY keyword_weightRETURN collect(DISTINCT keyword), movie, actors, related, genres, directors, writers
![Page 43: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/43.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })
MATCH (genre)<-[:HAS_GENRE]-(movie)MATCH (director)-[:DIRECTED]->(movie)MATCH (actor)-[:ACTED_IN]->(movie)MATCH (writer)-[:WRITER_OF]->(movie)MATCH (actor)-[:ACTED_IN]->(actormovies)MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword) as weight, count(DISTINCT actormovies) as actormoviesweight, movie, collect(DISTINCT genre.name) as genres, collect(DISTINCT director.name) as directors, actor, collect(DISTINCT writer.name) as writersORDER BY weight DESC, actormoviesweight DESCWITH collect(DISTINCT {name: actor.name, weight: actormoviesweight}) as actors, movie, collect(DISTINCT {related: {title: related.title}, weight: weight}) as related, genres, directors, writersMATCH (movie)-[:HAS_KEYWORD]->(keyword:Keyword)<-[:HAS_KEYWORD]-(movies)WITH keyword.name as keyword, count(movies) as keyword_weight, movie, related, actors, genres, directors, writersORDER BY keyword_weightRETURN collect(DISTINCT keyword), movie, actors, related, genres, directors, writers
![Page 44: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/44.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })MATCH (genre)<-[:HAS_GENRE]-(movie)MATCH (director)-[:DIRECTED]->(movie)MATCH (actor)-[:ACTED_IN]->(movie)MATCH (writer)-[:WRITER_OF]->(movie)MATCH (actor)-[:ACTED_IN]->(actormovies)MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword) as weight, count(DISTINCT actormovies) as actormoviesweight, movie, collect(DISTINCT genre.name) as genres, collect(DISTINCT director.name) as directors, actor, collect(DISTINCT writer.name) as writersORDER BY weight DESC, actormoviesweight DESCWITH collect(DISTINCT {name: actor.name, weight: actormoviesweight}) as actors, movie, collect(DISTINCT {related: {title: related.title}, weight: weight}) as related, genres, directors, writersMATCH (movie)-[:HAS_KEYWORD]->(keyword:Keyword)<-[:HAS_KEYWORD]-(movies)WITH keyword.name as keyword, count(movies) as keyword_weight, movie, related, actors, genres, directors, writersORDER BY keyword_weightRETURN collect(DISTINCT keyword), movie, actors, related, genres, directors, writers
![Page 45: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/45.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })
MATCH (genre)<-[:HAS_GENRE]-(movie)MATCH (director)-[:DIRECTED]->(movie)MATCH (actor)-[:ACTED_IN]->(movie)MATCH (writer)-[:WRITER_OF]->(movie)MATCH (actor)-[:ACTED_IN]->(actormovies)MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword) as weight, count(DISTINCT actormovies) as actormoviesweight, movie, collect(DISTINCT genre.name) as genres, collect(DISTINCT director.name) as directors, actor, collect(DISTINCT writer.name) as writersORDER BY weight DESC, actormoviesweight DESCWITH collect(DISTINCT {name: actor.name, weight: actormoviesweight}) as actors, movie, collect(DISTINCT {related: {title: related.title}, weight: weight}) as related, genres, directors, writersMATCH (movie)-[:HAS_KEYWORD]->(keyword:Keyword)<-[:HAS_KEYWORD]-(movies)WITH keyword.name as keyword, count(movies) as keyword_weight, movie, related, actors, genres, directors, writersORDER BY keyword_weightRETURN collect(DISTINCT keyword), movie, actors, related, genres, directors, writers
![Page 46: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/46.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })
MATCH (genre)<-[:HAS_GENRE]-(movie)
MATCH (director)-[:DIRECTED]->(movie)MATCH (actor)-[:ACTED_IN]->(movie)MATCH (writer)-[:WRITER_OF]->(movie)MATCH (actor)-[:ACTED_IN]->(actormovies)MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword) as weight, count(DISTINCT actormovies) as actormoviesweight, movie, collect(DISTINCT genre.name) as genres, collect(DISTINCT director.name) as directors, actor, collect(DISTINCT writer.name) as writersORDER BY weight DESC, actormoviesweight DESCWITH collect(DISTINCT {name: actor.name, weight: actormoviesweight}) as actors, movie, collect(DISTINCT {related: {title: related.title}, weight: weight}) as related, genres, directors, writersMATCH (movie)-[:HAS_KEYWORD]->(keyword:Keyword)<-[:HAS_KEYWORD]-(movies)WITH keyword.name as keyword, count(movies) as keyword_weight, movie, related, actors, genres, directors, writersORDER BY keyword_weightRETURN collect(DISTINCT keyword), movie, actors, related, genres, directors, writers
![Page 47: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/47.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })
MATCH (genre)<-[:HAS_GENRE]-(movie)MATCH (director)-[:DIRECTED]->(movie)
MATCH (actor)-[:ACTED_IN]->(movie)MATCH (writer)-[:WRITER_OF]->(movie)MATCH (actor)-[:ACTED_IN]->(actormovies)MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword) as weight, count(DISTINCT actormovies) as actormoviesweight, movie, collect(DISTINCT genre.name) as genres, collect(DISTINCT director.name) as directors, actor, collect(DISTINCT writer.name) as writersORDER BY weight DESC, actormoviesweight DESCWITH collect(DISTINCT {name: actor.name, weight: actormoviesweight}) as actors, movie, collect(DISTINCT {related: {title: related.title}, weight: weight}) as related, genres, directors, writersMATCH (movie)-[:HAS_KEYWORD]->(keyword:Keyword)<-[:HAS_KEYWORD]-(movies)WITH keyword.name as keyword, count(movies) as keyword_weight, movie, related, actors, genres, directors, writersORDER BY keyword_weightRETURN collect(DISTINCT keyword), movie, actors, related, genres, directors, writers
![Page 48: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/48.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })
MATCH (genre)<-[:HAS_GENRE]-(movie)MATCH (director)-[:DIRECTED]->(movie)MATCH (actor)-[:ACTED_IN]->(movie)
MATCH (writer)-[:WRITER_OF]->(movie)MATCH (actor)-[:ACTED_IN]->(actormovies)MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword) as weight, count(DISTINCT actormovies) as actormoviesweight, movie, collect(DISTINCT genre.name) as genres, collect(DISTINCT director.name) as directors, actor, collect(DISTINCT writer.name) as writersORDER BY weight DESC, actormoviesweight DESCWITH collect(DISTINCT {name: actor.name, weight: actormoviesweight}) as actors, movie, collect(DISTINCT {related: {title: related.title}, weight: weight}) as related, genres, directors, writersMATCH (movie)-[:HAS_KEYWORD]->(keyword:Keyword)<-[:HAS_KEYWORD]-(movies)WITH keyword.name as keyword, count(movies) as keyword_weight, movie, related, actors, genres, directors, writersORDER BY keyword_weightRETURN collect(DISTINCT keyword), movie, actors, related, genres, directors, writers
![Page 49: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/49.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })
MATCH (genre)<-[:HAS_GENRE]-(movie)MATCH (director)-[:DIRECTED]->(movie)MATCH (actor)-[:ACTED_IN]->(movie)MATCH (writer)-[:WRITER_OF]->(movie)
MATCH (actor)-[:ACTED_IN]->(actormovies)MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword) as weight, count(DISTINCT actormovies) as actormoviesweight, movie, collect(DISTINCT genre.name) as genres, collect(DISTINCT director.name) as directors, actor, collect(DISTINCT writer.name) as writersORDER BY weight DESC, actormoviesweight DESCWITH collect(DISTINCT {name: actor.name, weight: actormoviesweight}) as actors, movie, collect(DISTINCT {related: {title: related.title}, weight: weight}) as related, genres, directors, writersMATCH (movie)-[:HAS_KEYWORD]->(keyword:Keyword)<-[:HAS_KEYWORD]-(movies)WITH keyword.name as keyword, count(movies) as keyword_weight, movie, related, actors, genres, directors, writersORDER BY keyword_weightRETURN collect(DISTINCT keyword), movie, actors, related, genres, directors, writers
![Page 50: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/50.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })
MATCH (genre)<-[:HAS_GENRE]-(movie)MATCH (director)-[:DIRECTED]->(movie)MATCH (actor)-[:ACTED_IN]->(movie)MATCH (writer)-[:WRITER_OF]->(movie)MATCH (actor)-[:ACTED_IN]->(actormovies)MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword) as weight, count(DISTINCT actormovies) as actormoviesweight, movie, collect(DISTINCT genre.name) as genres, collect(DISTINCT director.name) as directors, actor, collect(DISTINCT writer.name) as writersORDER BY weight DESC, actormoviesweight DESCWITH collect(DISTINCT {name: actor.name, weight: actormoviesweight}) as actors, movie, collect(DISTINCT {related: {title: related.title}, weight: weight}) as related, genres, directors, writersMATCH (movie)-[:HAS_KEYWORD]->(keyword:Keyword)<-[:HAS_KEYWORD]-(movies)WITH keyword.name as keyword, count(movies) as keyword_weight, movie, related, actors, genres, directors, writersORDER BY keyword_weightRETURN collect(DISTINCT keyword), movie, actors, related, genres, directors, writers
![Page 51: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/51.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })
MATCH (genre)<-[:HAS_GENRE]-(movie)MATCH (director)-[:DIRECTED]->(movie)MATCH (actor)-[:ACTED_IN]->(movie)MATCH (writer)-[:WRITER_OF]->(movie)MATCH (actor)-[:ACTED_IN]->(actormovies)MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword) as weight, count(DISTINCT actormovies) as actormoviesweight, movie, collect(DISTINCT genre.name) as genres, collect(DISTINCT director.name) as directors, actor, collect(DISTINCT writer.name) as writersORDER BY weight DESC, actormoviesweight DESCWITH collect(DISTINCT {name: actor.name, weight: actormoviesweight}) as actors, movie, collect(DISTINCT {related: {title: related.title}, weight: weight}) as related, genres, directors, writersMATCH (movie)-[:HAS_KEYWORD]->(keyword:Keyword)<-[:HAS_KEYWORD]-(movies)WITH keyword.name as keyword, count(movies) as keyword_weight, movie, related, actors, genres, directors, writersORDER BY keyword_weightRETURN collect(DISTINCT keyword), movie, actors, related, genres, directors, writers
![Page 52: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/52.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })
MATCH (genre)<-[:HAS_GENRE]-(movie)MATCH (director)-[:DIRECTED]->(movie)MATCH (actor)-[:ACTED_IN]->(movie)MATCH (writer)-[:WRITER_OF]->(movie)MATCH (actor)-[:ACTED_IN]->(actormovies)MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword) as weight, count(DISTINCT actormovies) as actormoviesweight, movie, collect(DISTINCT genre.name) as genres, collect(DISTINCT director.name) as directors, actor, collect(DISTINCT writer.name) as writersORDER BY weight DESC, actormoviesweight DESCWITH collect(DISTINCT {name: actor.name, weight: actormoviesweight}) as actors, movie, collect(DISTINCT {related: {title: related.title}, weight: weight}) as
related, genres, directors, writersMATCH (movie)-[:HAS_KEYWORD]->(keyword:Keyword)<-[:HAS_KEYWORD]-(movies)WITH keyword.name as keyword, count(movies) as keyword_weight, movie, related, actors, genres, directors, writersORDER BY keyword_weightRETURN collect(DISTINCT keyword), movie, actors, related, genres, directors, writers
![Page 53: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/53.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })
MATCH (genre)<-[:HAS_GENRE]-(movie)MATCH (director)-[:DIRECTED]->(movie)MATCH (actor)-[:ACTED_IN]->(movie)MATCH (writer)-[:WRITER_OF]->(movie)MATCH (actor)-[:ACTED_IN]->(actormovies)MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword) as weight, count(DISTINCT actormovies) as actormoviesweight, movie, collect(DISTINCT genre.name) as genres, collect(DISTINCT director.name) as directors, actor, collect(DISTINCT writer.name) as writersORDER BY weight DESC, actormoviesweight DESCWITH collect(DISTINCT {name: actor.name, weight: actormoviesweight}) as actors, movie, collect(DISTINCT {related: {title: related.title}, weight: weight}) as related, genres, directors, writersMATCH (movie)-[:HAS_KEYWORD]->(keyword:Keyword)<-[:HAS_KEYWORD]-(movies)WITH keyword.name as keyword, count(movies) as keyword_weight, movie, related, actors, genres, directors, writersORDER BY keyword_weightRETURN collect(DISTINCT keyword), movie, actors, related, genres, directors, writers
![Page 54: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/54.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })<-[:ACTED_IN]-(actor)
WITH movie, actor, length((actor)-[:ACTED_IN]->()) as actormoviesweight // 1 row per actorORDER BY actormoviesweight DESCWITH movie, collect({name: actor.name, weight: actormoviesweight}) as actors // 1 row MATCH (movie)-[:HAS_GENRE]->(genre)WITH movie, actors, collect(genre) as genres // 1 row MATCH (director)-[:DIRECTED]->(movie)WITH movie, actors, genres, collect(director.name) as directors // 1 rowMATCH (writer)-[:WRITER_OF]->(movie)WITH movie, actors, genres, directors, collect(writer.name) as writers // 1 row MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword.name) as keywords, movie, genres, directors, actors, writers // 1 row per related movieORDER BY keywords DESCWITH collect(DISTINCT { related: { title: related.title }, weight: keywords }) as related, movie, actors, genres, directors, writers // 1 rowMATCH (movie)-[:HAS_KEYWORD]->(keyword)RETURN collect(keyword.name) as keywords, related, movie, actors, genres, directors, writers
10x faster
![Page 55: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/55.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })<-[:ACTED_IN]-(actor)
WITH movie, actor, length((actor)-[:ACTED_IN]->()) as actormoviesweight // 1 row per actorORDER BY actormoviesweight DESCWITH movie, collect({name: actor.name, weight: actormoviesweight}) as actors // 1 row MATCH (movie)-[:HAS_GENRE]->(genre)WITH movie, actors, collect(genre) as genres // 1 row MATCH (director)-[:DIRECTED]->(movie)WITH movie, actors, genres, collect(director.name) as directors // 1 rowMATCH (writer)-[:WRITER_OF]->(movie)WITH movie, actors, genres, directors, collect(writer.name) as writers // 1 row MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword.name) as keywords, movie, genres, directors, actors, writers // 1 row per related movieORDER BY keywords DESCWITH collect(DISTINCT { related: { title: related.title }, weight: keywords }) as related, movie, actors, genres, directors, writers // 1 rowMATCH (movie)-[:HAS_KEYWORD]->(keyword)RETURN collect(keyword.name) as keywords, related, movie, actors, genres, directors, writers
10x faster
![Page 56: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/56.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })<-[:ACTED_IN]-(actor)WITH movie, actor, length((actor)-
[:ACTED_IN]->()) as actormoviesweightORDER BY actormoviesweight DESC // 1 row per actorWITH movie, collect({name: actor.name, weight: actormoviesweight}) as actors // 1 row MATCH (movie)-[:HAS_GENRE]->(genre)WITH movie, actors, collect(genre) as genres // 1 row MATCH (director)-[:DIRECTED]->(movie)WITH movie, actors, genres, collect(director.name) as directors // 1 rowMATCH (writer)-[:WRITER_OF]->(movie)WITH movie, actors, genres, directors, collect(writer.name) as writers // 1 row MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword.name) as keywords, movie, genres, directors, actors, writers // 1 row per related movieORDER BY keywords DESCWITH collect(DISTINCT { related: { title: related.title }, weight: keywords }) as related, movie, actors, genres, directors, writers // 1 rowMATCH (movie)-[:HAS_KEYWORD]->(keyword)RETURN collect(keyword.name) as keywords, related, movie, actors, genres, directors, writers
10x faster
![Page 57: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/57.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })<-[:ACTED_IN]-(actor)
WITH movie, actor, length((actor)-[:ACTED_IN]->()) as actormoviesweightORDER BY actormoviesweight DESC // 1 row per actorWITH movie, collect({name: actor.name, weight: actormoviesweight}) as actors // 1 row MATCH (movie)-[:HAS_GENRE]->(genre)WITH movie, actors, collect(genre) as genres // 1 row MATCH (director)-[:DIRECTED]->(movie)WITH movie, actors, genres, collect(director.name) as directors // 1 rowMATCH (writer)-[:WRITER_OF]->(movie)WITH movie, actors, genres, directors, collect(writer.name) as writers // 1 row MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword.name) as keywords, movie, genres, directors, actors, writers // 1 row per related movieORDER BY keywords DESCWITH collect(DISTINCT { related: { title: related.title }, weight: keywords }) as related, movie, actors, genres, directors, writers // 1 rowMATCH (movie)-[:HAS_KEYWORD]->(keyword)RETURN collect(keyword.name) as keywords, related, movie, actors, genres, directors, writers
10x faster
![Page 58: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/58.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })<-[:ACTED_IN]-(actor)
WITH movie, actor, length((actor)-[:ACTED_IN]->()) as actormoviesweightORDER BY actormoviesweight DESC // 1 row per actorWITH movie, collect({name: actor.name, weight: actormoviesweight}) as actors // 1 row MATCH (movie)-[:HAS_GENRE]->(genre)WITH movie, actors, collect(genre) as genres // 1 row MATCH (director)-[:DIRECTED]->(movie)WITH movie, actors, genres, collect(director.name) as directors // 1 rowMATCH (writer)-[:WRITER_OF]->(movie)WITH movie, actors, genres, directors, collect(writer.name) as writers // 1 row MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword.name) as keywords, movie, genres, directors, actors, writers // 1 row per related movieORDER BY keywords DESCWITH collect(DISTINCT { related: { title: related.title }, weight: keywords }) as related, movie, actors, genres, directors, writers // 1 rowMATCH (movie)-[:HAS_KEYWORD]->(keyword)RETURN collect(keyword.name) as keywords, related, movie, actors, genres, directors, writers
10x faster
![Page 59: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/59.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })<-[:ACTED_IN]-(actor)
WITH movie, actor, length((actor)-[:ACTED_IN]->()) as actormoviesweightORDER BY actormoviesweight DESC // 1 row per actorWITH movie, collect({name: actor.name, weight: actormoviesweight}) as actors // 1 row MATCH (movie)-[:HAS_GENRE]->(genre)WITH movie, actors, collect(genre) as genres // 1 row MATCH (director)-[:DIRECTED]->(movie)WITH movie, actors, genres, collect(director.name) as directors // 1 rowMATCH (writer)-[:WRITER_OF]->(movie)WITH movie, actors, genres, directors, collect(writer.name) as writers // 1 row MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword.name) as keywords, movie, genres, directors, actors, writers // 1 row per related movieORDER BY keywords DESCWITH collect(DISTINCT { related: { title: related.title }, weight: keywords }) as related, movie, actors, genres, directors, writers // 1 rowMATCH (movie)-[:HAS_KEYWORD]->(keyword)RETURN collect(keyword.name) as keywords, related, movie, actors, genres, directors, writers
10x faster
![Page 60: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/60.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })<-[:ACTED_IN]-(actor)
WITH movie, actor, length((actor)-[:ACTED_IN]->()) as actormoviesweightORDER BY actormoviesweight DESC // 1 row per actorWITH movie, collect({name: actor.name, weight: actormoviesweight}) as actors // 1 row MATCH (movie)-[:HAS_GENRE]->(genre)WITH movie, actors, collect(genre) as genres // 1 row MATCH (director)-[:DIRECTED]->(movie)WITH movie, actors, genres, collect(director.name) as directors // 1 rowMATCH (writer)-[:WRITER_OF]->(movie)WITH movie, actors, genres, directors, collect(writer.name) as writers // 1 row MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword.name) as keywords, movie, genres, directors, actors, writers // 1 row per related movieORDER BY keywords DESCWITH collect(DISTINCT { related: { title: related.title }, weight: keywords }) as related, movie, actors, genres, directors, writers // 1 rowMATCH (movie)-[:HAS_KEYWORD]->(keyword)RETURN collect(keyword.name) as keywords, related, movie, actors, genres, directors, writers
10x faster
![Page 61: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/61.jpg)
Movie query optimizationMATCH (movie:Movie {title: 'The Matrix' })<-[:ACTED_IN]-(actor)
WITH movie, actor, length((actor)-[:ACTED_IN]->()) as actormoviesweightORDER BY actormoviesweight DESC // 1 row per actorWITH movie, collect({name: actor.name, weight: actormoviesweight}) as actors // 1 row MATCH (movie)-[:HAS_GENRE]->(genre)WITH movie, actors, collect(genre) as genres // 1 row MATCH (director)-[:DIRECTED]->(movie)WITH movie, actors, genres, collect(director.name) as directors // 1 rowMATCH (writer)-[:WRITER_OF]->(movie)WITH movie, actors, genres, directors, collect(writer.name) as writers // 1 row MATCH (movie)-[:HAS_KEYWORD]->(keyword)<-[:HAS_KEYWORD]-(movies:Movie)WITH DISTINCT movies as related, count(DISTINCT keyword.name) as keywords, movie, genres, directors, actors, writers // 1 row per related movieORDER BY keywords DESCWITH collect(DISTINCT { related: { title: related.title }, weight: keywords }) as related, movie, actors, genres, directors, writers // 1 rowMATCH (movie)-[:HAS_KEYWORD]->(keyword)RETURN collect(keyword.name) as keywords, related, movie, actors, genres, directors, writers // 1 row
10x faster
![Page 62: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/62.jpg)
Design for Queryability
Model
![Page 63: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/63.jpg)
Design for Queryability
Query
![Page 64: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/64.jpg)
Design for Queryability
Model
![Page 65: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/65.jpg)
Making the implicit explicit
• When you have implicit relationships in the graph you can sometimes get better query performance by modeling the relationship explicitly
![Page 66: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/66.jpg)
Making the implicit explicit
![Page 67: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/67.jpg)
Refactor property to node
Bad:MATCH (g:Game)WHERE g.date > 1343779200 AND g.date < 1369094400RETURN g
![Page 68: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/68.jpg)
Good:MATCH (s:Season)-[:contains]->(g)WHERE season.name = "2012-2013"RETURN g
Refactor property to node
![Page 69: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/69.jpg)
Conclusion
• Avoid the global scan
• Add indexes / unique constraints
• Split up MATCH statements
• Measure, measure, measure, tweak, repeat
• Soon Cypher will do a lot of this for you!
![Page 70: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/70.jpg)
Bonus tip
• Use transactions/transactional cypher endpoint
![Page 71: Optimizing Cypher Queries in Neo4j](https://reader033.vdocuments.site/reader033/viewer/2022061218/54b663cc4a795938328b4651/html5/thumbnails/71.jpg)
Q & A
• If you have them send them in