refactor
The refactor
module provides utilities for changing nodes and relationships.
Trait | Value |
---|---|
Module type | algorithm |
Implementation | C++ |
Parallelism | sequential |
Procedures
You can execute this algorithm on graph projections, subgraphs or portions of the graph.
from(relationship, new_from)
Redirect the relationship to use a new start (from) node.
Input:
relationship: Relationship
➡ the relationship to be modified.new_from: Node
➡ new start (from) node.
Output:
relationship
- the modified relationship.
Usage:
MERGE (ivan:Person {name: "Ivan"}) MERGE (matija:Person {name: "Matija"}) MERGE (diora:Person {name:"Idora"}) CREATE (ivan)-[:Friends]->(matija);
The following query changes the the relationship Ivan ➡ Matija
to Idora ➡ Matija
.
MATCH (:Person {name: "Ivan"})-[rel:Friends]->(:Person {name: "Matija"}) MATCH (idora: Person {name:"Idora"}) CALL refactor.from(rel, idora) YIELD relationship RETURN relationship;
to(relationship, new_to)
Redirect the relationship to use a new end (to) node.
Input:
relationship: Relationship
➡ the relationship to be modified.new_to: Node
➡ new end (to) node.
Output:
relationship
- the modified relationship.
Usage:
MERGE (ivan:Person {name: "Ivan"}) MERGE (matija:Person {name: "Matija"}) MERGE (diora:Person {name:"Idora"}) CREATE (ivan)-[:Friends]->(matija);
The following query changes the the relationship Ivan ➡ Matija
to Ivan ➡ Idora
.
MATCH (:Person {name: "Ivan"})-[rel:Friends]->(:Person {name: "Matija"}) MATCH (idora: Person {name:"Idora"}) CALL refactor.to(rel, idora) YIELD relationship RETURN relationship;
rename_label(old_label, new_label, nodes)
Rename a label from old_label
to new_label
for all nodes. If nodes
is provided renaming is applied only to the given nodes. If a node doesn't contain the old_label
the procedure doesn't modify it.
Input:
old_label: str
➡ old label name.new_label: str
➡ new label name.nodes: List[Node]
➡ list of nodes to be modified.
Output:
nodes_changed: int
➡ number of modified nodes.
Usage:
CREATE (:Node1 {title: "Node1"}) CREATE (:Node2 {title: "Node2"}) CREATE (:Node1);
The following query changes the label of the first node to Node
MATCH(n) WITH collect(n) AS nodes CALL refactor.rename_label("Node1", "Node3", nodes) YIELD nodes_changed RETURN nodes_changed;
+----------------------------+
| nodes_changed |
+----------------------------+
| 2 |
+----------------------------+
rename_node_property(old_property, new_property, nodes)
Rename a property from old_property
to new_property
for all nodes. If nodes
is provided renaming is applied only to the given nodes. If a node doesn't contain the old_property
the procedure doesn't modify it.
Input:
old_property: str
➡ old property name.new_label: str
➡ new property name.nodes: List[Node]
➡ list of nodes to be modified.
Output:
nodes_changed: int
➡ number of modified nodes.
Usage:
CREATE (:Node1 {title: "Node1"}) CREATE (:Node2 {description: "Node2"}) CREATE (:Node3) CREATE (:Node4 {title: "title", description: "description"});
The following query will modify Node1
and Node4
.
MATCH(n) WITH collect(n) AS nodes CALL refactor.rename_node_property("title", "description", nodes) YIELD nodes_changed RETURN nodes_changed;
+----------------------------+
| nodes_changed |
+----------------------------+
| 2 |
+----------------------------+
categorize(original_prop_key, rel_type, is_outgoing, new_label, new_prop_name_key, copy_props_list)
Generates a new category of nodes based on a specific property key from the existing nodes in the graph. Then, it creates relationships between the original and new category nodes to organize a graph based on these categories.
Input:
original_prop_key: string
➡ the property key on the existing nodes used to determine the category.rel_type: string
➡ the type of relationship to be created between the original nodes and the new category nodes.is_outgoing: bool
➡ determines the direction of the new relationships. If 'true', relationships will be created from the original node to the category node. If 'false', they'll be created from the category node to the original node.new_label: string
➡ the label to be assigned to the new category nodes.new_prop_name_key: string
➡ the key for the new category node's property whose value will be the same asoriginal_prop_key
value.copy_props_list: List[string] (default = [])
➡ an array of property keys from the original nodes to be copied to the new category nodes.
Output:
status: string
➡ "success" if no errors were generated.
Usage:
CALL refactor.categorize('genre', 'GENRE', false, "Genre", "name") YIELD status RETURN status;
+----------------------------+
| status |
+----------------------------+
| success |
+----------------------------+
Example:
You can create a simple graph database by running the following queries:
CREATE (a:Movie {id: 0, name: "MovieName", genre: "Drama"})
CREATE (b:Book {id: 1, name: "BookName1", genre: "Drama", propertyToCopy: "copy me"})
CREATE (c:Book {id: 2, name: "BookName2", genre: "Romance"});
The image below shows the above data as a graph:
CALL refactor.categorize('genre', 'GENRE', true, "Genre", "name", ["propertyToCopy"])
YIELD status RETURN status;
The results should be identical to the ones in the graph below, except for the
id
values, which depend on the internal database id
values:
clone_nodes(nodes, clone_rels, skip_props)
Clones specific nodes in the graph, preserving their original labels, properties and optionally relationships. Offers the flexibility to exclude specific node properties during the cloning process.
Input:
nodes: List[Node]
➡ a list of nodes intended for duplication.clone_rels: bool (default = false)
➡ if set to true, the function will also clone the relationships of the original nodes, connecting them to the cloned nodes in the same manner.skip_props: List[string] (default = [])
➡ a list of property keys, properties associated with these keys will be skipped during the cloning process.
Output:
cloned_node_id: int
➡ ID of the original node which was cloned.new_node: Node
➡ new cloned node.
Usage:
MATCH (a:Person {name: "Ana", age: 22, id:0})
CALL refactor.clone_nodes([a], False, ["age", "id"])
YIELD cloned_node_id, new_node RETURN cloned_node_id, new_node;
+----------------------------+----------------------------+
| cloned_node_id | new_node |
+----------------------------+----------------------------+
| 0 | { |
| | "id": 1, |
| | "labels": [ |
| | "Person" |
| | ], |
| | "properties": { |
| | name: "Ana" |
| | }, |
| | "type": "node" |
| | } |
+----------------------------+----------------------------+
Example:
You can create a simple graph database by running the following queries:
CREATE (a:Ana {name: "Ana", age: 22})
CREATE (b:Marija {name: "Marija", age: 20})
CREATE (a)-[r:KNOWS]->(b);
The image below shows the above data as a graph:
MATCH (a:Ana) MATCH (b:Marija)
CALL refactor.clone_nodes([a, b], True, ["age"]) YIELD * RETURN *;
The results should be identical to the ones in the graph below, except for the
id
values, which depend on the internal database id
values:
clone_subgraph(nodes, rels, config)
Clones the subgraph by cloning the given list of nodes and relationships. If no relationships are provided, all existing relationships between the given nodes will be cloned.
Input:
nodes: List[Node]
➡ a list of nodes which form the subgraph intended for duplication.rels: List[Relationship] (default = [])
➡ a list of relationships intended for duplication. If this list is empty or not provided, all existing relationships between the given nodes will be cloned.config: Map (default = {})
➡ configuration parameters explained below.
Parameters:
Name | Type | Default | Description |
---|---|---|---|
skipProperties | List | [ ] | A list of property keys. Properties associated with these keys will be skipped during the cloning process. Therefore, new nodes will not have them. |
standinNodes | List | [ ] | A list of pairs (lists with only two elements) where: 1) The first element is the original node (from the input nodes list) that you're planning to clone. 2) The second element is an existing node in the graph that will "stand in" or replace the clone of the original node in the resultant subgraph. |
Output:
cloned_node_id: int
➡ ID of the original node which was cloned.new_node: Node
➡ new cloned node.
Usage:
MATCH (ana:Ana {id: 0}), (marija:Marija {id: 1})
MATCH (ana)-[r1:KNOWS]->(marija)
CALL refactor.clone_subgraph([ana, marija], [r1], {standinNodes: [[ana, marija]]})
YIELD cloned_node_id, new_node RETURN cloned_node_id, new_node;
+----------------------------+----------------------------+
| cloned_node_id | new_node |
+----------------------------+----------------------------+
| 1 | { |
| | "id": 2, |
| | "labels": [ | -> node :Ana was not cloned
| | "Marija" | because :Marija is its
| | ], | "stand-in" node
| | "properties": {}, |
| | "type": "node" |
| | } |
+----------------------------+----------------------------+
Example:
You can create a simple graph database by running the following queries:
MERGE (ana:Ana{name:'Ana'})
MERGE (marija:Marija{name:'Marija'})
MERGE (p2:Person{name:'person2'})
MERGE (p3:Person{name:'person3'})
MERGE (p4:Person{name:'person4'})
MERGE (p5:Person{name:'person5'})
MERGE (p6:Person{name:'person6'})
CREATE (ana)-[:KNOWS]->(p2)-[:KNOWS]->(p3)-[:KNOWS]->(p4)
CREATE (p4)<-[:KNOWS]-(p5)
CREATE (marija)-[:KNOWS]->(p6);
The image below shows the above data as a graph:
MATCH (ana:Ana),
(p2:Person{name: "person2"}),
(p3:Person{name: "person3"}),
(p4:Person{name: "person4"}),
(p5:Person{name: "person5"})
CALL refactor.clone_subgraph([ana, p2, p3, p4, p5], [], {
standinNodes:[[ana, marija]]
})
YIELD * RETURN *;
The results should be identical to the ones in the graph below, except for the
id
values, which depend on the internal database id
values. Note that the
whole subgraph was cloned except for node :Ana
because node :Marija
was
used as its "stand-in" node.
clone_subgraph_from_paths(paths, config)
Clones the subgraph specified by a specific list of paths. A path is a series of nodes connected by relationships.
Input:
paths: List[Path]
➡ a list of paths which define the subgraph intended for duplication.config: Map (default = {})
➡ configuration parameters explained below.
Parameters:
Name | Type | Default | Description |
---|---|---|---|
skipProperties | List | [ ] | A list of property keys. Properties associated with these keys will be skipped during the cloning process. Therefore, new nodes will not have them. |
standinNodes | List | [ ] | A list of pairs (lists with only two elements) where the first element is the original node (from the input nodes list) that you're planning to clone, and the second element is an existing node in the graph that will "stand-in" or replace the clone of the original node in the resultant subgraph. |
Output:
cloned_node_id: int
➡ ID of the original node which was cloned.new_node: Node
➡ new cloned node.
Usage:
MATCH (ana:Ana {id: 0}), (marija:Marija {id: 1})
MATCH path = (ana)-[:KNOWS*]->(marija)
CALL refactor.clone_subgraph_from_paths([path], {standinNodes:[[ana, marija]]})
YIELD cloned_node_id, new_node RETURN cloned_node_id, new_node;
+----------------------------+----------------------------+
| cloned_node_id | new_node |
+----------------------------+----------------------------+
| 1 | { |
| | "id": 2, |
| | "labels": [ | -> node :Ana was not cloned
| | "Marija" | because :Marija is its
| | ], | "stand-in" node
| | "properties": {}, |
| | "type": "node" |
| | } |
+----------------------------+----------------------------+
Example:
You can create a simple graph database by running the following queries:
MERGE (ana:Ana{name:'Ana'})
MERGE (marija:Marija{name:'Marija'})
MERGE (p2:Person{name:'person2'})
MERGE (p3:Person{name:'person3'})
MERGE (p4:Person{name:'person4'})
MERGE (p5:Person{name:'person5'})
MERGE (p6:Person{name:'person6'})
CREATE (ana)-[:KNOWS]->(p2)-[:KNOWS]->(p3)-[:KNOWS]->(p4)
CREATE (p4)<-[:KNOWS]-(p5) CREATE (p5)-[:LOVES]->(p6)
CREATE (marija)-[:KNOWS]->(p6);
The image below shows the above data as a graph:
MATCH (ana:Ana),
(marija:Marija)
MATCH path = (ana)-[:KNOWS*]->(node)
WITH ana, marija, collect(path) as paths
CALL refactor.clone_subgraph_from_paths(paths, {
standinNodes:[[ana, marija]]
})
YIELD cloned_node_id, new_node
RETURN cloned_node_id, new_node;
The results should be identical to the ones in the graph below, except for the
id
values, which depend on the internal database id
values. Note that the
whole subgraph was cloned except for the node :Ana
because node :Marija
was
used as its "stand-in" node.
collapse_node(nodes, type)
Collapses a node into a relationship. Can only collapse nodes with exactly 1 in relationship, and exactly 1 out relationship. The node must not have any self relationships. Collapsing any node that doesn't satisfy these requirements results in an exception.
Input:
nodes: Any
➡ a node, node ID, or list of nodes and node IDs.type: string
➡ the type of the new relationship.
Output:
id_collapsed: integer
➡ ID of the collapsed node.new_relationship: integer
➡ newly created relationship.
Usage:
Create the following graph:
CREATE (c:Car)-[t:DRIVES_ON]->(r:Road)-[l:LEADS_TO]->(ci:City);
Run the refactor.collapse_node()
procedure:
MATCH (r:Road)
CALL refactor.collapse_node(r, "DRIVES_TO") YIELD id_collapsed, new_relationship RETURN id_collapsed, new_relationship;
+-------------------------------------------------------------------------------------------------------------------+
| id_collapsed | new_relationship |
+-------------------------------------------------------------------------------------------------------------------+
| 1 | {"id": 2,"start": 0,"end": 2,"label": "DRIVES_TO","properties": {},"type": "relationship"} |
+-------------------------------------------------------------------------------------------------------------------+
invert(relationship)
Invert the direction of the given relationship.
Input:
relationship: Any
➡ relationship, relationship ID, or a list of relationships or relationship IDs.
Output:
id_inverted: integer
➡ ID of the inverted relationship.relationship
➡ the inverted relationship.
Usage:
Create the following graph:
CREATE (d:Dog)-[l:LOVES]->(h:Human);
Run the refactor.invert()
procedure:
MATCH (d:Dog)-[l:LOVES]->(h:Human)
CALL refactor.invert(l) YIELD id_inverted, relationship RETURN id_inverted, relationship;
+-------------------------------------------------------------------------------------------------------------------+
| id_inverted | relationship |
+-------------------------------------------------------------------------------------------------------------------+
| 0 | {"id": 0,"start": 1,"end": 0,"label": "LOVES","properties": {},"type": "relationship"} |
+-------------------------------------------------------------------------------------------------------------------+