Статьи

Neo4j: сделать отношения свойств

Я провел несколько выходных, работая над  книгой ДжимаЯна  и  Эмиля « Базы данных графов », и одна из вещей, которые они подчеркивают, заключается в том, что графы позволяют нам  строить отношения с первоклассными гражданами в нашей модели .

Оглядываясь назад на пару графиков, которые я смоделировал в прошлом году, я понимаю, что я не совсем понял это, и хотя моделируемые мною графики имели некоторые отношения большую часть времени, когда я определял вещи как свойства на узлах.

Хотя это нормально, я думаю, что мы теряем часть мощности графа, и не обязательно очевидно, что мы потеряли, пока мы не смоделируем свойство как отношение и не увидим, какие возможности открываются.

Например, на своем футбольном графике я хотел записать дату матчей и изначально сохранил ее как свойство в матче, прежде чем осознал, что моделирование его представляет собой отношение, которое может открыть некоторые интересные запросы.

Я создал эти отношения между матчем и месяцем, в котором он состоялся:

MATCH-[:in_month]->MONTH

Благодаря этим отношениям я теперь могу легко узнать, какие матчи Гарет Бэйл сыграли в сентябре, например:

START player = node:players('name:"Gareth Bale"'), month=node:months('name:September')
MATCH player-[:played_in]-game
WHERE game-[:in_month]-month
RETURN game.name, game.home_goals + "-" +game.away_goals AS score, game.date
+----------------------------------------------------------------------------------+
| game.name                                  | score | game.date                   |
+----------------------------------------------------------------------------------+
| "Reading vs Tottenham Hotspur"             | "1-3" | "2012-09-16 16:00:00 +0100" |
| "Tottenham Hotspur vs Norwich City"        | "1-1" | "2012-09-01 15:00:00 +0100" |
| "Tottenham Hotspur vs Queens Park Rangers" | "2-1" | "2012-09-23 16:00:00 +0100" |
| "Manchester United vs Tottenham Hotspur"   | "2-3" | "2012-09-29 17:30:00 +0100" |
+----------------------------------------------------------------------------------+

Или мы могли бы найти все матчи в декабре, где одна из команд выиграла с более чем 2 голами:

START month=node:months('name:December')
MATCH month-[:in_month]-game
WHERE ABS(game.home_goals - game.away_goals) > 2
RETURN game.name, game.home_goals + "-" +game.away_goals AS score, game.date
+----------------------------------------------------------------------------+
| game.name                            | score | game.date                   |
+----------------------------------------------------------------------------+
| "Sunderland vs Reading"              | "3-0" | "2012-12-11 19:45:00 +0000" |
| "Reading vs Arsenal"                 | "2-5" | "2012-12-17 20:00:00 +0000" |
| "Newcastle United vs Wigan Athletic" | "3-0" | "2012-12-03 20:00:00 +0000" |
| "Fulham vs Tottenham Hotspur"        | "0-3" | "2012-12-01 15:00:00 +0000" |
| "Liverpool vs Fulham"                | "4-0" | "2012-12-22 17:30:00 +0000" |
| "Chelsea vs Aston Villa"             | "8-0" | "2012-12-23 16:00:00 +0000" |
| "Aston Villa vs Tottenham Hotspur"   | "0-4" | "2012-12-26 17:30:00 +0000" |
| "Aston Villa vs Wigan Athletic"      | "0-3" | "2012-12-29 15:00:00 +0000" |
| "Arsenal vs Newcastle United"        | "7-3" | "2012-12-29 17:30:00 +0000" |
| "Queens Park Rangers vs Liverpool"   | "0-3" | "2012-12-30 16:00:00 +0000" |
+----------------------------------------------------------------------------+

Конечно, есть и другие вещи, которые мы можем выяснить сейчас, когда у нас есть эти отношения от месяцев до явных совпадений, но не только даты, когда эта идея оказывается полезной.

У меня уже были моделированные игроки в наборе данных, но я подумал, что было бы интересно узнать больше о наборе данных, основанном на том, откуда пришли игроки.

Поэтому я добавил следующие отношения:

PLAYER-[:comes_from]->COUNTRY-[:is_in]->CONTINENT

Теперь мы можем найти лучших бомбардиров в Премьер-лиге (с точностью до прошлых выходных), например, из Южной Америки:

START continent = node:continents('name:"South America"')
MATCH continent-[:is_in]-country-[:comes_from]-player-[:played|subbed_on]-stats-[:in]-game
WHERE player-[:scored_in]-game
RETURN player.name, country.name, player.team, SUM(stats.goals) AS goals
ORDER BY goals DESC
LIMIT 5
+--------------------------------------------------------------+
| player.name       | country.name | player.team       | goals |
+--------------------------------------------------------------+
| "Luis Suárez"     | "Uruguay"    | "Liverpool"       | 18    |
| "Sergio Agüero"   | "Argentina"  | "Manchester City" | 9     |
| "Carlos Tevez"    | "Argentina"  | "Manchester City" | 8     |
| "Franco Di Santo" | "Argentina"  | "Wigan Athletic"  | 5     |
| "Ramires"         | "Brazil"     | "Chelsea"         | 4     |
+--------------------------------------------------------------+

Или мы могли бы узнать, сколько голов было забито игроками с каждого континента:

START continent = node:continents('name:*')
MATCH continent-[:is_in]-country-[:comes_from]-player-[:played|subbed_on]-stats-[:in]-game
WHERE player-[:scored_in]-game
RETURN continent.name, SUM(stats.goals) AS goals
ORDER BY goals DESC
+-------------------------+
| continent.name  | goals |
+-------------------------+
| "Europe"        | 569   |
| "Africa"        | 73    |
| "South America" | 62    |
| "North America" | 22    |
| "Asia"          | 3     |
| "Oceania"       | 3     |
+-------------------------+

Я не думаю, что каждое свойство должно быть отношением, но, безусловно, полезно подумать об этом, потому что оно позволяет вам думать об интересных запросах, о которых вы, возможно, раньше не думали.

Кроме того, я работаю над размещением этого набора данных где-нибудь, чтобы люди могли поиграть с зашифрованными запросами, поэтому, если вам будет интересно, дайте мне знать.