Neo4j APOC назначилRelationshipProperties, триггеры удаленыRelationshipProperties и apoc.index.in

Я использую Neo4j 3.3.5 Community Edition с APOC apoc-3.3.0.2-all.jar

У меня есть триггеры, которые позволяют мне добавлять / удалять все свойства из определенных отношений в / из ручного индекса:

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'})

Моя бизнес-логика также может вводить новые свойства или удалять существующие из существующих отношений, поэтому я думаю, что для поддержания моего индекса в актуальном состоянии мне также следует использовать еще два оператора, например:

assignedRelationshipProperties
removedRelationshipProperties

я прав? Если да, не могли бы вы показать, как они оба могут использоваться для добавления новых триггеров и обновления / удаления свойств в индексе из отношения MATCH (d:Decision)-[r:HAS_VALUE_ON]->(ch:Characteristic)?

ОБНОВЛЕНИЕ №1

Я проверил решение, указанное в разделе ответов, но, к сожалению, оно не работает. См. Подробности ниже:

Я создал следующий триггер:

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'})

подтвердил, что триггер существует CALL apoc.trigger.list()

создать следующие узлы и отношения:

CREATE (p:Person) return p
CREATE (c:City) return c

MATCH (p:Person), (c:City) CREATE (p)-[r:LIVES_IN]->(c) RETURN type(r)

попытался получить к нему доступ по запросу индекса:

MATCH (p:Person)-[r:LIVES_IN]->(c:City) 
CALL apoc.index.in(c, 'LIVES_IN', 'time:10') YIELD node AS person 
RETURN person

quthery возвращает пустой результат, что пока нормально.

назначенное отношение новое свойство time со значением = 10:

MATCH (p:Person)-[r:LIVES_IN]->(c:City) SET r.time = 10 RETURN r

попытался получить к нему доступ по запросу индекса:

MATCH (p:Person)-[r:LIVES_IN]->(c:City) 
CALL apoc.index.in(c, 'LIVES_IN', 'time:10') YIELD node AS person 
RETURN person

запрос успешно возвращает ожидаемый Person узел

Теперь я переназначил свойству time другое значение = 11

MATCH (p:Person)-[r:LIVES_IN]->(c:City) SET r.time = 11 RETURN r

еще раз попытался получить к нему доступ с помощью индексного запроса:

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

запрос возвращает пустой результат для них обоих ..

Почему индекс не обновлялся после изменения свойства?

ОБНОВЛЕНИЕ №2

Я создал следующий триггер:

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'})

подтвердил, что триггер существует на CALL apoc.trigger.list()

создать следующие узлы и отношения:

CREATE (p:Person) return p
CREATE (c:City) return c

MATCH (p:Person), (c:City) CREATE (p)-[r:LIVES_IN]->(c) RETURN type(r)

попытался получить к нему доступ по запросу индекса:

MATCH (p:Person)-[r:LIVES_IN]->(c:City)
CALL apoc.index.in(c, 'LIVES_IN', 'time:10') YIELD node AS person 
RETURN person

запрос возвращает пустой результат, что пока нормально.

назначенное отношение новое свойство time со значением = 10:

MATCH (p:Person)-[r:LIVES_IN]->(c:City) SET r.time = 10 RETURN r

попытался получить к нему доступ по запросу индекса:

MATCH (p:Person)-[r:LIVES_IN]->(c:City) 
CALL apoc.index.in(c, 'LIVES_IN', 'time:10') YIELD node AS person 
RETURN person

запрос успешно возвращает ожидаемый Person узел

Теперь я переназначил свойству time другое значение = 11

MATCH (p:Person)-[r:LIVES_IN]->(c:City) SET r.time = 11 RETURN r

еще раз попытался получить к нему доступ с помощью индексного запроса:

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

запрос возвращает пустой результат для них обоих ..

