ID-MAPPING解绑实现(图计算)

直接上代码吧。

/**
 * 这是一个无向图数据结构,支持非联通。
 * 支持ID-Mapping解绑使用
 * @Author Ma Shuai
 * @Date 9/13/24 5:45 PM
 * @Version 1.0
 */

public class UnbindGraph {

  private static String SPLIT = ":";

  public UnbindGraph() {
    this.adjacentNodeMap = new HashMap<>();
    this.nodeMessageMap = new HashMap<>();
  }

  @Data
  public class NodeMessage {

    private String  idType;
    private String  idValue;
    // key是业务来源table_name(业务来源唯一对应一个表) value是表主键PK。 Long类型有需要时可换成bean
    private Map<String, List<Long>> tableAndPKList;


    public NodeMessage(String idType, String idValue,String tableName, Long pk){
      this.idType = idType;
      this.idValue = idValue;
      this.tableAndPKList = new HashMap<>();
      this.tableAndPKList.put(tableName,new ArrayList<Long>(){{add(pk);}});
    }

    private void setTableAndPKList(Map<String, Set<Long>> tableAndPKList) {}

    public void setTableAndPKList(String tableName, Long pk) {
      if(!this.tableAndPKList.containsKey(tableName)){
        this.tableAndPKList.put(tableName,new ArrayList<Long>(){{add(pk);}});
      }else {
        this.tableAndPKList.get(tableName).add(pk);
      }
    }
  }

  //节点关系 node String=>idtype:idvalue
  private Map<String, Set<String>> adjacentNodeMap;

  //节点信息 node message (方便拓展性维护性以及空间的节省 单独Map存节点信息)
  private Map<String, NodeMessage> nodeMessageMap;


  /**
   * 添加节点关系 A-B
   * @param A
   * @param B
   */
  public void addEdge(GraphNodeParameter A,GraphNodeParameter B){
    // 都不符合规范不入图(所以图结果集不存在不符合规范的数据会导致有的centerid对应的数据没有得到处理,最后要按照老的centerid逻辑删除数据)
    if(!checkGraphNodeParameterIsTrue(A)&&!checkGraphNodeParameterIsTrue(B)){
      return;
    }
    setAdjacentNodeRelation(A,B);
  }

  /**
   * A-B 入图
   * @param A
   * @param B
   */
  private void setAdjacentNodeRelation(GraphNodeParameter A,GraphNodeParameter B) {
    //当前节点的预处理
    pretreatmentNode(A,B);
    // AB都合规
    if(checkGraphNodeParameterIsTrue(A)&&checkGraphNodeParameterIsTrue(B)){
      String idTypeValueA = A.getIdType()+SPLIT+A.getIdValue();
      String idTypeValueB = B.getIdType()+SPLIT+B.getIdValue();
      //无向
      setAdjacentNode(idTypeValueA, idTypeValueB);
      setAdjacentNode(idTypeValueB, idTypeValueA);
    }
  }

  /**
   * 存储节点信息、整理临接表
   * @param nodeParameters
   */
  private void pretreatmentNode(GraphNodeParameter... nodeParameters) {
    for (GraphNodeParameter N : nodeParameters) {
      if(!checkGraphNodeParameterIsTrue(N)){
        continue;
      }
      //节点信息
      String idType = N.getIdType();
      String idValue = N.getIdValue();
      String idTypeValue = idType+SPLIT+idValue;
      String tableName = N.getTableName();
      Long pk = N.getPK();
      // pretreatment adjacentNodeMap
      if(!this.adjacentNodeMap.containsKey(idTypeValue)){
        this.adjacentNodeMap.put(idTypeValue,new HashSet<>());
      }
      // add NodeMessage
      if(!this.nodeMessageMap.containsKey(idTypeValue)) {
        this.nodeMessageMap.put(idTypeValue,new NodeMessage(idType,idValue,tableName,pk));
      }else {
        this.nodeMessageMap.get(idTypeValue).setTableAndPKList(tableName,pk);
      }
    }
  }

