整体效果概览

Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)METHOD_CALLSMETHOD_CALLSMETHOD_CALLSMETHOD_CALLSMETHOD_CALLSMETHOD_CALLSMETHOD_CALLSBELO…BELONG_APPBELONG_APPBELONG_APPBELONG_APP appC,m… appD,m… appD,m… appA,m… appB,m… appB appD appC appA

核心实体定义

ChainMethod-接口方法

@NodeEntity(label = "ChainMethod")
@Data
public class Neo4jChainMethodEntity implements Serializable {

    /**
     * appName + methodName
     *
     * 测试下来有一个非常神奇的问题:如果一个属性以 xxxId 结尾,似乎会导致节点显示为空。
     */
    @Id
    private String methodFullName;

    @Property
    private String methodName;

    /**
     * @see com.github.houbb.method.chain.neo4j.constant.MethodTypeEnum
     */
    @Property
    private String methodType;

    @Property
    private String appName;

    @Relationship(type = RelationshipTypeConst.BELONG_APP, direction = Relationship.OUTGOING)
    private Neo4jChainAppEntity chainApp;

    public Neo4jChainMethodEntity(String methodName, String methodType, String appName) {
        this.methodName = methodName;
        this.methodType = methodType;
        this.appName = appName;

        this.methodFullName = InnerAppMethodUtil.buildFullName(appName, methodName);
        this.chainApp = new Neo4jChainAppEntity(appName);
    }
}

ChainApp-应用

@NodeEntity(label = "ChainApp")
@Data
public class Neo4jChainAppEntity implements Serializable {

    @Id
    private String appName;

    public Neo4jChainAppEntity(String appName) {
        this.appName = appName;
    }

}

关系

/**
 * method 方法名称
 */
@RelationshipEntity(type = RelationshipTypeConst.METHOD_CALLS)
@Data
public class Neo4jChainMethodRelationshipEntity implements Serializable {

    /**
     * 当前调用关系的唯一标识
     *
     * 如何保证唯一呢?
     *
     * md5(tid+startMethod+endMethod)?
     */
    @Id
    private String methodRelationId;

    /**
     * 链路唯一标识 traceId
     */
    @Index
    @Property
    private String tid;

    /**
     * 链路哈希
     */
    @Property
    @Index
    private String chainHash;

    /**
     * 开始节点
     */
    @StartNode
    private Neo4jChainMethodEntity startMethod;

    /**
     * 结束节点
     */
    @EndNode
    private Neo4jChainMethodEntity endMethod;

    public Neo4jChainMethodRelationshipEntity(String tid, Neo4jChainMethodEntity startMethod, Neo4jChainMethodEntity endMethod) {
        this.tid = tid;

        this.startMethod = startMethod;
        this.endMethod = endMethod;
    }

}

链路初始化

