基於社交帳號互動網絡生成虛擬圖

一、原始互動圖

原始圖譜結構包含Twitter賬號和帖子,關係類型有點贊|轉發|評論等,生成的圖譜如下所示:
在這裏插入圖片描述

二、生成的虛擬圖

生成虛擬圖之後,隱藏了全部的帖子節點,只展示出人與人之間的關係:
在這裏插入圖片描述

三、可視化數據格式樣例

{"totalNodeSize":3,"totalRelationSize":2,"consume":"Total consume 0s,average consume 0s/request","failed":0,"totalQuery":1,"message":true,"results":[{"data":[{"graph":{"relationships":[{"startNode":161,"id":40122,"type":"發帖","endNode":34650,"properties":{"relationType":"發帖","pub_time_mills":1573569457000,"update_time_mills":1582283028366}},{"startNode":497,"id":40123,"type":"轉發","endNode":34650,"properties":{"pub_time_mills":1573575391000,"update_time_mills":1582283028366}}],"nodes":[{"id":161,"properties":{"_unique_uuid":"0cd911cea1f97c6ef610721ac81adc61","name":"Denise Ho (HOCC)","nameNodeSpace":"Denise Ho (HOCC)","update_time_mills":1582283028366},"labels":["TwitterID"]},{"id":34650,"properties":{"_unique_uuid":"e6c41e85e33ee38d826fcf2c0ba2d8b9","nameNodeSpace":"轉推了","name":"轉推了","update_time_mills":1582283028366},"labels":["Twitter發帖"]},{"id":497,"properties":{"_unique_uuid":"6fa25ec0b043445c144e44e33c57121d","loadRecommendEnginePathSize":6,"nameNodeSpace":"Wenli9187","name":"Wenli9187","update_time_mills":1582283148428},"labels":["TwitterID"]}],"properties":[]}}],"columns":["p"]}],"successful":1}

四、相關類

實現思路:遍歷圖譜,對於賬號之間存在帖子的兩層關係線進行合併,將賬號直接連接到另一個賬號,實現收縮圖譜的目的。生成的虛擬圖不持久化到到圖庫,是即時分析的結果。

  1. VirtualGraphManager虛擬圖IDS管理對象
/**
 * @author YanchaoMa [email protected]
 * @PACKAGE_NAME: casia.isi.zdr.graph.services.graph.virtual
 * @Description: TODO(虛擬圖IDS管理對象)
 * @date 2019/5/20 16:18
 */
public class VirtualGraphManager {

    // 從RESULT中獲取NODES - KEY
    public final static String nodesFieldName = "nodes";

    // 從RESULT中獲取RELATIONSHIPS - KEY
    public final static String relationshipsFieldName = "relationships";

    /**
     * 虛擬圖ID都爲負值
     **/

    /**
     * 自增關係ID變量 - 互動網絡虛擬關係線ID都爲負值
     **/
    private static long relationshipId;

    /**
     * 關係線虛擬ID管理LIST
     **/
    private final static CopyOnWriteArrayList<VirtualRelaId> virtualRelaIdManager = new CopyOnWriteArrayList<>();

    private static void clear(int virtualRelaIdSize) {
        if (virtualRelaIdManager.size() >= virtualRelaIdSize) {
            virtualRelaIdManager.clear();
        }
    }

    private static void add(VirtualRelaId virtualRelaId) {
        if (!virtualRelaIdManager.contains(virtualRelaId)) {
            virtualRelaIdManager.add(virtualRelaId);
        }
    }

    /**
     * @param targetId:開始節點ID
     * @param endId:結束節點ID
     * @return
     * @Description: TODO(從虛擬關係ID列表中獲取關係ID)
     */
    private static long getVirtualRelaId(long targetId, long endId, String virRelaName) {
        return virtualRelaIdManager.parallelStream()
                .filter(v -> v.pathEquals(targetId, endId, virRelaName))
                .findAny().orElse(new VirtualRelaId()).getRelationshipId();
    }

