Как включить пакет в запрос? - PullRequest
3 голосов
/ 19 июня 2019

Этот вопрос является продолжением Как определить все классы, реализующие определенный интерфейс, которые НЕ расширяют некоторый базовый класс? .

Принятый там ответ предлагает использовать:

MATCH 
   (i:Interface {name:'Action'}  )<-[:IMPLEMENTS|EXTENDS*1..10]- (class), 
   (abstractAction:Class {name:'AbstractAction'}) 
   where not (class)-->(abstractAction)   
RETURN class

Это прекрасно работает и дает список классов, соответствующих этому условию.

Единственная проблема, которая у меня есть: имя этого интерфейса Action (неожиданно) неоднозначно.Абсолютное имя класса com.whatever.foo.bar.Action будет.Но когда я изменяю запрос на использование {name:'com.whatever.foo.bar.Action'}, я получаю пустой результат.

Затем я попытался {package:'com.whatever.foo.bar' name:'Action'}, но это не сработало:

Одно из имен свойств в вашем запросе недоступно в базе данных, убедитесь, что вы этого не сделалинеправильно или что ярлык доступен, когда вы запускаете этот оператор в своем приложении (отсутствует имя свойства: package )

Есть ли способ уменьшить результат поиска до что интерфейс действий, который меня действительно волнует?

Ответы [ 3 ]

3 голосов
/ 19 июня 2019

Существует свойство узла fqn - полное имя.

Таким образом, правильный запрос будет:

MATCH 
   (i:Interface {fqn:'com.whatever.foo.bar.Action'}  )<-[:IMPLEMENTS|EXTENDS*1..10]- (class), 
   (abstractAction:Class {fqn:'com.whatever.foo.bar.AbstractAction'}) 
   where not (class)-->(abstractAction)   
RETURN class

Этот запрос создает декартово произведение, что означает, что он не очень производительный.

На следующем рисунке показан план выполнения этого запроса для одного из моих проектов: enter image description here

Этот вопрос более подробно рассматривает эту проблему: Почему neo4j предупреждает: «Этот запрос строит декартово произведение между несвязанными образцами»?

Поскольку этот запрос предназначен только для целей анализа и не выполняется в производственной системе, я бы проигнорировал эту подсказку.

2 голосов
/ 19 июня 2019

Предполагая, что вы хотите найти все классы, реализующие com.whatever.foo.bar.Action, которые не расширяются com.whatever.foo.bar.AbstractAction, ваш запрос должен выглядеть следующим образом:

MATCH 
  (class:Type:Class)-[:EXTENDS|IMPLEMENTS*]->(:Type:Interface{fqn:"com.whatever.foo.bar.Action"})
WHERE NOT
  (class)-[:EXTENDS*]->(:Type:Class{fqn:"com.whatever.foo.bar.AbstractAction"})
RETURN
  class

(ИМХО это довольно самовыразительно)

Два совета:

  • Поиск типов Java всегда должен выполняться с использованием индексированного свойства fqn метки Type, которое принимает полное имя класса
  • Вы должны всегда квалифицировать отношения, т. Е. Вместо (class)-->(abstractAction) использовать (class)-[:EXTENDS*]->(abstractAction), поскольку помимо EXTENDS или IMPLEMENTS может быть много исходящих отношений узла класса (например, DEPENDS_ON, ANNOTATED_BY), которые все будут проходить по запросу
1 голос
/ 19 июня 2019

При более внимательном рассмотрении графика результатов «рабочего» запроса был выявлен простой ответ, поскольку можно просто использовать свойство fileName:

MATCH 
 (i:Interface {name:"Action", fileName:"/com/whatever/foo/bar/Action.class"}  )<-[:IMPLEMENTS]- (c) 
RETURN c
...