Neo4j Procedure

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.whx.neo4j.procedure</groupId>
	<artifactId>Neo4jProcedure</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>Neo4jProcedure</name>
	<url>http://maven.apache.org</url>

	<properties>
	    <maven.compiler.source>11</maven.compiler.source>
	    <maven.compiler.target>11</maven.compiler.target>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.neo4j</groupId>
			<artifactId>neo4j</artifactId>
			<version>4.4.6</version>
		</dependency>
	</dependencies>
</project>
package com.whx.neo4j.procedure.controlflow.path;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.traversal.Evaluators;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.graphdb.traversal.Traverser;
import org.neo4j.graphdb.traversal.Uniqueness;
import org.neo4j.internal.helpers.collection.Iterables;
import org.neo4j.logging.Log;
import org.neo4j.procedure.Context;
import org.neo4j.procedure.Name;
import org.neo4j.procedure.Procedure;

import com.whx.neo4j.procedure.enums.EdgeTypes;
import com.whx.neo4j.procedure.evaluators.CyclePathEvaluator;
import com.whx.neo4j.procedure.filters.CompletePathFileter;
import com.whx.neo4j.procedure.filters.CyclePathFileter;
import com.whx.neo4j.procedure.result.PathResult;
import com.whx.neo4j.procedure.utils.ProcedureUtils;

public class ControlFlowPathTraversal {
	@Context
    public Transaction tx;
	
	@Context
    public Log log;
	
	/**
	 * 
	 * @param start
	 * @param end
	 * @return
	 * @throws Exception
	 */
	@Procedure("control.flow.path.sample")
	public Stream<PathResult> doTraversal(@Name("start") Object start) throws Exception{
		
		Node startNode = tx.getNodeById(4);
		
		TraversalDescription td = tx.traversalDescription()
				.depthFirst()
				.relationships(EdgeTypes.ControlFlow, Direction.OUTGOING)
				.uniqueness(Uniqueness.RELATIONSHIP_PATH);
		
		Traverser traverser = td.traverse(startNode);
		return Iterables.stream(traverser).map( PathResult::new );
	}

	/**
	 * 
	 * @param start
	 * @param end
	 * @return
	 * @throws Exception
	 */
	@Procedure("control.flow.path")
	public Stream<PathResult> doTraversal(@Name("start") Object start,
			@Name("end") Object end) throws Exception{
		List<Node> startNodes = objectToNodes(start);
		List<Node> endNodes = objectToNodes(end);
		 Stream<Path> traversal = doTraversal(null
				, startNodes.get(0)
				, endNodes.get(0)
				, EdgeTypes.ControlFlow
				, Direction.OUTGOING
				, Uniqueness.RELATIONSHIP_PATH);
		 
		 return traversal.map( PathResult::new);
	}
	
	/**
	 * 
	 * @param srcPath
	 * @param startNode
	 * @param endNode
	 * @param edge
	 * @param direction
	 * @param uniqueness
	 * @return
	 */
	public Stream<Path> doTraversal(
			Path srcPath,
			Node startNode,
			Node endNode,
			EdgeTypes edge,
			Direction direction,
			Uniqueness uniqueness){
		
		if(null == srcPath) {
			System.out.println("Traversal Start");
		}else {
			ProcedureUtils.showPath(srcPath, "Cycle Traversal Start");
		}
		
		TraversalDescription td = tx.traversalDescription()
				.depthFirst()
				.relationships(edge, direction);
		
		// minLevel: 1
		int minLevel = 1;
		td = td.evaluator(Evaluators.fromDepth(minLevel));
		
		//
		td = td.evaluator(Evaluators.fromDepth(minLevel));
		
		// Uniqueness
		td = td.uniqueness(uniqueness);

		// Cycle Path Check
		td = td.evaluator(new CyclePathEvaluator(endNode));
		
		// do traverse
		Traverser traverser = td.traverse(startNode);
		List<Path> traverseredPathList = Iterables.stream(traverser).collect(Collectors.toList());
		ProcedureUtils.showPaths(traverseredPathList, "Traversered");
		
		// Cycle Path Extra
		CyclePathFileter<Path> cyclePathFileter = new CyclePathFileter<Path>(endNode);
		List<Path> cyclePathList = traverseredPathList.stream().filter(cyclePathFileter).collect(Collectors.toList());
		if(cyclePathList.size() == 0) {
			if(null == srcPath) {
				ProcedureUtils.showPaths(traverseredPathList, "Traversal End");
				
			}else {
				ProcedureUtils.showPaths(traverseredPathList, "Cycle Traversal End");
			}
			return traverseredPathList.stream();
		}
		ProcedureUtils.showPaths(cyclePathList, "Cycle");
		// Cycle Path Traversal Again
		final List<Path> subPathList = new ArrayList<>();
		cyclePathList.stream().forEach(path -> {
			if(path.endNode().getId() == endNode.getId()) {
				return;
			}
			Stream<Path> traversal = doTraversal(path, path.endNode(), endNode, edge, direction, uniqueness);
			traversal.forEach(subPath -> {
				Path combinePath = ProcedureUtils.combine(path, subPath);
				subPathList.add(combinePath);
			});
		});
		ProcedureUtils.showPaths(subPathList, "Sub");
		CompletePathFileter<Path> completePathFileter = new CompletePathFileter<Path>(endNode);
		List<Path> result = traverseredPathList.stream().filter(completePathFileter).collect(Collectors.toList());
		ProcedureUtils.showPaths(result, "Complete");
		result.addAll(subPathList);
		ProcedureUtils.showPaths(result, "ALL");
		if(null == srcPath) {
			System.out.println("Traversal End");
		}else {
			ProcedureUtils.showPath(srcPath, "Cycle Traversal End");
		}
		
		return result.stream();
	}
	/**
	 * 
	 * @param start
	 * @return
	 * @throws Exception
	 */
	private List<Node> objectToNodes(Object start) throws Exception {
		if (start == null) return Collections.emptyList();
		if (start instanceof Node) {
			return Collections.singletonList((Node) start);
		}
		if (start instanceof Number) {
			return Collections.singletonList(tx.getNodeById(((Number) start).longValue()));
		}
		if (start instanceof List) {
			List list = (List) start;
			if (list.isEmpty()) return Collections.emptyList();

			Object first = list.get(0);
			if (first instanceof Node) return (List<Node>)list;
			if (first instanceof Number) {
                List<Node> nodes = new ArrayList<>();
                for (Number n : ((List<Number>)list)) nodes.add(tx.getNodeById(n.longValue()));
                return nodes;
            }
		}
		throw new Exception("Unsupported data type for start parameter a Node or an Identifier (long) of a Node must be given!");
	}
}
package com.whx.neo4j.procedure.enums;

