Skip to content

Commit

Permalink
FIxes neo4j-contrib#331 - missing detailed documentation for some pro…
Browse files Browse the repository at this point in the history
…cedures
  • Loading branch information
DanielBerton committed May 5, 2017
1 parent 94d5bb1 commit d357d5d
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 304 deletions.
287 changes: 287 additions & 0 deletions docs/graph-refactor.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@

[cols="1m,5"]
|===
| call apoc.refactor.cloneNodes([node1,node2,...]) | clone nodes with their labels and properties
| call apoc.refactor.cloneNodesWithRelationships([node1,node2,...]) | clone nodes with their labels, properties and relationships
| call apoc.refactor.mergeNodes([node1,node2]) | merge nodes onto first in list
| call apoc.refactor.to(rel, endNode) | redirect relationship to use new end-node
| call apoc.refactor.from(rel, startNode) | redirect relationship to use new start-node
| call apoc.refactor.invert(rel) | inverts relationship direction
| call apoc.refactor.setType(rel, 'NEW-TYPE') | change relationship-type
| call apoc.refactor.extractNode([rel1,rel2,...], [labels], 'OUT','IN') | extract node from relationships
| call apoc.refactor.collapseNode([node1,node2],'TYPE') | collapse node to relationship, node with one rel becomes self-relationship
| call apoc.refactor.normalizeAsBoolean(entity, propertyKey, true_values, false_values) | normalize/convert a property to be boolean
| call apoc.refactor.categorize(node, propertyKey, type, outgoing, label) | turn each unique propertyKey into a category node and connect to it
|===

TODO:

* merge nodes by label + property
* merge relationships
=== Graph Refactoring Examples

.Clone nodes

We create a dataset
[source,cypher]
----
CREATE (f:Foo{name:'Foo'}),(b:Bar{name:'Bar'})
----

As result we have two nodes

image::{img}/apoc.refactor.cloneNodes.dataset.png[width=800]

[source,cypher]
----
MATCH (f:Foo{name:'Foo'}),(b:Bar{name:'Bar'}) WITH f,b
CALL apoc.refactor.cloneNodes([f,b]) yield input, output RETURN *
----

As result we have the two nodes that we have created before and their clones

image::{img}/apoc.refactor.cloneNodes.png[width=800]

.Clone nodes with relationship

We create a dataset of two different nodes of type `Actor` connected with other two different node of type `Movie`

[source,cypher]
----
CREATE (k:Actor {name:'Keanu Reeves'})-[:ACTED_IN {role:'Neo'}]->(m:Movie {title:'The Matrix'}),
(t:Actor {name:'Tom Hanks'})-[:ACTED_IN {role:'Forrest'}]->(f:Movie {title:'Forrest Gump'}) RETURN *
----

image::{img}/apoc.refactor.cloneNodesWithRelationships.dataset.png[width=800]

[source,cypher]
----
MATCH (k:Actor {name:'Keanu Reeves'}), (t:Actor {name:'Tom Hanks'})
CALL apoc.refactor.cloneNodesWithRelationships([k,t]) YIELD input, output RETURN *
----

As result we have a copy of the nodes and relationships

image::{img}/apoc.refactor.cloneNodesWithRelationships.png[width=800]

.Merge nodes

We create two nodes with different properties

[source,cypher]
----
CREATE (f:Person {name:'Foo'}), (b:Person {surname:'Bar'}) RETURN f,b
----

image::{img}/apoc.refactor.mergeNodes.dataset.png[width=800]

Now we want to merge these nodes into one

[source,cypher]
----
MATCH (f:Person {name:'Foo'}), (b:Person {surname:'Bar'})
CALL apoc.refactor.mergeNodes([f,b])
YIELD node RETURN node
----

image::{img}/apoc.refactor.mergeNodes.png[width=800]

Thus we have one node with both properties `name` and `surname`

.Redirect relationship to

We start with two nodes related each other with a relationship. We create a new node which we will use to redirect the relationship like end node

[source,cypher]
----
CREATE (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar)
CREATE (p:Person {name:'Antony'})
RETURN *
----

image::{img}/apoc.refactor.to.dataset.png[width=800]

[source,cypher]
----
MATCH (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar) with id(rel) as id
MATCH (p:Person {name:'Antony'}) with p as p
MATCH ()-[r]->(), (p:Person) CALL apoc.refactor.to(r, p) YIELD input, output RETURN *
----

image::{img}/apoc.refactor.to.png[width=800]

Now the relationship is towards the new node `Person`

.Redirect relationship from

We start with two nodes related each other with a relationship. We create a new node which we will use to redirect the relationship like start node

[source,cypher]
----
CREATE (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar)
CREATE (p:Person {name:'Antony'})
RETURN *
----

image::{img}/apoc.refactor.from.dataset.png[width=800]

[source,cypher]
----
MATCH (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar) with id(rel) as id
MATCH (p:Person {name:'Antony'}) with p as p
MATCH ()-[r]->(), (p:Person) CALL apoc.refactor.from(r, p) YIELD input, output RETURN *
----

image::{img}/apoc.refactor.from.png[width=800]

Now the relationship starts from the new node `Person` from the old node `Bar`

.Invert relationship

We start with two nodes connected by a relationship

[source,cypher]
----
CREATE (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar)
----

image::{img}/apoc.refactor.invert.dataset.png[width=800]

Now we want to invert the relationship direction

