数据血缘——基于单机版Neo4j实现数据血缘的管理

1 前言

        数据血缘是指在数据生命周期内,数据从产生到消亡的全过程中,各个阶段的数据流向、数据加工处理以及对应的数据元素和数据对象之间的关系和依赖关系。 数据血缘可以帮助我们跟踪数据的源头和去向,记录数据的使用情况,确保数据的合法性、完整性和安全性。更重要的是,数据血缘能够为数据治理、质量监控、风险控制、信息价值发现等方面提供强有力的支持,使数据的管理和使用更加精确、高效和透明。本篇文章将重点介绍数据血缘的概念、意义、实现方法及其在大数据时代的应用场景。

2 技术实现

2.1 图数据库选型

2.2 服务端代码

1、Maven依赖

        
        
            org.springframework.boot
            spring-boot-starter-data-neo4j
        
        
            
            org.neo4j.driver
            neo4j-java-driver
            1.7.2
        
        
            
            org.neo4j
            neo4j
            3.3.4
        

2、yml配置

spring:  
  data:
    neo4j:
      uri: bolt://localhost:7687  #本地单机版neo4j
      username: neo4j
      password: neo4jj

3、配置类

import org.aspectj.lang.annotation.Aspect;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
import org.springframework.data.transaction.ChainedTransactionManager;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Aspect
@Configuration
@DependsOn("sessionFactory")
@EnableTransactionManagement
public class TransactionAspect {

    ThreadLocal transactionStatusThreadLocal = new ThreadLocal<>();

    /**
     * 定义mysql事务管理器,必须有transactionManager作为默认事务管理器
     *
     * @param dataSource
     * @return
     */
    @Bean("transactionManager")
    @Primary
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * 定义neo4j事务管理器
     *
     * @param sessionFactory
     * @return
     */
    @Bean("neo4jTransactionManager")
    public Neo4jTransactionManager neo4jTransactionManager(SessionFactory sessionFactory) {
        return new Neo4jTransactionManager(sessionFactory);
    }

    @Autowired
    @Bean(name = "multiTransactionManager")
    public PlatformTransactionManager multiTransactionManager(
            Neo4jTransactionManager neo4jTransactionManager,
            DataSourceTransactionManager mysqlTransactionManager) {
        return new ChainedTransactionManager(
                neo4jTransactionManager, mysqlTransactionManager);
    }

}
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;

@Configuration
@EnableNeo4jRepositories(basePackages = "com.grg.data.meta.repository")
public class Neo4jConfig {

    @Bean("neo4jTransaction")
    public Neo4jTransactionManager neo4jTransactionManager(SessionFactory sessionFactory) {
        return new Neo4jTransactionManager(sessionFactory);
    }
}

4、节点类和关系类

import lombok.Builder;
import lombok.Data;
import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Property;

@Builder
@Data
@NodeEntity(label = "TABLE")
public class TableNode {

    @Id
    @GeneratedValue
    private Long id;

    @Property(name = "pid")
    private Long pid;

    @Property(name = "cnName")
    private String cnName;

    @Property(name = "name")
    private String name;

    @Property(name = "dbName")
    private String dbName;

    @Property(name = "dbCnName")
    private String dbCnName;

    @Property(name = "type")
    private String type;
}
import lombok.Data;
import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Property;

@Data
@NodeEntity(label = "COLUMN")
public class ColumnNode {

    @Id
    @GeneratedValue
    private Long id;

    @Property(name = "pid")
    private Long pid;

    @Property(name = "name")
    private String name;

    @Property(name = "cnName")
    private String cnName;
    
    @Property(name = "dbName")
    private String dbName;

    @Property(name = "dbCnName")
    private String dbCnName;

    @Property(name = "tableName")
    private String tableName;

    @Property(name = "tbCnName")
    private String tbCnName;

    @Property(name = "type")
    private String type;
}
import com.grg.data.meta.entity.neo4j.node.TableNode;
import lombok.Data;
import org.neo4j.ogm.annotation.*;

@Data
@RelationshipEntity(type = "tblood")
public class TableRelation {

    @Id
    @GeneratedValue
    private Long id;

    @StartNode
    private TableNode startNode;

    @EndNode
    private TableNode endNode;
}
import com.grg.data.meta.entity.neo4j.node.ColumnNode;
import lombok.Data;
import org.neo4j.ogm.annotation.*;


