За последние пару недель я читал о развитии навыков и разбивке навыков на более управляемые куски, и недавно у меня была возможность разбить навыки, необходимые для обучения циклу.
Сначала я набросал схему развития навыка, но быстро понял, что нарисовал график зависимости, и подумал, что его включение в Neo4j упростит ситуацию.
Я начал с общей цели катания на велосипеде, которая заключалась в том, чтобы «иметь возможность ездить на велосипеде через общественный парк»:
1
|
MERGE (:Goal:Task {name: "Be able to cycle through a public park" }) |
Эта цель проста для тех, кто уже научился ездить на велосипеде, но если мы начинаем с нуля, это немного утомительно, поэтому нам нужно разбить ее на более простой навык, который мы можем практиковать.
Мини-алгоритм, который мы собираемся использовать для разбивки задач:
- Можем ли мы выполнить данную задачу сейчас?
- Разбейте задачу на что-то более простое и вернитесь к 1.
Одна из вещей, которую нужно иметь в виду, это то, что мы не получим идеальный разрыв в первый раз, поэтому нам, возможно, придется его изменить. Для диаграммы, нарисованной на листе бумаги, это будет раздражать, но в Neo4j это просто более простой рефакторинг.
Возвращаясь к велоспорту. Поскольку цель еще не достижима, нам нужно разбить ее на что-то более простое. Давайте начнем с чего-то действительно простого:
1
2
3
4
|
MERGE (task:Task {name: "Take a few steps forward while standing over the bike" }) WITH task MATCH (goal:Goal:Task {name: "Be able to cycle through a public park" }) MERGE (goal)-[:DEPENDS_ON]->(task) |
В первой строке мы создаем нашу новую задачу, а затем связываем ее с нашей целью, которую мы создали ранее.
После того, как мы научились ездить на велосипеде, мы хотим научиться ездить на велосипеде вперед на несколько оборотов, сидя на велосипеде, но для этого нам нужно иметь возможность начать движение велосипеда с места стоя. У нас также может быть еще один шаг, когда мы будем ездить на велосипеде вперед, стоя на велосипеде, поскольку это может быть немного проще.
Давайте обновим наш график:
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
|
// First let's get rid of the relationship between our initial task and the goal MATCH (initialTask:Task {name: "Take a few steps forward while standing over the bike" }) MATCH (goal:Goal {name: "Be able to cycle through a public park" }) MATCH (goal)-[rel:DEPENDS_ON]->(initialTask) DELETE rel WITH initialTask, goal, [ "Get bike moving from standing start" , "Cycle forward while standing" , "Cycle forward while sitting" ] AS newTasks // Create some nodes for our new tasks UNWIND newTasks AS newTask MERGE (t:Task {name: newTask}) WITH initialTask, goal, COLLECT(t) AS newTasks WITH initialTask, goal, newTasks, newTasks[ 0 ] AS firstTask, newTasks[- 1 ] AS lastTask // Connect the last task to the goal MERGE (goal)-[:DEPENDS_ON]->(lastTask) // And the first task to our initial task MERGE (firstTask)-[:DEPENDS_ON]->(initialTask) // And all the tasks to each other FOREACH(i in RANGE( 0 , length(newTasks) - 2 ) | FOREACH(t1 in [newTasks[i]] | FOREACH(t2 in [newTasks[i+ 1 ]] | MERGE (t2)-[:DEPENDS_ON]->(t1) ))) |
Строго говоря, нам не нужно учиться ездить на велосипеде, стоя — мы могли бы просто перейти от движения велосипеда к велосипеду вперед, сидя. Давайте обновим график, чтобы отразить это:
1
2
3
|
MATCH (sitting:Task {name: "Cycle forward while sitting" }) MATCH (moving:Task {name: "Get bike moving from standing start" }) MERGE (sitting)-[:DEPENDS_ON]->(moving) |
Как только мы разберемся с этими задачами, давайте добавим еще несколько, чтобы приблизить нас к нашей цели:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
WITH [ {skill: "Controlled stop using brakes/feet" , dependsOn: "Cycle forward while sitting" }, {skill: "Steer around stationary objects" , dependsOn: "Controlled stop using brakes/feet" }, {skill: "Steer around people" , dependsOn: "Steer around stationary objects" }, {skill: "Navigate a small circular circuit" , dependsOn: "Steer around stationary objects" }, {skill: "Navigate a loop of a section of the park" , dependsOn: "Navigate a small circular circuit" }, {skill: "Navigate a loop of a section of the park" , dependsOn: "Steer around people" }, {skill: "Be able to cycle through a public park" , dependsOn: "Navigate a loop of a section of the park" } ] AS newTasks FOREACH(newTask in newTasks | MERGE (t1:Task {name: newTask.skill}) MERGE (t2:Task {name: newTask.dependsOn}) MERGE (t1)-[:DEPENDS_ON]->(t2) ) |
Наконец, давайте избавимся от отношения с нашей целью «Цикл вперед, сидя», так как мы заменили это на несколько промежуточных шагов:
1
2
3
4
5
|
MATCH (task:Task {name: "Cycle forward while sitting" }) WITH task MATCH (goal:Goal:Task {name: "Be able to cycle through a public park" }) MERGE (goal)-[rel:DEPENDS_ON]->(task) DELETE rel |
И вот как выглядит окончательный граф зависимостей:
Хотя я поместил это в Neo4j, чтобы визуализировать зависимости, теперь мы можем также запрашивать данные. Например, скажем, я знаю, как ездить на велосипеде вперед, сидя на велосипеде. Какие шаги есть между мной и возможностью кататься на велосипеде вокруг парка?
1
2
3
4
|
MATCH (t:Task {name: "Cycle forward while sitting" }), (g:Goal {name: "Be able to cycle through a public park" }), path = shortestpath((g)-[:DEPENDS_ON*]->(t)) RETURN path |
Или, если мы хотим получить список задач, которые нам нужно выполнить, мы могли бы немного реструктурировать запрос:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
MATCH (t:Task {name: "Cycle forward while sitting" }), (g:Goal {name: "Be able to cycle through a public park" }), path = shortestpath((t)<-[:DEPENDS_ON*]->(g)) WITH [n in nodes(path) | n.name] AS tasks UNWIND tasks AS task RETURN task ==> +--------------------------------------------+ ==> | task | ==> +--------------------------------------------+ ==> | "Cycle forward while sitting" | ==> | "Controlled stop using brakes/feet" | ==> | "Steer around stationary objects" | ==> | "Steer around people" | ==> | "Navigate a loop of a section of the park" | ==> | "Be able to cycle through a public park" | ==> +--------------------------------------------+ ==> 6 rows |
Пока это все, но я думаю, что это интересный способ отследить, как вы изучаете навык. Я пытаюсь подобный подход для некоторых статистических тем, о которых я узнаю, но я обнаружил, что порядок задач там не такой линейный — интересно гораздо больше графика, чем дерева.
Ссылка: | Neo4j: обучение циклическому графу зависимостей от нашего партнера по JCG Марка Нидхэма в блоге Марка Нидхэма . |