Статьи

Neo4j: создание графики технологического радара ThoughtWorks

Чтобы немного повеселиться на Рождество, я подумал, что было бы здорово создать график различных всплесков на технологическом радаре ThoughtWorks и того, как рекомендации менялись с течением времени.

Я написал сценарий для извлечения каждого сообщения (например, .NET Core ) и рекомендации, сделанные на каждом радаре, в котором он появился. В итоге я получил файл CSV :

1
2
3
4
5
6
7
8
9
|----------------------------------------------+----------+-------------|
|  technology                                  | date     | suggestion  |
|----------------------------------------------+----------+-------------|
|  AppHarbor                                   | Mar 2012 | Trial       |
|  Accumulate-only data                        | Nov 2015 | Assess      |
|  Accumulate-only data                        | May 2015 | Assess      |
|  Accumulate-only data                        | Jan 2015 | Assess      |
|  Buying solutions you can only afford one of | Mar 2012 | Hold        |
|----------------------------------------------+----------+-------------|

Затем я написал скрипт Cypher для создания следующей графовой модели:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
WITH ["Hold", "Assess", "Trial", "Adopt"] AS positions
UNWIND RANGE (0, size(positions) - 2) AS index
WITH positions[index] AS pos1, positions[index + 1] AS pos2
MERGE (position1:Position {value: pos1})
MERGE (position2:Position {value: pos2})
MERGE (position1)-[:NEXT]->(position2);
  
load csv with headers from "file:///blips.csv" AS row
MATCH (position:Position {value:  row.suggestion })
MERGE (tech:Technology {name:  row.technology })
MERGE (date:Date {value: row.date})
MERGE (recommendation:Recommendation {
  id: tech.name + "_" + date.value + "_" + position.value})
MERGE (recommendation)-[:ON_DATE]->(date)
MERGE (recommendation)-[:POSITION]->(position)
MERGE (recommendation)-[:TECHNOLOGY]->(tech);
  
match (date:Date)
SET date.timestamp = apoc.date.parse(date.value, "ms", "MMM yyyy");
  
MATCH (date:Date)
WITH date
ORDER BY date.timestamp
WITH COLLECT(date) AS dates
UNWIND range(0, size(dates)-2) AS index
WITH dates[index] as month1, dates[index+1] AS month2
MERGE (month1)-[:NEXT]->(month2);
  
MATCH (tech)<-[:TECHNOLOGY]-(reco:Recommendation)-[:ON_DATE]->(date)
WITH tech, reco, date
ORDER BY tech.name, date.timestamp
WITH tech, COLLECT(reco) AS recos
UNWIND range(0, size(recos)-2) AS index
WITH recos[index] AS reco1, recos[index+1] AS reco2
MERGE (reco1)-[:NEXT]->(reco2);

Обратите внимание, что я установил библиотеку процедур APOC, чтобы можно было преобразовать строковое представление даты в метку времени, используя функцию apoc.date.parse . Файл blips.csv должен находиться в каталоге импорта Neo4j.

Сейчас мы читаем, чтобы написать несколько запросов.

У технологического радара есть 4 позиции, которые можно занять для данной технологии: удержание, оценка, испытание и принятие:

  • Hold: обрабатывать с осторожностью
  • Оценить: стоит изучить с целью понять, как это повлияет на ваше предприятие.
  • Судебный процесс: стоит продолжить. Важно понимать, как создать эту возможность. Предприятия должны попробовать эту технологию в проекте, который может справиться с риском.
  • Принять: Мы твердо убеждены, что отрасль должна принять эти позиции. Мы используем их при необходимости в наших проектах.

Мне было любопытно, существовала ли когда-либо технология, в которой совет изначально был «Удерживать», но позже изменился на «Оценить». Я написал следующий запрос, чтобы узнать:

01
02
03
04
05
06
07
08
09
10
11
12
MATCH (pos1:Position {value:"Hold"})<-[:POSITION]-(reco)-[:TECHNOLOGY]->(tech),
      (pos2:Position {value:"Assess"})<-[:POSITION]-(otherReco)-[:TECHNOLOGY]->(tech),
      (reco)-[:ON_DATE]->(recoDate),
      (otherReco)-[:ON_DATE]->(otherRecoDate)
WHERE (reco)-[:NEXT]->(otherReco)
RETURN tech.name AS technology, otherRecoDate.value AS dateOfChange;
  
╒════════════╤══════════════╕
"technology""dateOfChange"
╞════════════╪══════════════╡
"Azure"     "Aug 2010"   
└────────────┴──────────────┘

Только лазурь ! На странице нет никакого объяснения первоначальной рекомендации «Удержание» в апреле 2010 года, которая была предположительно незадолго до того, как «облако» стало заметным. А как же наоборот? Существуют ли какие-либо технологии, в которых изначально предлагалось «оценить», а потом «провести»?

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
MATCH (pos1:Position {value:"Assess"})<-[:POSITION]-(reco)-[:TECHNOLOGY]->(tech),
      (pos2:Position {value:"Hold"})<-[:POSITION]-(otherReco)-[:TECHNOLOGY]->(tech),
      (reco)-[:ON_DATE]->(recoDate),
      (otherReco)-[:ON_DATE]->(otherRecoDate)
