How to include package into query?

丶灬走出姿态 提交于 2020-01-04 04:16:08

问题


This question is a continuation of How to identify all classes implementing a specific interface that do NOT extend some base class?.

The accepted answer there suggests to use:

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

That works nicely, and gives a list of classes matching that condition.

The only problem I have: the name of that interface Action is (surprise) ambiguous. The absolute class name com.whatever.foo.bar.Action would be. But when I change the query to use {name:'com.whatever.foo.bar.Action'} I get an empty result.

I then tried {package:'com.whatever.foo.bar' name:'Action'}, but that doesn't work:

One of the property names in your query is not available in the database, make sure you didn't misspell it or that the label is available when you run this statement in your application (the missing property name is: package)

Is there a way reduce the search result to that Action interface I really care about?


回答1:


There is a fqn node property - full qualified name.

So the correct query would be:

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

This query produces a cartesian produckt which means that it's not very performant.

The following image shows the execution plan of that query for one of my projects:

This questions deals with that problem in more detail: Why does neo4j warn: "This query builds a cartesian product between disconnected patterns"?

Since this query is just for analysis purposes and not executed against a production system, I would ignore that hint.




回答2:


Assuming that you want to find all classes implementing com.whatever.foo.bar.Action which do not extend com.whatever.foo.bar.AbstractAction your query should look like this:

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

(IMHO this is quite self-expressive)

Two hints:

  • Looking up Java types should always be done using the indexed fqn property of the Type label which takes the fully qualified class name
  • You should always qualify the relationships, i.e. instead of (class)-->(abstractAction) use (class)-[:EXTENDS*]->(abstractAction) as beside EXTENDS or IMPLEMENTS there might be many outgoing relationships of a class node (e.g. DEPENDS_ON, ANNOTATED_BY) which all would be traversed by a query



回答3:


A closer look at the result graph of the "working" query revealed the simple answer, as one can simply use the fileName property:

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


来源:https://stackoverflow.com/questions/56667478/how-to-include-package-into-query

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!