import org.neo4j.graphdb.RelationshipType;

public enum EdgeTypes implements RelationshipType {
	ControlFlow
}
package com.whx.neo4j.procedure.evaluators;

import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.traversal.Evaluation;
import org.neo4j.graphdb.traversal.Evaluator;
import org.neo4j.internal.helpers.collection.Iterables;

import com.whx.neo4j.procedure.utils.ProcedureUtils;

public class CyclePathEvaluator implements Evaluator {
	private Node endNode;
	
	public CyclePathEvaluator(Node endNode) {
		this.endNode = endNode;
	}

	@Override
	public Evaluation evaluate(Path path) {
		ProcedureUtils.showPath(path, "Cycle Path Evaluator");
		if(endNode.getId() == path.endNode().getId()) {
			return Evaluation.INCLUDE_AND_CONTINUE;
		}
		// Relationships count
		long relationshipCount = path.length();
		// Nodes count
		long nodeCount = Iterables.stream(path.nodes()).distinct().count();
		
		if(nodeCount <= relationshipCount) {
			// Cycle Path
			if(path.startNode().getId() == path.endNode().getId()) {
				return Evaluation.EXCLUDE_AND_CONTINUE;
			}
			return Evaluation.INCLUDE_AND_CONTINUE;
		}
		return Evaluation.EXCLUDE_AND_CONTINUE;
	}

}
package com.whx.neo4j.procedure.filters;

import java.util.function.Predicate;

import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;

public class CompletePathFileter<T> implements Predicate<T> {
	private Node endNode;
	
	public CompletePathFileter(Node endNode) {
		super();
		this.endNode = endNode;
	}

	@Override
	public boolean test(T t) {
		if(!(t instanceof Path)) {
			throw new IllegalArgumentException("CompletePathFileter Error!!!");
		}
		Path path = (Path) t;
		if(path.endNode().getId() == endNode.getId()) {
			return true;
		}
		return false;
	}

}
package com.whx.neo4j.procedure.filters;

import java.util.function.Predicate;

import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.internal.helpers.collection.Iterables;

public class CyclePathFileter<T> implements Predicate<T> {
private Node endNode;
	
	public CyclePathFileter(Node endNode) {
		super();
		this.endNode = endNode;
	}

	@Override
	public boolean test(T t) {
		if(!(t instanceof Path)) {
			throw new IllegalArgumentException("CyclePathFileter Error!!!");
		}
		Path path = (Path) t;
		if(path.endNode().getId() == endNode.getId()) {
			return false;
		}
		// Relationships count
		long relationshipCount = path.length();
		// Nodes count
		long nodeCount = Iterables.stream(path.nodes()).distinct().count();
		
		if(nodeCount <= relationshipCount) {
			return true;
		}

		if(nodeCount == (relationshipCount + 1)) {
			return false;
		}
		throw new IllegalArgumentException("CyclePathFileter Error!!!");
	}

}
package com.whx.neo4j.procedure.result;

import org.neo4j.graphdb.Path;

public class PathResult {
    public Path path;

    public PathResult(Path path) {
        this.path = path;
    }
}
package com.whx.neo4j.procedure.utils;

import java.util.List;

import org.neo4j.graphalgo.impl.util.PathImpl;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Relationship;

public class ProcedureUtils {
	/**
	 * 
	 * @param first
	 * @param second
	 * @return
	 */
	public static Path combine(Path first, Path second) {
        if (first == null) return second;
        if (second == null) return first;

        if (first.endNode().getId() != second.startNode().getId())
            throw new IllegalArgumentException("Paths don't connect on their end and start-nodes "+first+ " with "+second);

        PathImpl.Builder builder = new PathImpl.Builder(first.startNode());
        for (Relationship rel : first.relationships()) builder = builder.push(rel);
        for (Relationship rel : second.relationships()) builder = builder.push(rel);
        return builder.build();
    }
	/**
	 * 
	 * @param paths
	 * @param prefix
	 */
	public static void showPaths(List<Path> paths, String prefix) {
		paths.stream().forEach(path -> {
			showPath(path, prefix);
		});
	}
	/**
	 * 
	 * @param path
	 * @param prefix
	 */
	public static void showPath(Path path, String prefix) {
		StringBuilder result = new StringBuilder();
		
		result.append(prefix).append(" ").append("Path\t");
		path.nodes().forEach(node -> {
			String text = (String) node.getProperty("text");
			result.append(text)
				.append("->");
		});
		System.out.println(result.toString());
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值