[source,cypher]
----
MATCH (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar) WITH id(rel) as id
MATCH ()-[r]->() WHERE id(r) = id
CALL apoc.refactor.invert(r) yield input, output RETURN *
----

image::{img}/apoc.refactor.invert.call.png[width=800]

image::{img}/apoc.refactor.invert.png[width=800]

.Set type

With a simple relationship between two node

[source,cypher]
----
CREATE (f:Foo)-[rel:FOOBAR]->(b:Bar)
----

image::{img}/apoc.refactor.setType.dataset.png[width=800]

We can change the relationship type from `FOOBAR` to `NEW-TYPE`

[source,cypher]
----
MATCH (f:Foo)-[rel:FOOBAR]->(b:Bar) with rel
CALL apoc.refactor.setType(rel, 'NEW-TYPE') YIELD input, output RETURN *
----

image::{img}/apoc.refactor.setType.png[width=800]

.Extract node from relationships

[source,cypher]
----
CREATE (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar)
----

image::{img}/apoc.refactor.extractNode.dataset.png[width=800]

We pass the ID of the relationship as parameter to extract a node

[source,cypher]
----
MATCH (f:Foo)-[rel:FOOBAR {a:1}]->(b:Bar) WITH id(rel) as id
CALL apoc.refactor.extractNode(id,['FooBar'],'FOO','BAR')
YIELD input, output RETURN *
----

image::{img}/apoc.refactor.extractNode.png[width=800]

.Collapse node to relationship

[source,cypher]
----
CREATE (f:Foo)-[:FOO {a:1}]->(b:Bar {c:3})-[:BAR {b:2}]->(f) WITH id(b) as id
CALL apoc.refactor.collapseNode(id,'FOOBAR')
YIELD input, output RETURN *
----

Before we have this situation

image::{img}/apoc.refactor.collapseNode.dataset.png[width=800]

And the result are

image::{img}/apoc.refactor.collapseNode.png[width=800]

The property of the two relationship and the property of the node are joined in one relationship that has the properties `a:1`, `b:2`, `name:Bar`

.Normalize As Boolean

[source,cypher]
----
CREATE (:Person {prop: 'Y', name:'A'}),(:Person {prop: 'Yes', name:'B'}),(:Person {prop: 'NO', name:'C'}),(:Person {prop: 'X', name:'D'})
----

As a resul we have four nodes with different properties `prop` like `Y`, `Yes`, `NO`, `X`

image::{img}/apoc.refactor.normalizeAsBoolean.dataset.png[width=800]

Now we want to transform some properties into a boolean, `Y`, `Yes` into true and the properties `NO` into false.
The other properties that don't match these possibilities will be set as `null`.

[source,cypher]
----
MATCH (n) CALL apoc.refactor.normalizeAsBoolean(n,'prop',['Y','Yes'],['NO']) WITH n ORDER BY n.id RETURN n.prop AS prop
----

image::{img}/apoc.refactor.normalizeAsBoolean.png[width=800]

.Categorize

First of all we create some nodes as dataset

[source,cypher]
----
CREATE (:Person {prop: 'A', k: 'a', id: 1}),
(:Person {prop: 'A', k: 'a', id: 2}),
(:Person {prop: 'C', k: 'c', id: 3}),
(:Person { id: 4}),
(:Person {prop: 'B', k: 'b', id: 5}),
(:Person {prop: 'C', k: 'c', id: 6})
----

As result we have six nodes with label 'Person' with different properties

image::{img}/apoc.refactor.categorize.dataset.png[width=800]

Now we want to transform the property `prop` into a separate node with label `Letter` and transfer the properties of the nodes `Person`: `prop` (now renamed in `name`) and `k`.
The nodes `Person` will keep only the propertie `id`, and will be connected with a relationship `IS_A` with the new nodes `Letter`.

[source,cypher]
----
CALL apoc.refactor.categorize('prop','IS_A',true,'Letter','name',['k'],1)
----

image::{img}/apoc.refactor.categorize.png[width=800]

The direction of the relationship (in this case outgoing) is defined by the third field, if `true` outgoing else incoming.
If a node doesn't has the property `prop` (like node with `id: 4`) it won't be managed.

=== Rename

Procedures set for renaming labels, relationship types, nodes and relationships' properties.
They return the list of eventually impacted constraints and indexes, the user should take care of.

[cols="1m,5"]
|===
| call apoc.refactor.rename.label(oldLabel, newLabel, [nodes]) | rename a label from 'oldLabel' to 'newLabel' for all nodes. If 'nodes' is provided renaming is applied to this set only
| call apoc.refactor.rename.type(oldType, newType, [rels]) | rename all relationships with type 'oldType' to 'newType'. If 'rels' is provided renaming is applied to this set only
| call apoc.refactor.rename.nodeProperty(oldName, newName, [nodes]) | rename all node's property from 'oldName' to 'newName'. If 'nodes' is provided renaming is applied to this set only
| call apoc.refactor.rename.typeProperty(oldName, newName, [rels]) | rename all relationship's property from 'oldName' to 'newName'. If 'rels' is provided renaming is applied to this set only
|===
Binary file added docs/img/apoc.graph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions docs/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,14 @@ $(document).ready(function() {
</script>
++++

== Virtual

include::virtual-graph.adoc[leveloffset=1]

== Graph Refactoring

include::graph-refactor.adoc[leveloffset=1]

== Appendix: Complete Overview

include::overview.adoc[tags=overview,leveloffset=1]
Loading

0 comments on commit d357d5d

Please sign in to comment.