WHERE (reco)-[:NEXT]->(otherReco)
RETURN tech.name AS technology, otherRecoDate.value AS dateOfChange;
  
╒═══════════════════════════════════╤══════════════╕
"technology"                       "dateOfChange"
╞═══════════════════════════════════╪══════════════╡
"RIA"                              "Apr 2010"   
├───────────────────────────────────┼──────────────┤
"Backbone.js"                      "Oct 2012"   
├───────────────────────────────────┼──────────────┤
"Pace-layered Application Strategy""Nov 2015"   
├───────────────────────────────────┼──────────────┤
"SPDY"                             "May 2015"   
├───────────────────────────────────┼──────────────┤
"AngularJS"                        "Nov 2016"   
└───────────────────────────────────┴──────────────┘

Пара из них — библиотеки / фреймворки Javascript, поэтому, вероятно, сейчас советуют использовать React . Давай проверим:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
MATCH (t:Technology)<-[:TECHNOLOGY]-(reco)-[:ON_DATE]->(date), (reco)-[:POSITION]->(pos)
WHERE t.name contains "React.js"
RETURN pos.value, date.value
ORDER BY date.timestamp
  
╒═══════════╤════════════╕
"pos.value""date.value"
╞═══════════╪════════════╡
"Assess"   "Jan 2015" 
├───────────┼────────────┤
"Trial"    "May 2015" 
├───────────┼────────────┤
"Trial"    "Nov 2015" 
├───────────┼────────────┤
"Adopt"    "Apr 2016" 
├───────────┼────────────┤
"Adopt"    "Nov 2016" 
└───────────┴────────────┘

Ember также популярен:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
MATCH (t:Technology)<-[:TECHNOLOGY]-(reco)-[:ON_DATE]->(date), (reco)-[:POSITION]->(pos)
WHERE t.name contains "Ember"
RETURN pos.value, date.value
ORDER BY date.timestamp
  
╒═══════════╤════════════╕
"pos.value""date.value"
╞═══════════╪════════════╡
"Assess"   "May 2015" 
├───────────┼────────────┤
"Assess"   "Nov 2015" 
├───────────┼────────────┤
"Trial"    "Apr 2016" 
├───────────┼────────────┤
"Adopt"    "Nov 2016" 
└───────────┴────────────┘

Давайте пойдем по другому и посмотрим, сколько технологий было внедрено на самом последнем радаре?

1
2
3
4
5
6
7
8
9
MATCH (date:Date {value: "Nov 2016"})<-[:ON_DATE]-(reco)
WHERE NOT (reco)<-[:NEXT]-()
RETURN COUNT(*)
  
╒══════════╕
"COUNT(*)"
╞══════════╡
"45"     
└──────────┘

Вау, 45 новых вещей! Как они были распределены по разным позициям?

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
MATCH (date:Date {value: "Nov 2016"})<-[:ON_DATE]-(reco)-[:TECHNOLOGY]->(tech),
      (reco)-[:POSITION]->(position)
WHERE NOT (reco)<-[:NEXT]-()
WITH position, COUNT(*) AS count, COLLECT(tech.name) AS technologies
ORDER BY LENGTH((position)-[:NEXT*]->()) DESC
RETURN position.value, count, technologies
  
╒════════════════╤═══════╤══════════════════════════════════════════════╕
"position.value""count""technologies"                               
╞════════════════╪═══════╪══════════════════════════════════════════════╡
"Hold"          "1"    │["Anemic REST"]                               │
├────────────────┼───────┼──────────────────────────────────────────────┤
"Assess"        "28"   │["Nuance Mix","Micro frontends","Three.js","Sc│
│                │       │ikit-learn","WebRTC","ReSwift","Vue.js","Elect│
│                │       │ron","Container security scanning","wit.ai","D│
│                │       │ifferential privacy","Rapidoid","OpenVR","AWS │
│                │       │Application Load Balancer","Tarantool","IndiaS│
│                │       │tack","Ethereum","axios","Bottled Water","Cass│
│                │       │andra carefully","ECMAScript 2017","FBSnapshot│
│                │       │Testcase","Client-directed query","JuMP","Cloj│
│                │       │ure.spec","HoloLens","Android-x86","Physical W│
│                │       │eb"]                                          │
├────────────────┼───────┼──────────────────────────────────────────────┤
"Trial"         "13"   │["tmate","Lightweight Architecture Decision Re│
│                │       │cords","APIs as a product","JSONassert","Unity│
│                │       │ beyond gaming","Galen","Enzyme","Quick and Ni│
│                │       │mble","Talisman","fastlane","Auth0","Pa11y","P│
│                │       │hoenix"]                                      │
├────────────────┼───────┼──────────────────────────────────────────────┤
"Adopt"         "3"    │["Grafana","Babel","Pipelines as code"]       │
└────────────────┴───────┴──────────────────────────────────────────────┘

Много новых вещей, чтобы исследовать во время праздников! Файлы CSV, скрипт импорта и запросы, используемые в этом посте, доступны на github, если вы хотите поиграть с ними.