Skip to content

Commit

Permalink
changed procedure signature
Browse files Browse the repository at this point in the history
  • Loading branch information
vga91 committed Apr 3, 2024
1 parent 04ddcb7 commit 901f25e
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 46 deletions.
2 changes: 2 additions & 0 deletions docs/asciidoc/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ include::partial$generated-documentation/nav.adoc[]
** xref::cypher-execution/cypher-based-procedures-functions.adoc[]
** xref::cypher-execution/parallel.adoc[]
* xref:virtual-nodes-and-relationships/index.adoc[]
* xref:virtual-resource/index.adoc[]
* xref:nlp/index.adoc[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,36 @@
label:function[] label:apoc-extended[]

[.emphasis]
apoc.graph.filterProperties(<anyEntityObject>, [propertiesToRemove]) - aggregation function which returns an object {node: [virtual nodes], relationships: [virtual relationships]} without the properties defined in propertiesToRemove
apoc.graph.filterProperties(anyEntityObject, nodePropertiesToRemove, relPropertiesToRemove) - aggregation function which returns an object {node: [virtual nodes], relationships: [virtual relationships]} without the properties defined in nodePropertiesToRemove and relPropertiesToRemove

== Signature

[source]
----
apoc.graph.filterProperties(value :: ANY?, type :: LIST OF STRING?) :: ANY
apoc.graph.filterProperties(value :: ANY?, nodePropertiesToRemove :: MAP?, relPropertiesToRemove :: MAP?) :: ANY?
----

== Input parameters
[.procedures, opts=header]
|===
| Name | Type | Default
|value|ANY|null
|predicate|STRING|null
|===
The `nodePropertiesToRemove` and `relPropertiesToRemove` parameter are maps
with key the label/relationship type and value the list of properties to remove from the virtual entities.
The key can also be `_all`, for both of them, which means that the properties of each label/rel-type are filtered.


== Usage Examples


Given the following dataset:
[source,cypher]
----
CREATE (:Person {name: "foo", plotEmbedding: "11"})-[:REL {idRel: 1, posterEmbedding: "33"}]->(:Movie {name: "bar", plotEmbedding: "22"}),
(:Person {name: "baz", plotEmbedding: "33"})-[:REL {idRel: 1, posterEmbedding: "66"}]->(:Movie {name: "ajeje", plotEmbedding: "44"})
----

we can execute:
we can execute:

[source,cypher]
----
MATCH path=(:Person)-[:REL]->(:Movie)
WITH apoc.graph.filterProperties(path, ['plotEmbedding', 'posterEmbedding', 'plot', 'bio']) as graph
WITH apoc.graph.filterProperties(path, {Movie: ['posterEmbedding'], Person: ['posterEmbedding', 'plotEmbedding', 'plot', 'bio']}) as graph
RETURN graph.nodes AS nodes, graph.relationships AS relationships
----

Expand All @@ -46,4 +44,16 @@ RETURN graph.nodes AS nodes, graph.relationships AS relationships
| [(:Person {name: "1"}), (:Movie {name: "bar"}), (:Movie {title: "1",tmdbId: "ajeje"}), (:Person {name: "baz"}), (:Person {name: "uno"}), (:Movie {name: "ajeje"}), (:Movie {title: "1",tmdbId: "due"}), (:Movie {title: "1",tmdbId: "ajeje"}), (:Person {name: "1"}), (:Movie {title: "1",tmdbId: "ajeje"}), (:Person {name: "foo"}), (:Person {name: "1"})] | [[:REL], [:REL {idRel: 1}], [:REL {idRel: 1}], [:REL], [:REL], [:REL]]│
|===

or:

[source,cypher]
----
MATCH path=(:Person)-[:REL]->(:Movie)
WITH apoc.graph.filterProperties(path, {_all: ['plotEmbedding', 'posterEmbedding', 'plot', 'bio']}) as graph
RETURN graph.nodes AS nodes, graph.relationships AS relationships
----

with the same result as above.



Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
////
This file is generated by DocsTest, so don't change it!
////

= apoc.virtual.graph
:description: This section contains reference documentation for the apoc.virtual.graph procedure.
= apoc.graph.filterProperties
:description: This section contains reference documentation for the apoc.graph.filterProperties procedure.

label:procedure[] label:apoc-extended[]

[.emphasis]
CALL apoc.virtual.graph(<anyEntityObject>, [propertiesToRemove]) YIELD nodes, relationships - returns a set of virtual nodes and relationships without the properties defined in propertiesToRemove
CALL apoc.graph.filterProperties(anyEntityObject, nodePropertiesToRemove, relPropertiesToRemove) YIELD nodes, relationships - returns a set of virtual nodes and relationships without the properties defined in nodePropertiesToRemove and relPropertiesToRemove

== Signature

[source]
----
apoc.dv.catalog.list(value :: ANY?, type :: LIST OF STRING?) :: (nodes :: LIST OF NODE?, relationships :: LIST OF RELATIONSHIP?)
apoc.graph.filterProperties(value :: ANY?, nodePropertiesToRemove = {} :: MAP? , relPropertiesToRemove = {} :: MAP?) :: ANY?
----

== Output parameters
Expand All @@ -25,6 +21,10 @@ apoc.dv.catalog.list(value :: ANY?, type :: LIST OF STRING?) :: (nodes :: LIST O
|relationships|LIST OF RELATIONSHIP?
|===

The `nodePropertiesToRemove` and `relPropertiesToRemove` parameter are maps
with key the label/relationship type and value the list of properties to remove from the virtual entities.
The key can also be `_all`, for both of them, which means that the properties of each label/rel-type are filtered.

== Usage examples

Given the following dataset:
Expand All @@ -40,7 +40,7 @@ we can execute:
----
MATCH path=(:Person)-[:REL]->(:Movie)
WITH collect(path) AS paths
CALL apoc.virtual.graph(paths, ['plotEmbedding', 'posterEmbedding', 'plot', 'bio'])
CALL apoc.graph.filterProperties(paths, {Movie: ['posterEmbedding'], Person: ['posterEmbedding', 'plotEmbedding', 'plot', 'bio']})
YIELD nodes, relationships
RETURN nodes, relationships
----
Expand All @@ -52,3 +52,14 @@ RETURN nodes, relationships
| [(:Person {name: "1"}), (:Movie {name: "bar"}), (:Movie {title: "1",tmdbId: "ajeje"}), (:Person {name: "baz"}), (:Person {name: "uno"}), (:Movie {name: "ajeje"}), (:Movie {title: "1",tmdbId: "due"}), (:Movie {title: "1",tmdbId: "ajeje"}), (:Person {name: "1"}), (:Movie {title: "1",tmdbId: "ajeje"}), (:Person {name: "foo"}), (:Person {name: "1"})] | [[:REL], [:REL {idRel: 1}], [:REL {idRel: 1}], [:REL], [:REL], [:REL]]│
|===

or:
[source,cypher]
----
MATCH path=(:Person)-[:REL]->(:Movie)
WITH collect(path) AS paths
CALL apoc.graph.filterProperties(paths, {_all: ['plotEmbedding', 'posterEmbedding', 'plot', 'bio']})
YIELD nodes, relationships
RETURN nodes, relationships
----

with the same result as above.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
[.procedures, opts=header, cols='5a,1a']
|===
| Qualified Name | Type
|xref::overview/apoc.graph/apoc.virtual.graph.adoc[apoc.virtual.graph icon:book[]]
|xref::overview/apoc.graph/apoc.graph.filterProperties.adoc[apoc.graph.filterProperties icon:book[]]

CALL apoc.virtual.graph(<anyEntityObject>, [propertiesToRemove]) YIELD nodes, relationships - returns a set of virtual nodes and relationships without the properties defined in propertiesToRemove
CALL apoc.graph.filterProperties(anyEntityObject, nodePropertiesToRemove, relPropertiesToRemove) YIELD nodes, relationships - returns a set of virtual nodes and relationships without the properties defined in nodePropertiesToRemove and relPropertiesToRemove
|label:procedure[]
|xref::overview/apoc.graph/apoc.graph.filterProperties.adoc[apoc.graph.filterProperties icon:book[]]
|xref::overview/apoc.graph/apoc.graph.filterPropertiesProcedure.adoc[apoc.graph.filterProperties icon:book[]]

apoc.graph.filterProperties(<anyEntityObject>, [propertiesToRemove]) - aggregation function which returns an object {node: [virtual nodes], relationships: [virtual relationships]} without the properties defined in propertiesToRemove
apoc.graph.filterProperties(anyEntityObject, nodePropertiesToRemove, relPropertiesToRemove) - aggregation function which returns an object {node: [virtual nodes], relationships: [virtual relationships]} without the properties defined in nodePropertiesToRemove and relPropertiesToRemove
|label:function[]
|===
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[[virtual-nodes-and-relationships]]
= Virtual Nodes and Relationships


This section includes:

* xref::overview/apoc.graph/apoc.graph.filterPropertiesProcedure.adoc[apoc.graph.filterProperties (procedure)]
* xref::overview/apoc.graph/apoc.graph.filterProperties.adoc[apoc.graph.filterProperties (aggregation function)]
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ This file is generated by DocsTest, so don't change it!
*** xref::overview/apoc.get/apoc.get.nodes.adoc[]
*** xref::overview/apoc.get/apoc.get.rels.adoc[]
** xref::overview/apoc.graph/index.adoc[]
*** xref::overview/apoc.get/apoc.virtual.graph.adoc[]
*** xref::overview/apoc.get/apoc.graph.filterProperties.adoc[]
*** xref::overview/apoc.graph/apoc.graph.filterProperties.adoc[]
*** xref::overview/apoc.graph/apoc.graph.filterPropertiesProcedure.adoc[]
** xref::overview/apoc.import/index.adoc[]
*** xref::overview/apoc.import/apoc.import.arrow.adoc[]
** xref::overview/apoc.load/index.adoc[]
Expand Down
46 changes: 34 additions & 12 deletions extended/src/main/java/apoc/graph/GraphsExtended.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import apoc.result.VirtualNode;
import apoc.result.VirtualRelationship;
import apoc.util.collection.Iterables;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.procedure.Description;
import org.neo4j.procedure.Name;
import org.neo4j.procedure.Procedure;
Expand All @@ -25,20 +27,23 @@
@Extended
public class GraphsExtended {

@Procedure("apoc.virtual.graph")
@Procedure("apoc.graph.filterProperties")
@Description(
"CALL apoc.virtual.graph(<anyEntityObject>, [propertiesToRemove]) YIELD nodes, relationships - returns a set of virtual nodes and relationships without the properties defined in propertiesToRemove")
"CALL apoc.graph.filterProperties(anyEntityObject, nodePropertiesToRemove, relPropertiesToRemove) YIELD nodes, relationships - returns a set of virtual nodes and relationships without the properties defined in nodePropertiesToRemove and relPropertiesToRemove")
public Stream<GraphResult> fromData(
@Name("value") Object value, @Name("propertiesToRemove") List<String> propertiesToRemove) {
VirtualGraphExtractor extractor = new VirtualGraphExtractor(propertiesToRemove);
@Name("value") Object value,
@Name(value = "nodePropertiesToRemove", defaultValue = "{}") Map<String, List<String>> nodePropertiesToRemove,
@Name(value = "relPropertiesToRemove", defaultValue = "{}") Map<String, List<String>> relPropertiesToRemove) {

VirtualGraphExtractor extractor = new VirtualGraphExtractor(nodePropertiesToRemove, relPropertiesToRemove);
extractor.extract(value);
GraphResult result = new GraphResult( extractor.nodes(), extractor.rels() );
return Stream.of(result);
}

@UserAggregationFunction("apoc.graph.filterProperties")
@Description(
"apoc.graph.filterProperties(<anyEntityObject>, [propertiesToRemove]) - aggregation function which returns an object {node: [virtual nodes], relationships: [virtual relationships]} without the properties defined in propertiesToRemove")
"apoc.graph.filterProperties(anyEntityObject, nodePropertiesToRemove, relPropertiesToRemove) - aggregation function which returns an object {node: [virtual nodes], relationships: [virtual relationships]} without the properties defined in nodePropertiesToRemove and relPropertiesToRemove")
public GraphFunction filterProperties() {
return new GraphFunction();
}
Expand All @@ -50,9 +55,13 @@ public static class GraphFunction {
private VirtualGraphExtractor virtualGraphExtractor;

@UserAggregationUpdate
public void filterProperties(@Name("value") Object value, @Name("propertiesToRemove") List<String> propertiesToRemove) {
public void filterProperties(
@Name("value") Object value,
@Name(value = "nodePropertiesToRemove", defaultValue = "{}") Map<String, List<String>> nodePropertiesToRemove,
@Name(value = "relPropertiesToRemove", defaultValue = "{}") Map<String, List<String>> relPropertiesToRemove) {

if (virtualGraphExtractor == null) {
virtualGraphExtractor = new VirtualGraphExtractor(propertiesToRemove);
virtualGraphExtractor = new VirtualGraphExtractor(nodePropertiesToRemove, relPropertiesToRemove);
}
virtualGraphExtractor.extract(value);
}
Expand All @@ -69,14 +78,18 @@ public Object result() {
}

public static class VirtualGraphExtractor {
private static final String ALL_FILTER = "_all";

private final Map<String, Node> nodes;
private final Map<String, Relationship> rels;
private final List<String> propertiesToRemove;
private final Map<String, List<String>> nodePropertiesToRemove;
private final Map<String, List<String>> relPropertiesToRemove;

public VirtualGraphExtractor(List<String> propertiesToRemove) {
public VirtualGraphExtractor(Map<String, List<String>> nodePropertiesToRemove, Map<String, List<String>> relPropertiesToRemove) {
this.nodes = new HashMap<>();
this.rels = new HashMap<>();
this.propertiesToRemove = propertiesToRemove;
this.nodePropertiesToRemove = nodePropertiesToRemove;
this.relPropertiesToRemove = relPropertiesToRemove;
}

public void extract(Object value) {
Expand Down Expand Up @@ -123,7 +136,11 @@ private void addVirtualNode(Node node) {

private Node createVirtualNode(Node startNode) {
List<String> props = Iterables.asList(startNode.getPropertyKeys());
props.removeAll(propertiesToRemove);
nodePropertiesToRemove.forEach((k,v) -> {
if (k.equals(ALL_FILTER) || startNode.hasLabel(Label.label(k))) {
props.removeAll(v);
}
});

return new VirtualNode(startNode, props);
}
Expand All @@ -136,7 +153,12 @@ private Relationship createVirtualRel(Relationship rel) {
endNode = nodes.putIfAbsent(endNode.getElementId(), createVirtualNode(endNode));

Map<String, Object> props = rel.getAllProperties();
propertiesToRemove.forEach(props.keySet()::remove);

relPropertiesToRemove.forEach((k,v) -> {
if (k.equals(ALL_FILTER) || rel.isType(RelationshipType.withName(k))) {
v.forEach(props.keySet()::remove);
}
});

return new VirtualRelationship(startNode, endNode, rel.getType(), props);
}
Expand Down
24 changes: 16 additions & 8 deletions extended/src/test/java/apoc/graph/GraphsExtendedTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ with collect(path) as paths

testCall(db, """
MATCH path=(:Person)-[:REL]->(:Movie)
WITH apoc.graph.filterProperties(path, ['plotEmbedding', 'posterEmbedding', 'plot', 'bio']) as graph
WITH apoc.graph.filterProperties(path, {_all: ['plotEmbedding', 'posterEmbedding', 'plot', 'bio']}) as graph
RETURN graph.nodes AS nodes, graph.relationships AS relationships""",
this::commonFilterPropertiesAssertions);

Expand Down Expand Up @@ -113,11 +113,19 @@ with collect(path) as paths
}

@Test
public void testVirtualGraph() {
public void testFilterPropertiesProcedure() {
testCall(db, """
MATCH path=(:Person)-[:REL]->(:Movie)
WITH collect(path) AS paths
CALL apoc.virtual.graph(paths, ['plotEmbedding', 'posterEmbedding', 'plot', 'bio'])
CALL apoc.graph.filterProperties(paths, {_all: ['plotEmbedding', 'posterEmbedding', 'plot', 'bio']})
YIELD nodes, relationships
RETURN nodes, relationships""",
this::commonFilterPropertiesAssertions);

testCall(db, """
MATCH path=(:Person)-[:REL]->(:Movie)
WITH collect(path) AS paths
CALL apoc.graph.filterProperties(paths, {Movie: ['posterEmbedding'], Person: ['posterEmbedding', 'plotEmbedding', 'plot', 'bio']})
YIELD nodes, relationships
RETURN nodes, relationships""",
this::commonFilterPropertiesAssertions);
Expand Down Expand Up @@ -161,14 +169,14 @@ public void filterPropertiesWithPathsWithMultipleRels() {
testCall(db, """
MATCH path=(:Foo)--(:Bar)--(:Baz)
WITH collect(path) AS paths
CALL apoc.virtual.graph(paths, ['remove'])
CALL apoc.graph.filterProperties(paths, {_all: ['remove']}, {_all: ['remove']})
YIELD nodes, relationships
RETURN nodes, relationships""",
r -> assertNodeAndRelIdProps(r, expectedIdNodes, expectedIdRels));

testCall(db, """
MATCH path=(:Foo)--(:Bar)--(:Baz)
WITH apoc.graph.filterProperties(path, ['remove']) as graph
WITH apoc.graph.filterProperties(path, {_all: ['remove']}, {_all: ['remove']}) as graph
RETURN graph.nodes AS nodes, graph.relationships AS relationships""",
r -> assertNodeAndRelIdProps(r, expectedIdNodes, expectedIdRels));
}
Expand All @@ -180,21 +188,21 @@ public void testWithCompositeDataTypes() {

testCall(db, """
MATCH p1=(:One)--(:Two), p2=(:Two)--(:Three)
CALL apoc.virtual.graph([p1, p2], ['remove'])
CALL apoc.graph.filterProperties([p1, p2], {_all: ['remove']}, {_all: ['remove']})
YIELD nodes, relationships
RETURN nodes, relationships""",
r -> assertNodeAndRelIdProps(r, expectedIdNodes, expectedIdRels));

testCall(db, """
MATCH p1=(:One)--(:Two), p2=(:Two)--(:Three)
CALL apoc.virtual.graph([{key1: p1, key2: [p1, p2]}], ['remove'])
CALL apoc.graph.filterProperties([{key1: p1, key2: [p1, p2]}], {_all: ['remove']}, {_all: ['remove']})
YIELD nodes, relationships
RETURN nodes, relationships""",
r -> assertNodeAndRelIdProps(r, expectedIdNodes, expectedIdRels));

testCall(db, """
MATCH p1=(:One)--(:Two), p2=(:Two)--(:Three)
CALL apoc.virtual.graph([{key2: {subKey: [p1, p2]}}], ['remove'])
CALL apoc.graph.filterProperties([{key2: {subKey: [p1, p2]}}], {_all: ['remove']}, {_all: ['remove']})
YIELD nodes, relationships
RETURN nodes, relationships""",
r -> assertNodeAndRelIdProps(r, expectedIdNodes, expectedIdRels));
Expand Down

0 comments on commit 901f25e

Please sign in to comment.