user3620998
user3620998

Reputation: 3

Request for help wirting Cypher query through R-neo4j

I just started programming in R, neo4j and R-neo4j so please be indulgent if my question is trivial.

I have created following database (please confer the attached photo) [1] using R-neo4j and the following R Project code [2].

The database contains the outcome of computer game matches between four players. The dataset consists of four nodes, player 1 to player 4. The nodes are connected via the relationship "defeats", which indicates the outcome of the matches. There are two label entries attached to each relationship containing the following data: judge, game.

From the graph database using Cypher queries, I want to extract data in the following form (please confer the picture in [1]):

Winning player    Loosing player    Game         Judge
player 1          player 4          Starcraft    player 2
player 1          player 4          LOL          player 3
player 4          player 1          LOL          player 2
player 1          player 4          Starcraft    player 3
player 1          player 2          LOL          player 3
player 2          player 1          LOL          player 4
player 4          player 1          Starcraft    player 4

I want to make a query (preferred in the R-neo4j environment) to the graph database, where the input is "player 1" and the table above is returned.

I hope that my question is clear and someone can help me with this.

Have a good day.

Christian

[1] https://goo.gl/cMxXHo

[2] The R (Rneo4j) code:

clear(graph)
Y
player1 = createNode(graph,"user",ID="Player 1",male=T)
player2 = createNode(graph,"user",ID="Player 2",male=T)
player3 = createNode(graph,"user",ID="Player 3",male=F)
player4 = createNode(graph,"user",ID="Player 4",male=F)

addConstraint(graph,"user","ID")

rel1 = createRel(player1,"defeats",player4)
rel2 = createRel(player1,"defeats",player4)
rel3 = createRel(player4,"defeats",player1)
rel4 = createRel(player1,"defeats",player4)
rel5 = createRel(player1,"defeats",player2)
rel6 = createRel(player2,"defeats",player1)
rel7 = createRel(player3,"defeats",player1)

rel1 = updateProp(rel1, game = "Starcraft", judge = "Player 2")
rel2 = updateProp(rel2, game = "League of Legends", judge = "Player 3")
rel3 = updateProp(rel3, game = "League of Legends", judge = "Player 2")
rel4 = updateProp(rel4, game = "Starcraft", judge = "Player 3")
rel5 = updateProp(rel5, game = "League of Legends", judge = "Player 3")
rel6 = updateProp(rel6, game = "League of Legends", judge = "Player 4")
rel7 = updateProp(rel7, game = "Starcraft", judge = "Player 4")

Upvotes: 0

Views: 184

Answers (2)

ErnestoE
ErnestoE

Reputation: 1304

Looking at your graph, it kind of hits me of not having the right structure. Even though every scenario might be different, it is always good to consider what happens when you add MUCH more data. Can your model handle it?

For example, you are using relationships to represent results of games, which then of course requires attributes to store the judge and the games. Game names actually look like tournament games to me, but you'll know what works better. When storing the player and tournament names, you end up having a lot of repetition because the same names and players appear everywhere.

If you continue to add results between players you will end up with many relationships and the possibilities for error and repetition keep growing.

What can you do in order to improve your model then? Think of your basic relationship as a starting point but now it has outgrown the original requirement: you can introduce nodes for tournaments and nodes for games; keep relationships for storing the roles of the players within a game and so on. There is always more than one way to do it (TIMTOWTDI).

Given that a picture is worth a thousand words, look at the improved model here:

Improved Graph Model You see how it is also easier to add additional properties to the corresponding nodes or relationships in the model.

In order to produce your desired table with results, you then can use:

MATCH
  (g:Game)-[:WINNER]->(w:Player),
  (g)-[:LOSER]->(l:Player),
  (g)-[:JUDGE]->(j:Player),
  (g)<-[:HAS_GAMES]-(t:Tournament)
WHERE
  w.name = 'Player 1' OR l.name = 'Player 1'
RETURN
  w.name AS 'Winning Player',
  l.name AS 'Losing Player',
  t.name AS 'Game',
  j.name AS 'Judge'

and adapt for R as suggested by Nicole. If you pretend to add lots of data, I think this structure will adapt better to your needs, and you can also explore different ways of querying for the same data, as you can now start with the tournaments or explore games directly.

Upvotes: 0

Nicole White
Nicole White

Reputation: 7790

A couple things. If you want to use clear(graph) without having to type "Y", you can use clear(graph, input=F). Also, if you weren't aware, you can set properties on relationships when you create them:

rel1 = createRel(player1, "defeats", player4, game="Starcraft", judge="Player 2")

To answer the question, I'd do this:

getDataForPlayer = function(name) {
  query = "
  MATCH (winner:user)-[game:defeats]->(loser:user)
  WHERE winner.ID = {name} OR loser.ID = {name}
  RETURN winner.ID AS `Winning Player`,
         loser.ID AS `Losing Player`,
         game.game AS Game,
         game.judge AS Judge
  "

  return(cypher(graph, query, name=name))
}

getDataForPlayer("Player 1")

Output:

  Winning Player Losing Player              Game    Judge
1       Player 4      Player 1 League of Legends Player 2
2       Player 2      Player 1 League of Legends Player 4
3       Player 3      Player 1         Starcraft Player 4
4       Player 1      Player 2 League of Legends Player 3
5       Player 1      Player 4         Starcraft Player 2
6       Player 1      Player 4 League of Legends Player 3
7       Player 1      Player 4         Starcraft Player 3

Upvotes: 1

Related Questions