@Data
@RelationshipEntity(type = "blood")
public class ColumnRelation {

    @Id
    @GeneratedValue
    private Long id;

    @StartNode
    private ColumnNode startNode;

    @EndNode
    private ColumnNode endNode;
}
import com.grg.data.meta.entity.neo4j.node.ColumnNode;
import com.grg.data.meta.entity.neo4j.node.TableNode;
import lombok.Data;
import org.neo4j.ogm.annotation.*;

@Data
@RelationshipEntity(type = "has")
public class TableColumnRelation {

    @Id
    @GeneratedValue
    private Long id;

    @StartNode
    private TableNode tableNode;

    @EndNode
    private ColumnNode columnNode;

}

5、Repository类

import com.grgbanking.metadata.entity.neo4j.node.TableNode;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.Optional;
@Repository
public interface TableNodeRepository extends Neo4jRepository {

    @Query(value = "MATCH (start:TABLE)-[:tblood*1..20]-(end:TABLE) WHERE start.tableId={tableId} RETURN start,end")
    Iterable findAllByTableId(@Param("tableId") Long tableId);

    @Query(value = "MATCH (t:TABLE) WHERE t.tableId={tableId} RETURN t")
    Optional findByTableId(@Param("tableId") Long tableId);
}
import com.grgbanking.metadata.entity.neo4j.node.ColumnNode;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface ColumnNodeRepository extends Neo4jRepository {

    @Query("MATCH (t:TABLE)-[:has*1..2]-(c:COLUMN) WHERE t.tableId={tableId} RETURN c")
    Iterable findAllByTableId(@Param("tableId") Long tableId);
}

import com.grgbanking.metadata.entity.neo4j.relation.TableRelation;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface TableRelationRepository extends Neo4jRepository {

    @Query("match (a:TABLE), (b:TABLE) WHERE a.tableId = {startTableId} and b.tableId = {endTableId} create UNIQUE (a)-[r:tblood]->(b) return a,b,r")
    Optional matchTableRelation(@Param("startTableId") Long startTableId, @Param("endTableId") Long endTableId);

    @Query(value = "MATCH p=(a:TABLE)-[r:tblood*1..20]->(:TABLE) WHERE a.tableId={tableId} RETURN p")
    Iterable findRelationByTableId(@Param("tableId") Long tableId);

    @Query("match (a:TABLE)-[r:tblood]->(b:TABLE) WHERE a.tableId = {startTableId} and b.tableId = {endTableId} return a,b,r")
    Optional find2TablesRelation(@Param("startTableId") Long startTableId, @Param("endTableId") Long endTableId);
}
import com.grgbanking.metadata.entity.neo4j.relation.ColumnRelation;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface ColumnRelationRepository extends Neo4jRepository {

    @Query("MATCH (a:COLUMN), (b:COLUMN) WHERE a.columnId = {startColumnId} AND b.columnId = {endColumnId} CREATE UNIQUE (a)-[r:blood{fun:{fun}}]->(b) RETURN a,b,r")
    Optional matchColumnRelation(@Param("startColumnId") Long startColumnId, @Param("endColumnId") Long endColumnId, @Param("fun") String fun);

    @Query("MATCH c=(a:COLUMN)-[:blood*1..20]->(b:COLUMN) WHERE a.columnId={columnId} RETURN c")
    Iterable findAllByColumnId(@Param("columnId") Long columnId);

    @Query("MATCH (c1:COLUMN)-[r:blood]->(c2:COLUMN) WHERE c1.tableId = {startTableId} AND c2.tableId = {endTableId} RETURN c1,c2,r")
    Iterable find2TableColumnsRelation(@Param("startTableId") Long startTableId, @Param("endTableId") Long endTableId);
}
import com.grg.data.meta.entity.neo4j.relation.TableColumnRelation;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface TableColumnRelationRepository extends Neo4jRepository {
}

6、Serivce

import com.grgbanking.metadata.dto.*;
import com.grgbanking.metadata.entity.neo4j.node.ColumnNode;
import com.grgbanking.metadata.vo.req.TableBloodReq;
import com.grgbanking.metadata.vo.req.TableNodeReq;

import java.util.List;

public interface Neo4jService {

    void addTableColumnNodes(TableColumnsDTO tableColumnsDTO);

    void addTableRelationBatch(TableRelationDTO tableRelationDTO);

