I use Neo4j 3.3.5 Community Edition
with APOC apoc-3.3.0.2-all.jar
I have triggers that allow me to add/remove all properties from a particular relationships to/from manual index:
CALL apoc.trigger.add('HAS_VALUE_ON_CREATED_RELATIONSHIPS_TRIGGER',
'UNWIND {createdRelationships} AS r
MATCH (d:Decision)-[r:HAS_VALUE_ON]->(ch:Characteristic)
CALL apoc.index.addRelationship(r, keys(r)) RETURN count(*)', {phase:'after'})
CALL apoc.trigger.add('HAS_VALUE_ON_DELETED_RELATIONSHIPS_TRIGGER',
\"UNWIND {deletedRelationships} AS r
MATCH (d:Decision)-[r:HAS_VALUE_ON]->(Characteristic)
CALL apoc.index.removeRelationshipByName('HAS_VALUE_ON', r) RETURN count(*)\", {phase:'after'})
My business logic can also introduce new properties or remove existing ones from the existing relationship so I think in order to keep my index up to date I should also use another two statements, like:
assignedRelationshipProperties
removedRelationshipProperties
am I right? If so, could you please show how both of them can be used in order to add new triggers and update/remove properties in index from MATCH (d:Decision)-[r:HAS_VALUE_ON]->(ch:Characteristic)
relationship ?
UPDATE #1
I have verified solution provided in the answer section but unfortunately it doesn't work. Please see details below:
I have created the following trigger:
CALL apoc.trigger.add('TEST_TRIGGER', "UNWIND keys({assignedRelationshipProperties}) AS key
UNWIND {assignedRelationshipProperties}[key] AS map
WITH map
WHERE type(map.relationship) = 'LIVES_IN'
CALL apoc.index.addRelationship(map.relationship, keys(map.relationship))
RETURN count(*)", {phase:'before'})
verified that trigger exists by CALL apoc.trigger.list()
create the following nodes and relationship:
CREATE (p:Person) return p
CREATE (c:City) return c
MATCH (p:Person), (c:City) CREATE (p)-[r:LIVES_IN]->(c) RETURN type(r)
tried to access it by index query:
MATCH (p:Person)-[r:LIVES_IN]->(c:City)
CALL apoc.index.in(c, 'LIVES_IN', 'time:10') YIELD node AS person
RETURN person
the quthe ery returns empty result which is fine for now.
assigned relationship new property time
with value = 10
:
MATCH (p:Person)-[r:LIVES_IN]->(c:City) SET r.time = 10 RETURN r
tried to access it by index query:
MATCH (p:Person)-[r:LIVES_IN]->(c:City)
CALL apoc.index.in(c, 'LIVES_IN', 'time:10') YIELD node AS person
RETURN person
the query successfully returns the expected Person
node
Now, I reassigned the time
property another value = 11
MATCH (p:Person)-[r:LIVES_IN]->(c:City) SET r.time = 11 RETURN r
tried to access it by index query one more time:
MATCH (p:Person)-[r:LIVES_IN]->(c:City)
CALL apoc.index.in(c, 'LIVES_IN', 'time:10') YIELD node AS person
RETURN person
MATCH (p:Person)-[r:LIVES_IN]->(c:City)
CALL apoc.index.in(c, 'LIVES_IN', 'time:11') YIELD node AS person
RETURN person
the query returns empty result for both of them..
Why was the index not updated after the property change?
UPDATE #2
I have created the following trigger:
CALL apoc.trigger.add('HAS_VALUE_ON_ASSIGNED_RELATIONSHIP_PROPERTIES_TRIGGER',
"UNWIND apoc.trigger.propertiesByKey({assignedRelationshipProperties}, 'time') AS prop WITH prop.relationship as r
CALL apoc.index.addRelationship(r, keys(r))
RETURN count(*)", {phase:'after'})
verified that trigger exists by CALL apoc.trigger.list()
create the following nodes and relationship:
CREATE (p:Person) return p
CREATE (c:City) return c
MATCH (p:Person), (c:City) CREATE (p)-[r:LIVES_IN]->(c) RETURN type(r)
tried to access it by index query:
MATCH (p:Person)-[r:LIVES_IN]->(c:City)
CALL apoc.index.in(c, 'LIVES_IN', 'time:10') YIELD node AS person
RETURN person
the query returns empty result which is fine for now.
assigned relationship new property time
with value = 10
:
MATCH (p:Person)-[r:LIVES_IN]->(c:City) SET r.time = 10 RETURN r
tried to access it by index query:
MATCH (p:Person)-[r:LIVES_IN]->(c:City)
CALL apoc.index.in(c, 'LIVES_IN', 'time:10') YIELD node AS person
RETURN person
the query successfully returns the expected Person
node
Now, I reassigned the time
property another value = 11
MATCH (p:Person)-[r:LIVES_IN]->(c:City) SET r.time = 11 RETURN r
tried to access it by index query one more time:
MATCH (p:Person)-[r:LIVES_IN]->(c:City)
CALL apoc.index.in(c, 'LIVES_IN', 'time:10') YIELD node AS person
RETURN person
MATCH (p:Person)-[r:LIVES_IN]->(c:City)
CALL apoc.index.in(c, 'LIVES_IN', 'time:11') YIELD node AS person
RETURN person
the query returns empty result for both of them..
So, this approach ran into the same issue as I previously described above. And the other drawback is that I need to specify the exact key name - in this case time
. But I'm not interested in some certain key but instead I'm interested in the add/update/delete of all keys of the HAS_VALUE_ON
relationship.
The assignedRelationshipProperties
is quite tricky. The structure of this parameter is Map<String, List<Map<String, Object>>>
.
Where, the first String
is the key of the property, and the list elements are maps with the following keys :
To be more visual, this is what the parameter look like in a debug format :
For your particular use case, updating the lucene index on relationship property updates for a particular relationship type, you can use the following query :
CALL apoc.trigger.add('test-rel-trigger',
'UNWIND keys({assignedRelationshipProperties}) AS key
UNWIND {assignedRelationshipProperties}[key] AS map
WITH map WHERE type(map.relationship) = "HAS_VALUE_ON"
CALL apoc.index.addRelationship(map.relationship, keys(map.relationship)) RETURN count(*)'
, {phase:'before'})
As for removal, because you index the full map of properties, I believe you can just replace assignedRelationshipProperties
with removedRelationshipProperties