In this show-and-tell session, we’ll find out how Neo4j can make us a professional League of Legends player. First, we’ll import game data into a Neo4j graph. Then we will push the limits of Cypher to uncover hidden secrets that lie in the depth of LoL.
• Which champions perform best as allies?
• What is the most effective strategy to advance your champion?
• What enemy team setup is the most dangerous?
This session covers a rarely seen graph domain (gaming) and will provide you will solid, factual advice on how to play LoL.
13. League of Legends?
1. I play this game a lot
2. Rich API
3. There is library for API
https://developer.riotgames.com
14.
15. meraki-analytics/Orianna
A Java adaptation of the Riot Games LoL API
Summoner summoner =
RiotAPI.getSummonerByName(“FylmTM");
println(summoner.getName()
+ " is a level “ + summoner.getLevel());
16. Neo4j
Highly scalable native graph
database that leverages data
relationships as
first-class entities.
by Neo Technology, Inc.
33. Cypher
Cypher is a declarative
graph query language that
allows for expressive and
efficient querying.
https://github.com/opencypher/openCypher
34. Cypher
( ) - node
--> - relationship
Keywords:
- MATCH
- CREATE
- WHERE
- RETURN
MATCH (jug) RETURN jug
MATCH (attendees)-->(jug)
RETURN *
MATCH (attendees)-->(jug)
WHERE jug.city = “Kaunas”
RETURN *
42. Create database
File dbDir = new File(databasePath);
GraphDatabaseService db = new GraphDatabaseFactory()
.newEmbeddedDatabaseBuilder(dbDir)
.newGraphDatabase();
47. neo4j-contrib/neo4j-apoc-procedures
Awesome procedures for Neo4j 3.0 - codenamed "apoc"
// examines the full graph to create the meta-graph
CALL apoc.meta.graph();
Apoc was the technician and driver on board of the
Nebuchadnezzar in the Matrix movie.
He was killed by Cypher.
48. Import result
• Season 6, EUNE region
• Players: me & 7 friends
MATCH (n) RETURN count(n) as nodeCount
nodeCount
336729
50. Query #1 How many games I have played?
MATCH (s:Summoner {name: "FylmTM"})
MATCH (s)-[:PARTICIPATED|:PARTICIPATED_IN_MATCH]->(sMatch)
RETURN count(sMatch); // 59 ms
Count
110
51. Query #2 Who are my friends?
MATCH (s:Summoner {name: "FylmTM"})
MATCH (s)-[:PARTICIPATED]-()-[:PARTICIPATED_IN_MATCH]
->(sMatch)<-
[:PARTICIPATED_IN_MATCH]-()-[:PARTICIPATED]-(f)
WITH f.name as friendName, count(f) as gamesTogether
WHERE gamesTogether > 2
RETURN friendName, gamesTogether
ORDER BY gamesTogether DESC // 55 ms
friendName gamesTogether
Cryptael 107
Henua 28
Iger 11
XXpoMMou 10
yesCold 8
eskiuzi 3
52. Query #3 Most dangerous champions?
name total won lost %
Alistar 7 1 6 86%
Jax 12 3 9 75%
LeBlanc 8 2 6 75%
Dr. Mundo 7 2 5 71%
Miss Fortune 10 3 7 70%
MATCH (s:Summoner {name: "FylmTM"})
MATCH (s)-[:PARTICIPATED]->()-[:PLAYED_FOR_TEAM]->
(team {winner: true})<-[:HAS_TEAM]-()-[:HAS_TEAM]->(o)
<-[:PLAYED_FOR_TEAM]-()-[:PARTICIPATED_WITH_CHAMPION]->(c)
RETURN c.name as championName, count(c) as winCount
ORDER BY winCount DESC
55. Query #4 Any statistics?
MATCH (s:Summoner) WHERE s.name IN ["MrMgr", "Cryptael"]
MATCH (s)-[:PARTICIPATED|:PARTICIPANT_TIMELINE*2]->(pt)-[r]->(ptd)
WHERE pt.role = "SOLO" AND pt.lane = "MIDDLE"
AND r.name IN ["getCreepsPerMinDeltas", "getGoldPerMinDeltas"]
WITH s.name as name, r.name as stat,
sum(ptd.zero_to_ten) as `sum_0-10`,
size(filter(x IN collect(ptd.zero_to_ten) WHERE x <> 0))
as `size_0-10`,
sum(ptd.ten_to_twenty) as `sum_10-20`,
size(filter(x IN collect(ptd.ten_to_twenty) WHERE x <> 0))
as `size_10-20`,
sum(ptd.twenty_to_thirty) as `sum_20-30`,
size(filter(x IN collect(ptd.twenty_to_thirty) WHERE x <> 0))
as `size_20-30`,
sum(ptd.thirty_to_end) as `sum_30+`,
size(filter(x IN collect(ptd.thirty_to_end) WHERE x <> 0))
as `size_30+`
RETURN name, stat,
`sum_0-10` / `size_0-10` as `0-10`,
`sum_10-20` / `size_10-20` as `10-20`,
`sum_20-30` / `size_20-30` as `20-30`,
`sum_30+` / `size_30+` as `30+`
ORDER BY name, stat