社交图谱好友关系分析

版权声明:所有文章均为作者的学习笔记以及技术点整理,如果对您有帮助,请点个赞:) https://blog.csdn.net/superman_xxx/article/details/88920586

id(source)源节点 id(target)目标节点 result
60667 60669 60667:3条好友关系
60667 80988 60652:2条好友关系
60652 60667 60669:2条好友关系
60652 60669 80988:1条好友关系

以下代码完成快速统计目标人群中两两之间的好友关系数量(某节点相关联的好友关系数量)

一、两两之间好友关系查询

使用with定义一个列表变量,里面是所有的节点ID;使用match匹配出所有的结点,将结点放到列表中。使用两个unwind将结点列表打散到行,两个unwind的结点也是以笛卡尔积的方式返回的,所以这里是两两的任意组合,甚至两个结点相同的组合。实际上我们这里求最短路径1到2和2到1肯定是一样的,所以用id(source)<id(target)来去除一半;

WITH [60667,60652,60669,60635,80988] AS groupIds
     MATCH (n) WHERE id(n) IN groupIds
     WITH collect(n) AS nodes
     UNWIND nodes AS source
     UNWIND nodes AS target
     WITH source,target WHERE id(source)<id(target)
     MATCH paths=(source)-[:好友]-(target) RETURN path

二、自定义函数实现两两关系统计

1、通过节点列表统计之后将count值更新到节点并且返回节点列表

     /**
     * @param
     * @return
     * @Description: TODO(两两之间的好友关系分析)
     */
    @Procedure(name = "zdr.apoc.publicFriendAnalysis", mode = Mode.WRITE)
    @Description("Public friend analysis")
    public Stream<NodeResult> publicFriendAnalysis(@Name("sourceList") List<Node> sourceList, @Name("targetList") List<Node> targetList) {

        List<Node> nodes = new ArrayList<>();

        // 合并节点集合
        nodes.addAll(sourceList);
        nodes.addAll(targetList);

        // 统计好友关系数
        HashMap<Long, Integer> countMap = countFriedsRela(nodes);

        // 节点集合排重
        nodes = distinctNodes(nodes);

        // 给节点更新属性并返回
        return returnFriendResultNodes(nodes, countMap);
    }
     /**
     * @param
     * @return
     * @Description: TODO(统计好友关系数)
     */
    private HashMap<Long, Integer> countFriedsRela(List<Node> nodes) {
        HashMap<Long, Integer> countMap = new HashMap<>();
        nodes.forEach(node -> {
            long id = node.getId();
            if (countMap.containsKey(id)) {
                int count = countMap.get(id);
                count++;
                countMap.put(id, count);
            } else {
                countMap.put(id, 1);
            }
        });
        return countMap;
    }
    /**
     * @param
     * @return
     * @Description: TODO(节点集合排重)
     */
    private List<Node> distinctNodes(List<Node> nodes) {
        return nodes.stream()
                .filter(distinctById(v -> {
                    Node node = v;
                    return node.getId();
                }))
                .collect(Collectors.toCollection(ArrayList::new));
    }

2、通过节点ID列表统计之后返回LIST MAP(此过程使用函数实现更简洁)

     /**
     * @param
     * @return
     * @Description: TODO(两两之间的好友关系分析)
     */
    @Procedure(name = "zdr.apoc.publicFriendAnalysisMap", mode = Mode.WRITE)
    @Description("Public friend analysis")
    public Stream<NodeFriendCountList> publicFriendAnalysisMap(@Name("sourceList") List<Long> sourceList, @Name("targetList") List<Long> targetList) {

        List<Long> nodes = new ArrayList<>();

        // 合并节点集合
        nodes.addAll(sourceList);
        nodes.addAll(targetList);

        // 统计好友关系数
        HashMap<Long, Integer> countMap = countFriedsRelaIds(nodes);

        // 给节点更新属性并返回
        return Stream.of(new NodeFriendCountList(returnFriendResultNodesById(countMap)));
    }
     /**
     * @param
     * @return
     * @Description: TODO(统计好友关系数)
     */
    private HashMap<Long, Integer> countFriedsRelaIds(List<Long> nodes) {
        HashMap<Long, Integer> countMap = new HashMap<>();
        nodes.forEach(nodeId -> {
            long id = nodeId;
            if (countMap.containsKey(id)) {
                int count = countMap.get(id);
                count++;
                countMap.put(id, count);
            } else {
                countMap.put(id, 1);
            }
        });
        return countMap;
    }
    /**
     * @param
     * @return
     * @Description: TODO(将统计结果更新为节点属性并返回节点集合)
     */
    private List<Map<String, Object>> returnFriendResultNodesById(HashMap<Long, Integer> countMap) {
        List<Map<String, Object>> list = new ArrayList<>();
        countMap.forEach((k, v) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("id", k);
            map.put("count", v);
            list.add(map);
        });
        return list;
    }

三、使用UNWIND实现节点属性更新

# Nodes id list
 WITH [60667,60652,60669,60635,80988] AS groupIds
     MATCH (n) WHERE id(n) IN groupIds
     WITH collect(n) AS nodes
     UNWIND nodes AS source
     UNWIND nodes AS target
     WITH source,target WHERE id(source)<id(target)
     MATCH paths=(source)-[:好友]-(target) WITH collect(id(source)) AS sourceList,collect(id(target)) AS targetList
     CALL zdr.apoc.publicFriendAnalysisMap(sourceList,targetList) YIELD list WITH list
     UNWIND list AS row
     MATCH (n) WHERE id(n)=row.id SET n.targetGroupFriendsRelaCount=row.count RETURN n
     # publicFriendAnalysisMap过程返回的数据样例
     # [{"count":3,"id":60667},{"count":2,"id":60652},{"count":2,"id":60669},{"count":1,"id":80988}]  

四、自定义过程实现节点属性更新

# Nodes list
     WITH [60667,60652,60669,60635,80988] AS groupIds
     MATCH (n) WHERE id(n) IN groupIds
     WITH collect(n) AS nodes
     UNWIND nodes AS source
     UNWIND nodes AS target
     WITH source,target WHERE id(source)<id(target)
     MATCH paths=(source)-[:好友]-(target) WITH collect(source) AS sourceNodes,collect(target) AS targetNodes
     CALL zdr.apoc.publicFriendAnalysis(sourceNodes,targetNodes) YIELD node RETURN node
     # publicFriendAnalysis过程可以返回更新属性targetGroupFriendsRelaCount之后的节点

猜你喜欢

转载自blog.csdn.net/superman_xxx/article/details/88920586