我正在尝试将TraversalDescription.traverse()的结果映射到自定义节点和关系对象的列表。
如果我将Cypher与sdn一起使用,我可以执行以下操作:
@Query("WITH {0} AS ns, {1} AS ne " +
"MATCH p=(n1{name:ns})-[*]-(n), (n2{name:ne}) " +
"WHERE n=n2 " +
"AND all(a IN nodes(p) WHERE single(x IN nodes(p) WHERE x=a)) " +
"RETURN nodes(p) as persons, rels(p) as connections " +
"ORDER BY size(nodes(p))")
List<GraphPath> getAllPaths(String startNode, String endNode);
然后映射到包含自定义节点和关系对象的GraphPath对象:
GraphPath.java
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@QueryResult
public class GraphPath {
private List<Person> persons;
private List<Connection> connections;
}
Person.java
@Getter
@Setter
@NoArgsConstructor
@NodeEntity(label = "Person")
public class Person extends Entity{
@Property(name = "name")
private String fullName;
@Property(name = "status")
private String status;
@Relationship(type = "CONNECTS", direction = Relationship.UNDIRECTED)
private Set<Connection> personConnections = new HashSet<>();
}
Connection.java
@Getter
@Setter
@NoArgsConstructor
@RelationshipEntity(type = "CONNECTS")
public class Connection extends Entity{
@Property(name="connection_id")
private String connectId;
@Property(name = "status")
private String status;
@StartNode
private Person personSource;
@EndNode
private Person personTarget;
}
和Entity.java只是POJO,带有字段id并覆盖了equals()和hashCode()
这在简单的图形中工作得很好,但是当图形变得更复杂时,获得结果的时间会增加得更多。我的目标是找到开始和结束节点之间的所有可能路径,并且每个路径中没有重复的节点或关系。我希望在运行时使用遍历API来消除一些不需要的路径(包含重复节点或关系的路径),以减少处理时间。
这是我使用的代码,graphDb只是GraphDatabaseService:
final Node startNode = graphDb.findNode(Labels.Person, "name", startNodeName);
final Node endNode = graphDb.findNode(Labels.Person, "name", endNodeName);
TraversalDescription td = graphDb.traversalDescription()
.depthFirst()
.evaluator(Evaluators.excludeStartPosition())
.evaluator(Evaluators.includeWhereEndNodeIs(endNode))
.relationships(Types.CONNECTS)
.uniqueness(Uniqueness.NODE_PATH)
.uniqueness(Uniqueness.RELATIONSHIP_PATH);
Traverser t = td.traverse(startNode)
现在的问题是,如何将结果映射到我上面提到的自定义对象?手动完成它将达到我必须处理递归对象映射的一个点(Set of在Person中连接,以及Connection中的目标和源Person)。
答案 0 :(得分:1)
正如我在评论中写的那样,我想我会手动进行映射,因为Path
返回的Traverser
已经包含节点和关系,现在只需要读取属性
通过迭代Path
,GraphPath
及其Person
和Connection
可以按顺序构建和完成。显然,这个代码可以通过提取方法来重构。
for (Path path : t) {
GraphPath gp = new GraphPath();
Person person = null;
Connection connection = null;
for (PropertyContainer pc : path) {
if (pc instanceof Node) {
Node node = (Node) pc;
person = new Person();
person.setId(node.getId());
person.setFullName(node.getProperty("name", null));
person.setStatus(node.getProperty("status", null));
gp.getPersons().add(person);
// No connection exists for the first node in the path
if (connection != null) {
// Find out which end has already been connected
if (connection.getPersonSource() == null) {
connection.setPersonSource(person);
} else {
connection.setPersonTarget(person);
}
person.getPersonConnections().add(connection);
}
} else {
Relationship rel = (Relationship) pc;
connection = new Connection();
connection.setId(rel.getId());
connection.setConnectId(rel.getProperty("connection_id", null));
connection.setStatus(rel.getProperty("status", null));
gp.getConnections().add(connection);
// Find out which end has already been mapped
if (rel.getStartNode().getId() == person.getId().longValue()) {
connection.setPersonSource(person);
} else {
connection.setPersonTarget(person);
}
person.getPersonConnections().add(connection);
}
}
}
如果您想要给定节点的单个Person
(resp。Connection
)实例,则可以更改Person
(resp。Connection
)创建以查找首先是Map
,您可以按ID对实体进行索引;您还必须将Person
和Connection
的连线一起更改为仅在Connection
上设置未设置的结尾,而不是依赖于一端或另一端的事实仍然无效。