    /**
     * @param
     * @param targetId
     * @param endId
     * @return
     * @Description: TODO(關係ID生成 - 獲取關係ID)
     */
    // 併發操作可能導致生成相同的ID,加鎖操作
    public synchronized static long relaIdProducer(long targetId, long endId, String virRelaName) {

        Optional optional = Optional.ofNullable(getVirtualRelaId(targetId, endId, virRelaName));
        if (optional.isPresent() && (long) optional.get() != 0) {
            return (long) optional.get();
        } else {
            clear(1000);
            add(new VirtualRelaId(targetId, endId, -++relationshipId, virRelaName));
            return -relationshipId;
        }
    }

    /**
     * @param targetId:開始節點ID
     * @param endId:結束節點ID
     * @param virRelaName:虛擬關係名稱
     * @param properties:除關係名之外的其它關係屬性
     * @return
     * @Description: TODO(關係對象生成)
     */
    public static JSONObject virRelas(long targetId, String virRelaName, long endId, JSONObject properties) {
        if (targetId != endId) {
            JSONObject pro = new JSONObject();
            pro.put("name", virRelaName);
            if (properties != null) {
                pro.putAll(properties);
            }
            JSONObject relationship = new JSONObject();
            relationship.put("startNode", targetId);
            relationship.put("id", relaIdProducer(targetId, endId, virRelaName));
            relationship.put("type", virRelaName);
            relationship.put("endNode", endId);
            relationship.put("properties", pro);
            return relationship;
        }
        return null;
    }

}
  1. VirtualRelaId虛擬圖關係ID對象-如何排重關係
/**
 * @author YanchaoMa [email protected]
 * @PACKAGE_NAME: casia.isi.zdr.graph.services.graph.interactive
 * @Description: TODO(虛擬圖關係ID對象)
 * @date 2019/5/16 11:37
 */
public class VirtualRelaId {

    private long startNodeId;
    private long endNodeId;
    private String virRelaName;
    private long relationshipId;

    public VirtualRelaId() {
    }

    public VirtualRelaId(long startNodeId, long endNodeId, long relationshipId, String virRelaName) {
        this.startNodeId = startNodeId;
        this.endNodeId = endNodeId;
        this.relationshipId = relationshipId;
        this.virRelaName = virRelaName;
    }

    @Override
    public String toString() {
        return "VirtualRelaId{" +
                "startNodeId=" + startNodeId +
                ", endNodeId=" + endNodeId +
                ", virRelaName=" + virRelaName +
                ", relationshipId=" + relationshipId +
                '}';
    }

    /**
     * @param
     * @return
     * @Description: TODO(( 開始節點)->(結束節點) (結束節點)->(開始節點) 關係名一樣時使用相同的關係ID )
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        VirtualRelaId that = (VirtualRelaId) o;
        return ((this.startNodeId == that.startNodeId && this.endNodeId == that.endNodeId) ||
                (this.startNodeId == that.endNodeId && this.endNodeId == that.startNodeId)) &&
                (this.virRelaName.equals(that.virRelaName));
    }

    @Override
    public int hashCode() {
        return Objects.hash(startNodeId, endNodeId, virRelaName);
    }

    /**
     * @param
     * @return
     * @Description: TODO(判斷是否是同一虛擬條路徑)
     */
    public boolean pathEquals(long startNodeId, long endNodeId, String virRelaName) {
        if (((this.startNodeId == startNodeId && this.endNodeId == endNodeId) ||
                (this.startNodeId == endNodeId && this.endNodeId == startNodeId)) &&
                (this.virRelaName.equals(virRelaName))) {
            return true;
        }
        return false;
    }

    public long getStartNodeId() {
        return startNodeId;
    }

    public void setStartNodeId(long startNodeId) {
        this.startNodeId = startNodeId;
    }

    public long getEndNodeId() {
        return endNodeId;
    }

    public void setEndNodeId(long endNodeId) {
        this.endNodeId = endNodeId;
    }

    public long getRelationshipId() {
        return relationshipId;
    }

    public void setRelationshipId(long relationshipId) {
        this.relationshipId = relationshipId;
    }

    public String getVirRelaName() {
        return virRelaName;
    }

    public void setVirRelaName(String virRelaName) {
        this.virRelaName = virRelaName;
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章