    void addColumnRelation(ColumnRelationDTO columnRelationDTO);

    void add2TableAndColumnRelation(TablesAndColumnsRelationDTO tablesAndColumnsRelationDTO);

    void addColumnNodes(List columnNodes, Long tableId);


    TableNodeRelationDTO getTableNodes(TableNodeReq tableNodeReq);

    ColumnNodeRelationDTO getColumnNodesByTableId(TableNodeReq tableNodeReq);

    TablesAndColumnsRelationDTO get2TablesColumnRelation(TableBloodReq tableBloodReq);
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.grgbanking.metadata.common.exception.ServerException;
import com.grgbanking.metadata.dto.*;
import com.grgbanking.metadata.entity.neo4j.node.ColumnNode;
import com.grgbanking.metadata.entity.neo4j.node.TableNode;
import com.grgbanking.metadata.entity.neo4j.relation.ColumnRelation;
import com.grgbanking.metadata.entity.neo4j.relation.TableColumnRelation;
import com.grgbanking.metadata.entity.neo4j.relation.TableRelation;
import com.grgbanking.metadata.repository.*;
import com.grgbanking.metadata.service.MetadataShowService;
import com.grgbanking.metadata.service.Neo4jService;
import com.grgbanking.metadata.utils.CollectionUtils;
import com.grgbanking.metadata.vo.req.TableBloodReq;
import com.grgbanking.metadata.vo.req.TableNodeReq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Slf4j
@Service
public class Neo4jServiceImpl implements Neo4jService {

    @Autowired
    private MetadataShowService metadataShowService;

    @Resource
    private TableNodeRepository tableNodeRepository;

    @Resource
    private ColumnNodeRepository columnNodeRepository;

    @Resource
    private TableRelationRepository tableRelationRepository;

    @Resource
    private ColumnRelationRepository columnRelationRepository;

    @Resource
    private TableColumnRelationRepository tableColumnRelationRepository;


