123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- package main
- import (
- "fmt"
- "log"
- "strings"
- )
- // CheckLegalRelationshipsByStep 分层级判断企业名单之间是否存在投资关系
- func (c *NebulaClient) CheckLegalRelationshipsByStep(names []string, deep, stepLimit int) (bool, []string, error) {
- if len(names) < 2 {
- return false, nil, fmt.Errorf("企业数量不足,至少需要两个")
- }
- visited := make(map[string]bool)
- pathMap := map[string][]string{} // key: 路径key,value: 节点名称列表
- pathStrMap := map[string]string{} // key: 路径key,value: 形式化路径描述
- currentLayer := names // 当前要处理的起点
- startToTarget := make(map[string]struct{})
- for _, a := range names {
- for _, b := range names {
- if a != b {
- startToTarget[a+"->"+b] = struct{}{}
- }
- }
- }
- for totalStep := 1; totalStep <= deep; totalStep += stepLimit {
- thisStep := min(stepLimit, deep-totalStep+1)
- var nextLayer []string
- for _, start := range currentLayer {
- // 组装目标企业(排除自己)
- targets := []string{}
- for _, t := range names {
- if t != start {
- targets = append(targets, fmt.Sprintf(`%s`, t))
- }
- }
- targetList := strings.Join(targets, ", ")
- query := fmt.Sprintf(`
- USE %s;
- MATCH p=(a:Legal{name:"%s"})-[*1..%d]-(b:Legal)
- WHERE b.Legal.name IN [%s]
- RETURN p LIMIT 20
- `, Table_Space, start, thisStep, targetList)
- resp, err := c.ExecuteWithReconnect(query)
- if err != nil || resp == nil || !resp.IsSucceed() {
- log.Printf("查询失败: %v, %s\n", err, resp.GetErrorMsg())
- continue
- }
- for _, row := range resp.GetRows() {
- if len(row.Values) == 0 || !row.Values[0].IsSetPVal() {
- continue
- }
- path := row.Values[0].GetPVal()
- var namesInPath []string
- var builder strings.Builder
- // 起点
- src := path.Src
- startName := ""
- if src != nil && src.Vid != nil && src.Vid.IsSetSVal() {
- vid := string(src.Vid.GetSVal())
- lea, err := getLegalByVid(c.session, vid)
- if err == nil && lea != nil {
- startName = lea.Name
- }
- }
- namesInPath = append(namesInPath, startName)
- builder.WriteString(startName)
- // 步骤
- for _, step := range path.Steps {
- dstName := ""
- if step.Dst != nil && step.Dst.Vid != nil && step.Dst.Vid.IsSetSVal() {
- vid := string(step.Dst.Vid.GetSVal())
- lea, err := getLegalByVid(c.session, vid)
- if err == nil && lea != nil {
- dstName = lea.Name
- }
- }
- if step.Type > 0 {
- builder.WriteString(" → ")
- } else if step.Type < 0 {
- builder.WriteString(" ← ")
- } else {
- builder.WriteString(" - ")
- }
- builder.WriteString(dstName)
- namesInPath = append(namesInPath, dstName)
- }
- // 存储路径
- key := generatePathKey(namesInPath)
- pathMap[key] = namesInPath
- pathStrMap[key] = builder.String()
- // 记录下一层继续遍历
- last := namesInPath[len(namesInPath)-1]
- if !visited[last] && !isInList(names, last) {
- visited[last] = true
- nextLayer = append(nextLayer, last)
- }
- }
- }
- currentLayer = nextLayer
- }
- // 去重,保留最长路径
- finalMap := map[string]string{}
- for k1, nodes1 := range pathMap {
- shouldAdd := true
- for k2, nodes2 := range pathMap {
- if k1 == k2 {
- continue
- }
- if isSubPath(nodes1, nodes2) || isSubPath(reverseSlice(nodes1), nodes2) {
- shouldAdd = false
- break
- }
- }
- if shouldAdd {
- finalMap[k1] = pathStrMap[k1]
- }
- }
- if len(finalMap) > 0 {
- var result []string
- for _, v := range finalMap {
- result = append(result, v)
- }
- return true, result, nil
- }
- return false, nil, nil
- }
- func isInList(arr []string, target string) bool {
- for _, v := range arr {
- if v == target {
- return true
- }
- }
- return false
- }
- func min(a, b int) int {
- if a < b {
- return a
- }
- return b
- }
|