  /**
   * 设置临接关系
   * @param idTypeValueA
   * @param idTypeValueB
   */
  private void setAdjacentNode(String idTypeValueA, String idTypeValueB) {
    this.adjacentNodeMap.get(idTypeValueA).add(idTypeValueB);
  }

  /**
   * 校验节点数据
   * @param nodeParameter
   * @return
   */
  private boolean checkGraphNodeParameterIsTrue(GraphNodeParameter nodeParameter){
    return
        nodeParameter != null
        &&
        !StringUtils.isEmptyOrWhitespaceOnly(nodeParameter.getIdValue())
        &&
        !StringUtils.isEmptyOrWhitespaceOnly(nodeParameter.getIdType());
  }

  /**
   * 图遍历,默认使用DFS
   * @return List<List<NodeMessage>> 存储多个连通图数据,每个List<NodeMessage>是同一个连通图的数据
   */
  public List<List<NodeMessage>> traversingGraph(){
    return traversingGraph(true);
  }

  /**
   * DFS or BFS 遍历图,true使用DFS,false使用BFS,NULL默认使用DFS
   * @param b
   * @return List<List<NodeMessage>> 存储多个连通图数据,每个List<NodeMessage>是同一个连通图的数据
   */
  public List<List<NodeMessage>> traversingGraph(Boolean b){
    b = b==null?true:b;
    //此数据结构是个非联通图,所以遍历完后要存储多组联通图,每个map属于同一个graph。
    List<List<NodeMessage>> nGraph = new ArrayList<>();
    Set<String> visited = new HashSet<>();
    Set<String> nodes = this.adjacentNodeMap.keySet();

    if(b){
      for (String start : nodes) {
        if (!visited.contains(start)) {
          nGraph.add(dfs(start,visited));
        }
      }
    }else {
      for (String start : nodes) {
        if (!visited.contains(start)) {
          nGraph.add(bfs(start,visited));
        }
      }
    }
    return nGraph;
  }

  /**
   * 广度优先(BFS)
   * @param start
   * @return List<NodeMessage> 存储同一个连通图的数据
   */
  public List<NodeMessage> bfs(String start) {
    Set<String> visited = new HashSet<>();
    return bfs(start, visited);
  }
  /**
   * 广度优先(BFS)
   * @param start
   * @param visited
   * @return List<NodeMessage> 存储同一个连通图的数据
   */
  public List<NodeMessage> bfs(String start, Set<String> visited) {
    List<NodeMessage> nodeMessages = new ArrayList<>();
    Queue<String> queue = new LinkedList<>();
    queue.offer(start);
    visited.add(start);

    while (!queue.isEmpty()){
      String current = queue.poll();
      //存储层次遍历的数据
      nodeMessages.add(this.nodeMessageMap.get(current));
      for (String adjacent : adjacentNodeMap.get(current)) {
        if(!visited.contains(adjacent)){
          queue.offer(adjacent);
          visited.add(adjacent);
        }
      }
    }
    return nodeMessages;
  }


  /**
   * 深度优先搜索(DFS)
   * @param start
   * @return List<NodeMessage> 存储同一个连通图的数据
   */
  public List<NodeMessage> dfs(String start) {
    Set<String> visited = new HashSet<>();
    return dfs(start, visited);
  }
  /**
   * 深度优先搜索(DFS)
   * @param start
   * @return List<NodeMessage> 存储同一个连通图的数据
   */
  public List<NodeMessage> dfs(String start, Set<String> visited) {
    List<NodeMessage> nodeMessages = new ArrayList<>();
    dfs(start, visited, nodeMessages);
    return nodeMessages;
  }

  /**
   * 深度优先搜索(DFS)
   * @param start
   * @param visited
   * @param nodeMessages 存储同一个连通图的数据
   */
  private void dfs(String start, Set<String> visited, List<NodeMessage> nodeMessages) {
    if(visited.contains(start)) return;
    visited.add(start);
    nodeMessages.add(this.nodeMessageMap.get(start));
    for (String neighbor : this.adjacentNodeMap.get(start)) {
      dfs(neighbor,visited,nodeMessages);
    }
  }



}