    /**
     * 新增单个表节点及其字段节点并建立归属关系
     *
     * @param tableColumnsDTO
     */
    @Override
    @Transactional(value = "neo4jTransaction", rollbackFor = RuntimeException.class)
    public void addTableColumnNodes(TableColumnsDTO tableColumnsDTO) {
        try {
            // 新增表节点
            TableNode tableNode = new TableNode();
            BeanUtils.copyProperties(tableColumnsDTO, tableNode);
            tableNodeRepository.save(tableNode);

            // 新增字段节点
            List columnNodeDTOList = tableColumnsDTO.getColumnNodeDTOList();
            String json = JSON.toJSONString(columnNodeDTOList);
            List columnNodes = JSON.parseObject(json, new TypeReference>() {
            });
            Iterable columnNodeIterable = columnNodeRepository.saveAll(columnNodes);
            int columnCount = CollectionUtils.iterableCount(columnNodeIterable);
            if (columnNodeDTOList.size() != columnCount) {
                throw new ServerException("新增columnNode条数错误!");
            }

            // 新增表和字段关系
            List tableColumnRelations = new ArrayList<>();

            for (ColumnNode columnNode : columnNodes) {
                TableColumnRelation tableColumnRelation = TableColumnRelation.builder()
                        .tableNode(tableNode)
                        .columnNode(columnNode)
                        .build();
                tableColumnRelations.add(tableColumnRelation);
            }
            Iterable columnRelationIterable = tableColumnRelationRepository.saveAll(tableColumnRelations);
            int columnRelationCount = CollectionUtils.iterableCount(columnRelationIterable);
            if (tableColumnRelations.size() != columnRelationCount) {
                throw new ServerException("columnRelation新增数错误!");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 批量建立表节点血缘关系
     *
     * @param tableRelationDTO
     */
    @Override
    @Transactional(value = "neo4jTransaction", rollbackFor = RuntimeException.class)
    public void addTableRelationBatch(TableRelationDTO tableRelationDTO) {
        List tableRelationList = new ArrayList<>();
        try {
            Set tableRelationSet = tableRelationDTO.getTableRelationMapList().stream().collect(HashSet::new,
                    (cr, crm) -> {
                        cr.add(crm.getStartTableId().toString() + crm.getEndTableId().toString());
                    }, (s1, s2) -> {
                        s1.addAll(s2);
                    });
            if (tableRelationSet.size() != tableRelationDTO.getTableRelationMapList().size()) {
                throw new ServerException("tableRelationMapList里存在重复数据!");
            }

            tableRelationDTO.getTableRelationMapList().forEach(v -> {
                Optional optional = tableRelationRepository.matchTableRelation(v.getStartTableId(), v.getEndTableId());
                if (Objects.nonNull(optional) && optional.isPresent() && Objects.nonNull(optional.get())) {
                    tableRelationList.add(optional.get());
                }
            });
            if (tableRelationList.size() != tableRelationDTO.getTableRelationMapList().size()) {
                throw new ServerException("建立表关系异常!");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 批量建立字段节点血缘关系
     *
     * @param columnRelationDTO
     */
    @Override
    @Transactional(value = "neo4jTransaction", rollbackFor = RuntimeException.class)
    public void addColumnRelation(ColumnRelationDTO columnRelationDTO) {
        List columnRelationList = new ArrayList<>();
        try {
            Set columnRelationSet = columnRelationDTO.getColumnRelations().stream().collect(HashSet::new,
                    (cr, crm) -> {
                        cr.add(crm.getStartColumnId().toString() + crm.getEndColumnId().toString());
                    }, (s1, s2) -> {
                        s1.addAll(s2);
                    });
            if (columnRelationSet.size() != columnRelationDTO.getColumnRelations().size()) {
                throw new ServerException("ColumnRelations里存在重复数据!");
            }
            columnRelationDTO.getColumnRelations().forEach(v -> {
                Optional optional = columnRelationRepository.matchColumnRelation(v.getStartColumnId(), v.getEndColumnId(), v.getFun());
                if (Objects.nonNull(optional) && optional.isPresent() && Objects.nonNull(optional.get())) {
                    columnRelationList.add(optional.get());
                }
            });
            if (columnRelationList.size() != columnRelationDTO.getColumnRelations().size()) {
                throw new RuntimeException("columnRelation新增数错误!");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 批量新增两个表、字段节点及其所有血缘关系
     *
     * @param tablesAndColumnsRelationDTO
     */
    @Override
    @Transactional(value = "neo4jTransaction", rollbackFor = RuntimeException.class)
    public void add2TableAndColumnRelation(TablesAndColumnsRelationDTO tablesAndColumnsRelationDTO) {
        try {
            // 1、检查startTableNode、endTableNode是否存在,不存在则抛异常
            Optional startTableOptional = tableNodeRepository.findByTableId(tablesAndColumnsRelationDTO.getStartTableId());
            Optional endTableOptional = tableNodeRepository.findByTableId(tablesAndColumnsRelationDTO.getEndTableId());

            if (!startTableOptional.isPresent() || !endTableOptional.isPresent()) {
                throw new ServerException("表节点不存在");
            }

            // 2、建立表和表之间的血缘
            Optional tableRelationOptional = tableRelationRepository.matchTableRelation(tablesAndColumnsRelationDTO.getStartTableId(), tablesAndColumnsRelationDTO.getEndTableId());
            if (Objects.isNull(tableRelationOptional) || !tableRelationOptional.isPresent()) {
                throw new RuntimeException("tableRelation建立失败!");
            }

            // 3、批量建立字段之间的血缘
            ColumnRelationDTO columnRelationDTO = new ColumnRelationDTO();
            columnRelationDTO.setColumnRelations(tablesAndColumnsRelationDTO.getColumnRelations());
            this.addColumnRelation(columnRelationDTO);

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 新增column node并和table node绑定
     * @param columnNodes
     * @param tableId
     */
    @Override
    @Transactional(value = "neo4jTransaction", rollbackFor = RuntimeException.class)
    public void addColumnNodes(List columnNodes, Long tableId) {
        try {
            Optional tableNodeOptional = tableNodeRepository.findByTableId(tableId);
            if (!tableNodeOptional.isPresent()) {
                log.error("tableNode不存在,tableId:{}", tableId);
                throw new ServerException("tableNode不存在!");
            }

            // 新增column node
            Iterable iterable = columnNodeRepository.saveAll(columnNodes);
            Iterator iterator = iterable.iterator();
            int columnCount = CollectionUtils.iterableCount(iterable);
            if (columnNodes.size() != columnCount) {
                throw new ServerException("新增columnNode条数错误!");
            }

            // 新增table column relation
            List tableColumnRelations = new ArrayList<>();
            while (iterator.hasNext()) {
                ColumnNode columnNode = iterator.next();
                TableColumnRelation tableColumnRelation = TableColumnRelation.builder()
                        .tableNode(tableNodeOptional.get())
                        .columnNode(columnNode)
                        .build();
                tableColumnRelations.add(tableColumnRelation);
            }

            Iterable columnRelationIterable = tableColumnRelationRepository.saveAll(tableColumnRelations);
            int columnRelationCount = CollectionUtils.iterableCount(columnRelationIterable);
            if (tableColumnRelations.size() != columnRelationCount) {
                throw new ServerException("新增tableColumnRelation条数错误!");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e.getMessage());
        }
    }


    @Override
    public TableNodeRelationDTO getTableNodes(TableNodeReq tableNodeReq) {
        TableNodeRelationDTO tableNodeRelationDTO = new TableNodeRelationDTO();
        Iterable tableNodeIterable = tableNodeRepository.findAllByTableId(tableNodeReq.getTableId());
        Iterable tableRelationIterable = tableRelationRepository.findRelationByTableId(tableNodeReq.getTableId());
        tableNodeRelationDTO.setTableNodeIterable(tableNodeIterable);
        tableNodeRelationDTO.setTableRelationIterable(tableRelationIterable);
        return tableNodeRelationDTO;
    }

    @Override
    public ColumnNodeRelationDTO getColumnNodesByTableId(TableNodeReq tableNodeReq) {
        ColumnNodeRelationDTO columnNodeRelationDTO = new ColumnNodeRelationDTO();
        Map> columnRelationMap = new HashMap<>();

        Iterable columnNodeIterable = columnNodeRepository.findAllByTableId(tableNodeReq.getTableId());
        columnNodeRelationDTO.setColumnNodeIterable(columnNodeIterable);


        Iterator columnNodeIterator = columnNodeIterable.iterator();
        while (columnNodeIterator.hasNext()) {
            ColumnNode columnNode = columnNodeIterator.next();
            Iterable columnRelationIterable = columnRelationRepository.findAllByColumnId(columnNode.getColumnId());
            columnRelationMap.put(columnNode.getColumnId(), columnRelationIterable);
        }
        columnNodeRelationDTO.setColumnRelationMap(columnRelationMap);

        return columnNodeRelationDTO;
    }

    @Override
    public TablesAndColumnsRelationDTO get2TablesColumnRelation(TableBloodReq tableBloodReq) {
        TablesAndColumnsRelationDTO tablesAndColumnsRelationDTO = new TablesAndColumnsRelationDTO();
        List columnRelations = new ArrayList<>();

        Optional tableRelationOptional = tableRelationRepository.find2TablesRelation(tableBloodReq.getStartTableId(), tableBloodReq.getEndTableId());
        if (Objects.isNull(tableRelationOptional) || !tableRelationOptional.isPresent()) {
            return null;
        }

        tablesAndColumnsRelationDTO.setStartTableId(tableRelationOptional.get().getStartNode().getTableId());
        tablesAndColumnsRelationDTO.setStartTableCode(tableRelationOptional.get().getStartNode().getTableCode());
        tablesAndColumnsRelationDTO.setEndTableId(tableRelationOptional.get().getEndNode().getTableId());
        tablesAndColumnsRelationDTO.setEndTableCode(tableRelationOptional.get().getEndNode().getTableCode());

        Iterable columnRelationIterable = columnRelationRepository.find2TableColumnsRelation(tableBloodReq.getStartTableId(), tableBloodReq.getEndTableId());
        Iterator columnRelationIterator = columnRelationIterable.iterator();

        while (columnRelationIterator.hasNext()) {
            ColumnRelation columnRelation = columnRelationIterator.next();
            String fun = columnRelation.getFun();
            Long startColumnId = columnRelation.getStartNode().getColumnId();
            String startColumnCode = columnRelation.getStartNode().getColumnCode();
            Long endColumnId = columnRelation.getEndNode().getColumnId();
            String endColumnCode = columnRelation.getEndNode().getColumnCode();
            columnRelations.add(ColumnRelationMap.builder()
                    .startColumnId(startColumnId).endColumnId(endColumnId).fun(fun).startColumnCode(startColumnCode).endColumnCode(endColumnCode)
                    .build());
        }

        tablesAndColumnsRelationDTO.setColumnRelations(columnRelations);
        return tablesAndColumnsRelationDTO;
    }
}

7、Controller

import com.grgbanking.metadata.consts.Constants;
import com.grgbanking.metadata.dto.*;
import com.grgbanking.metadata.entity.neo4j.node.TableNode;
import com.grgbanking.metadata.service.Neo4jService;
import com.grgbanking.metadata.vo.ResultResponse;
import com.grgbanking.metadata.vo.req.TableBloodReq;
import com.grgbanking.metadata.vo.req.TableNodeReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

@Api(value = "/数据血缘", tags = "数据血缘", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@RestController
@RequestMapping(value = Constants.BASE_API_PATH + "/neo4j", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class Neo4jController {

    @Autowired
    private Neo4jService neo4jService;

   
    @ApiOperation(value = "新增单个表节点及其字段节点并建立归属关系", consumes = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/addTableColumnNodes", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity>> addTableColumnNodes(@Validated @RequestBody TableColumnsDTO tableColumnsDTO,
                                                                               HttpServletRequest request) {
        neo4jService.addTableColumnNodes(tableColumnsDTO);
        return ResponseEntity.ok(new ResultResponse().success());
    }

    @ApiOperation(value = "批量建立表节点血缘关系", consumes = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/addTableRelation", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity addTableRelation(@Validated @RequestBody TableRelationDTO tableRelationDTO, HttpServletRequest request) {

        neo4jService.addTableRelationBatch(tableRelationDTO);
        return ResponseEntity.ok(new ResultResponse().success());
    }

    @ApiOperation(value = "批量建立字段节点血缘关系", consumes = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/addColumnRelation", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity addColumnRelation(@Validated @RequestBody ColumnRelationDTO columnRelationDTO, HttpServletRequest request) {

        neo4jService.addColumnRelation(columnRelationDTO);
        return ResponseEntity.ok(new ResultResponse().success());
    }

    @ApiOperation(value = "批量新增两个表、字段节点及其所有血缘关系", consumes = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/add2TableAndColumnRelation", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity add2TableAndColumnRelation(@Validated @RequestBody TablesAndColumnsRelationDTO tablesAndColumnsRelationDTO, HttpServletRequest request) {

        neo4jService.add2TableAndColumnRelation(tablesAndColumnsRelationDTO);
        return ResponseEntity.ok(new ResultResponse().success());
    }

    /*************************-------以下是查询接口-----------*******************************/

    @ApiOperation(value = "获取表节点及其表血缘关系", consumes = MediaType.APPLICATION_JSON_VALUE)
    @GetMapping(value = "/getTableNodes")
    public ResponseEntity> getTableNodes(@Validated TableNodeReq tableNodeReq, HttpServletRequest request) {
        TableNodeRelationDTO tableNodeRelationDTO = neo4jService.getTableNodes(tableNodeReq);
        return ResponseEntity.ok(new ResultResponse().success(tableNodeRelationDTO));
    }

    @ApiOperation(value = "获取某个表下所有字段节点", consumes = MediaType.APPLICATION_JSON_VALUE)
    @GetMapping(value = "/getColumnNodesByTableId")
    public ResponseEntity> getColumnNodesByTableId(@Validated TableNodeReq tableNodeReq, HttpServletRequest request) {
        ColumnNodeRelationDTO columnNodeRelationDTO = neo4jService.getColumnNodesByTableId(tableNodeReq);
        return ResponseEntity.ok(new ResultResponse().success(columnNodeRelationDTO));
    }

    @ApiOperation(value = "获取表之间的血缘关系及其字段之间的血缘关系", consumes = MediaType.APPLICATION_JSON_VALUE)
    @GetMapping(value = "/get2TablesColumnRelation")
    public ResponseEntity> get2TablesColumnRelation(@Validated TableBloodReq tableBloodReq, HttpServletRequest request) {
        TablesAndColumnsRelationDTO tablesAndColumnsRelationDTO = neo4jService.get2TablesColumnRelation(tableBloodReq);
        return ResponseEntity.ok(new ResultResponse().success(tablesAndColumnsRelationDTO));
    }
}

3 思考和总结

本文章仅仅提供了Neo4j做数据血缘的设计,提供Restful-Api 对数据血缘的增删查改,至于数据血缘的解析,需要先在另外的模块进行处理。

你可能感兴趣的:(大数据,spring,boot,neo4j,数据血缘,图数据库)