初始化

    /**
     * 数据初始化
     *
     * methodA1 -WEB
     * methodB1 -DUBBO
     * methodC1 -DUBBO
     * methodD1 -DUBBO
     */
    @Test
    public void initMethodRelationshipTest() {
        Neo4jChainMethodEntity methodA1 = new Neo4jChainMethodEntity("methodA1", MethodTypeEnum.WEB.getCode(),
                "appA");
        Neo4jChainMethodEntity methodB1 = new Neo4jChainMethodEntity("methodB1", MethodTypeEnum.DUBBO.getCode(),
                "appB");
        Neo4jChainMethodEntity methodC1 = new Neo4jChainMethodEntity("methodC1", MethodTypeEnum.DUBBO.getCode(),
                "appC");
        Neo4jChainMethodEntity methodD1 = new Neo4jChainMethodEntity("methodD1", MethodTypeEnum.DUBBO.getCode(),
                "appD");
        Neo4jChainMethodEntity methodD2 = new Neo4jChainMethodEntity("methodD2", MethodTypeEnum.SERVICE.getCode(),
                "appD");

        // 保存方法信息
        chainMethodRepository.save(methodA1);
        chainMethodRepository.save(methodB1);
        chainMethodRepository.save(methodC1);
        chainMethodRepository.save(methodD1);
        chainMethodRepository.save(methodD2);


        // 第一个调用链路
        final String tidFirst = "T0001";
        //A=>B
        Neo4jChainMethodRelationshipEntity relationshipFirstA = new Neo4jChainMethodRelationshipEntity(tidFirst, methodA1, methodB1);
        //A=>C
        Neo4jChainMethodRelationshipEntity relationshipFirstB = new Neo4jChainMethodRelationshipEntity(tidFirst, methodA1, methodC1);
        //B=>D
        Neo4jChainMethodRelationshipEntity relationshipFirstC = new Neo4jChainMethodRelationshipEntity(tidFirst, methodB1, methodD1);
        List<Neo4jChainMethodRelationshipEntity> chainListFirst = Arrays.asList(relationshipFirstA, relationshipFirstB, relationshipFirstC);
        chainMethodRelationshipService.batchAdd(chainListFirst);

        // 第二个调用链路
        final String tidSecond = "T0002";
        //A=>B
        Neo4jChainMethodRelationshipEntity relationshipSecondA = new Neo4jChainMethodRelationshipEntity(tidSecond, methodA1, methodB1);
        //A=>C
        Neo4jChainMethodRelationshipEntity relationshipSecondB = new Neo4jChainMethodRelationshipEntity(tidSecond, methodA1, methodC1);
        //C=>D
        Neo4jChainMethodRelationshipEntity relationshipSecondC = new Neo4jChainMethodRelationshipEntity(tidSecond, methodC1, methodD1);
        //D1=>D2
        Neo4jChainMethodRelationshipEntity relationshipSecondD = new Neo4jChainMethodRelationshipEntity(tidSecond, methodD1, methodD2);

        List<Neo4jChainMethodRelationshipEntity> chainListSecond = Arrays.asList(relationshipSecondA, relationshipSecondB, relationshipSecondC, relationshipSecondD);
        chainMethodRelationshipService.batchAdd(chainListSecond);
    }

对应的链路效果

Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)CHAIN_CALLSCHAIN_CALLSCHAIN_CALLSCHAIN_CALLSCHAIN_CALLSCHAIN_CALLSCHAIN_CALLS appA,m… appC,m… appB,m… appD,m… appD,m… appD,m… appA,m… appC,m… appB,m…

清空

MATCH (n)  
DETACH DELETE n;

查询

作为入口:

match p=(startM)-[r:METHOD_CALLS]->(endM) 
where (r.endMethodFullName='appD,methodD1') 
return startM, r, endM

作为出口:

match p=(startM)-[r:METHOD_CALLS]->(endM) 
where (r.startMethodFullName='appD,methodD1') 
return startM, r, endM

必须要有方向性。


match p=(startM)-[r:METHOD_CALLS]->(endM) 
where (r.startMethodFullName='appD,methodD1') 
return r

过滤

MATCH p=(startM)-[r:METHOD_CALLS]->(endM) 
where r.tid='T0001'
RETURN startM, r, endM 
LIMIT 1000

根据节点直接查询

neo4j 如何查询一个节点关联的所有边信息

MATCH (n)-[r]-(m)
WHERE n.methodFullName = 'appB,methodB1'
RETURN r

neo4j 如何查询一个节点所有 income 进入边的信息,且 这个边的类别是 METHOD_CALLS

要查询一个节点所有入边的信息,且这些边的类别是METHOD_CALLS,你可以使用Cypher查询语言。以下是如何查询一个节点所有METHOD_CALLS类别的入边的示例:

假设你有一个节点,它的ID为node_id,你想查询所有指向这个节点的METHOD_CALLS类别的入边。你可以使用以下Cypher查询:

MATCH (n)<-[r:METHOD_CALLS]-(m)
WHERE n.methodFullName = 'appB,methodB1'
RETURN r

这个查询做了以下几件事情:

  1. MATCH (n)<-[r:METHOD_CALLS]-(m):这一部分会匹配所有节点n和节点m之间的METHOD_CALLS类别的入边rn是指定节点,m是指向节点,r是边的变量名。

  2. WHERE ID(n) = node_id:这一部分用于筛选出与特定节点ID匹配的n。替换node_id为你要查询的节点的实际ID。

  3. RETURN r:最后,这一部分会返回与选定节点相关的所有METHOD_CALLS类别的入边r

通过运行这个Cypher查询,你将得到与指定节点相关的所有METHOD_CALLS类别的入边信息。

查询作为出的边

MATCH (n)-[r:METHOD_CALLS]->(m)
WHERE n.methodFullName = 'appB,methodB1'
RETURN n,r,m 
LIMIT 1000

小结

基本的关系创建实例。

参考资料