图的入参单独做了一个bean(可根据自己业务需求自定义,同理上述图算法中的NodeMessage类也可以自定义需要存储的节点信息)

/**
 * @Author Ma Shuai
 * @Date 2021-09-03 19:48
 * @Version 1.0
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class GraphNodeParameter {
  private String  idType;
  private String  idValue;
  private String  tableName;
  private Long    pK;
}

测试:(需要解绑的关系不入图,然后再遍历图得到的就是解绑后的结果)

  @Test
  public void test1() {
    //创建图对象
    UnbindGraph unbindGraph = new UnbindGraph();
    // 添加连通关系1
    unbindGraph.addEdge(
        new GraphNodeParameter("mobile","mobile222","c_center_account_for_uc",123L)
        ,new GraphNodeParameter("userId","userId333","c_center_account_for_uc",123L)
    );
    unbindGraph.addEdge(
        new GraphNodeParameter("unionId","unionId444","c_center_account_for_user_union",343L)
        ,new GraphNodeParameter("userId","userId333","c_center_account_for_user_union",343L)
    );

    // 添加连通关系2
    unbindGraph.addEdge(
        new GraphNodeParameter("wxId","wxId111","c_center_account_for_user_union",24543L)
        ,null
    );
    unbindGraph.addEdge(
        new GraphNodeParameter("unionId","","c_center_account_for_user_union",24543L)
        ,new GraphNodeParameter("wxId","wxId111","c_center_account_for_user_union",24543L)
    );

    // 添加连通关系3
    unbindGraph.addEdge(
        new GraphNodeParameter("mobile","mobile111","c_center_account_for_uc",24524L)
        ,new GraphNodeParameter("userId","userId111","c_center_account_for_uc",24524L)
    );

    unbindGraph.addEdge(
        new GraphNodeParameter("unionId","unionId111","c_center_account_for_uc",35634L)
        ,new GraphNodeParameter("userId","userId111","c_center_account_for_uc",35634L)
    );

    unbindGraph.addEdge(
        new GraphNodeParameter("unionId","unionId111","c_center_account_for_crm",2356345L)
        ,new GraphNodeParameter("customerId","customerId111","c_center_account_for_crm",2356345L)
    );

    //图遍历
    List<List<UnbindGraph.NodeMessage>> lists = unbindGraph.traversingGraph();
    for (List<UnbindGraph.NodeMessage> list : lists) {
      System.out.println(list);
    }

  }

打印结果:

解释:idType和idValue相同时算作同一个节点,只不过添加相同节点时可能携带的信息不同。(比如相同的两个节点之间多条线,可以携带线的信息)

[UnbindGraph.NodeMessage(idType=wxId, idValue=wxId111, tableAndPKList={c_center_account_for_user_union=[24543, 24543]})]
[UnbindGraph.NodeMessage(idType=mobile, idValue=6a5af3a1467d36ed640aa7103e372e9c, tableAndPKList={c_center_account_for_uc=[24524]}), UnbindGraph.NodeMessage(idType=userId, idValue=userId111, tableAndPKList={c_center_account_for_uc=[24524, 35634]}), UnbindGraph.NodeMessage(idType=unionId, idValue=unionId111, tableAndPKList={c_center_account_for_uc=[35634], c_center_account_for_crm=[2356345]}), UnbindGraph.NodeMessage(idType=customerId, idValue=customerId111, tableAndPKList={c_center_account_for_crm=[2356345]})]
[UnbindGraph.NodeMessage(idType=unionId, idValue=unionId444, tableAndPKList={c_center_account_for_user_union=[343]}), UnbindGraph.NodeMessage(idType=userId, idValue=userId333, tableAndPKList={c_center_account_for_uc=[123], c_center_account_for_user_union=[343]}), UnbindGraph.NodeMessage(idType=mobile, idValue=557cd727e8f4d02ad2c295aa1d436e82, tableAndPKList={c_center_account_for_uc=[123]})]

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值