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 }