github.com/GuanceCloud/cliutils@v1.1.21/pipeline/ptinput/refertable/query.go (about)

     1  // Unless explicitly stated otherwise all files in this repository are licensed
     2  // under the MIT License.
     3  // This product includes software developed at Guance Cloud (https://www.guance.com/).
     4  // Copyright 2021-present Guance, Inc.
     5  
     6  package refertable
     7  
     8  import (
     9  	"math"
    10  )
    11  
    12  func query(index map[string]map[any][]int,
    13  	keys []string, values []any, count int,
    14  ) ([]int, bool) {
    15  	if len(keys) != len(values) {
    16  		return nil, false
    17  	}
    18  
    19  	// index 数据索引递增排序
    20  	tmp := [][]int{}
    21  
    22  	// key 中结果数量最少的
    23  	var startDataIdxs []int
    24  
    25  	headerDataIdx := 0
    26  	tailDataIdx := math.MaxInt
    27  
    28  	for kIdx, key := range keys {
    29  		// value map
    30  		m, ok := index[key]
    31  		if !ok {
    32  			return nil, false
    33  		}
    34  		// value -> index
    35  		dIdxs := m[values[kIdx]]
    36  		lenDIdxs := len(dIdxs)
    37  		switch lenDIdxs {
    38  		case 0:
    39  			return nil, false
    40  		default:
    41  			// max header
    42  			if dIdxs[0] > headerDataIdx {
    43  				headerDataIdx = dIdxs[0]
    44  			}
    45  			// min tail
    46  			if dIdxs[lenDIdxs-1] < tailDataIdx {
    47  				tailDataIdx = dIdxs[lenDIdxs-1]
    48  			}
    49  
    50  			if len(startDataIdxs) == 0 {
    51  				startDataIdxs = dIdxs
    52  				break
    53  			}
    54  			if len(dIdxs) < len(startDataIdxs) {
    55  				tmp = append(tmp, startDataIdxs)
    56  				startDataIdxs = dIdxs
    57  			} else {
    58  				tmp = append(tmp, dIdxs)
    59  			}
    60  		}
    61  	}
    62  
    63  	var ret []int
    64  	for _, idx := range startDataIdxs {
    65  		// 取相交段
    66  		if idx < headerDataIdx {
    67  			continue
    68  		}
    69  		if idx > tailDataIdx {
    70  			break
    71  		}
    72  
    73  		flag := true
    74  		// 取相交项
    75  		for _, idxs := range tmp {
    76  			if _, ok := binSearch(idxs, idx); !ok {
    77  				flag = false
    78  				break
    79  			}
    80  		}
    81  		if flag {
    82  			ret = append(ret, idx)
    83  			// count = 0, 取全部结果
    84  			if len(ret) == count {
    85  				break
    86  			}
    87  		}
    88  	}
    89  	if len(ret) > 0 {
    90  		return ret, true
    91  	}
    92  	return nil, false
    93  }
    94  
    95  func binSearch(li []int, s int) (int, bool) {
    96  	start := 0
    97  	end := len(li) - 1
    98  	for start <= end {
    99  		mid := (start + end) / 2
   100  		v := li[mid]
   101  		switch {
   102  		case s == v:
   103  			return mid, true
   104  		case s > v:
   105  			start = mid + 1
   106  		case s < v:
   107  			end = mid - 1
   108  		}
   109  	}
   110  	return 0, false
   111  }