Таким образом, этот подход столкнулся с той же проблемой, что я описал выше. Другой недостаток в том, что мне нужно указать точное имя ключа - в данном случае time. Но меня не интересует какой-то определенный ключ, а вместо этого меня интересуют добавление / обновление / удаление всех ключей отношения HAS_VALUE_ON.


person alexanoid    schedule 09.05.2018    source источник
comment
похоже, это связано с обновлением и запросом index.in, а не с триггерами. как работает индекс регулярных отношений.   -  person Michael Hunger    schedule 14.05.2018
comment
@MichaelHunger Спасибо! Есть ли шанс заставить его работать?   -  person alexanoid    schedule 14.05.2018


Ответы (2)


assignedRelationshipProperties довольно хитрый. Структура этого параметра - Map<String, List<Map<String, Object>>>.

Где первый String - это ключ свойства, а элементы списка - это карты со следующими ключами:

  • ключ: ключ собственности
  • old: старое значение, если оно есть
  • new: новое значение, присвоенное свойству
  • отношения: рассматриваемые отношения

Для большей наглядности вот как выглядит параметр в отладочном формате:

введите описание изображения здесь

Для вашего конкретного случая использования, обновления индекса lucene при обновлении свойств отношения для определенного типа отношения, вы можете использовать следующий запрос:

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'})

Что касается удаления, поскольку вы индексируете полную карту свойств, я считаю, что вы можете просто заменить assignedRelationshipProperties на removedRelationshipProperties

person Christophe Willemsen    schedule 10.05.2018
comment
Спасибо за Ваш ответ. Я проверил это решение, но, к сожалению, оно не работает - person alexanoid; 12.05.2018
comment
@MichaelHunger извините, я забыл упомянуть, что я предоставил подробное объяснение этого (что не работает с этим подходом) в моем обновленном вопросе - разделе ОБНОВЛЕНИЕ # 1 - person alexanoid; 14.05.2018
comment
Похоже, эта проблема была исправлена ​​в Neo4j 3.4.0 / apoc-3.4.0.1-all.jar - person alexanoid; 19.05.2018

Для их использования существуют специальные вспомогательные функции, которые описаны в документации для доступа к узлам / отношениям или свойствам этих структур данных:

см. https://neo4j-contrib.github.io/neo4j-apoc-procedures/#_triggers

Таблица 4. Вспомогательные функции

apoc.trigger.nodesByLabel({assignedLabels/assignedNodeProperties},'Label')

функция для фильтрации labelEntries по метке, которая будет использоваться в операторе триггера с {assignedLabels} и {removedLabels} {phase:'before/after/rollback'} возвращает информацию о предыдущем и новом триггере

apoc.trigger.propertiesByKey({assignedNodeProperties},'key')

функция для фильтрации PropertyEntries по ключу свойства, которая будет использоваться в операторе триггера с {assignedNode/RelationshipProperties} и {removedNode/RelationshipProperties}.

Возвращает [{old,[new],key,node,relationship}]

person Michael Hunger    schedule 12.05.2018
comment
Спасибо за Ваш ответ. См. Мой обновленный вопрос (ОБНОВЛЕНИЕ №2). При таком подходе я также столкнулся с той же проблемой, что описал ранее. Другой недостаток в том, что мне нужно указать точное имя ключа - в данном случае time. Но меня не интересует какой-то определенный ключ, а вместо этого меня интересуют добавление / обновление / удаление всех ключей отношения HAS_VALUE_ON. Что я делаю не так и как исправить? - person alexanoid; 13.05.2018
comment
Кстати. Я думаю, было бы неплохо также разрешить функции фильтровать метки / типы rel, возможно, вы хотите создать проблему GH для apoc на этом - person Michael Hunger; 14.05.2018
comment
Спасибо, я уже создал проблему с GH github.com/neo4j-contrib/ neo4j-apoc -cesses / issues / 805 - person alexanoid; 14.05.2018
comment
Еще одна проблема с GH для Neo4j: github.com/neo4j/neo4j/issues/11789 - person alexanoid; 16.05.2018