feat:implement search support for abbreviated token ranges (e.g., token4-token7)
This commit is contained in:
parent
c92cee9575
commit
0add3cf6db
|
|
@ -33,4 +33,5 @@ const (
|
||||||
const (
|
const (
|
||||||
// MaxIdentifyHierarchy define max data indentify syntax hierarchy
|
// MaxIdentifyHierarchy define max data indentify syntax hierarchy
|
||||||
MaxIdentifyHierarchy = 7
|
MaxIdentifyHierarchy = 7
|
||||||
|
IdentifyHierarchy = 4
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -45,3 +45,46 @@ const (
|
||||||
// SearchLinkDelAction define search link del action
|
// SearchLinkDelAction define search link del action
|
||||||
SearchLinkDelAction = "del"
|
SearchLinkDelAction = "del"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// RecommendHierarchyType define the hierarchy levels used for redis recommend search
|
||||||
|
type RecommendHierarchyType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// GridRecommendHierarchyType define grid hierarch for redis recommend search
|
||||||
|
GridRecommendHierarchyType RecommendHierarchyType = iota + 1
|
||||||
|
// ZoneRecommendHierarchyType define zone hierarch for redis recommend search
|
||||||
|
ZoneRecommendHierarchyType
|
||||||
|
// StationRecommendHierarchyType define station hierarch for redis recommend search
|
||||||
|
StationRecommendHierarchyType
|
||||||
|
// CompNSPathRecommendHierarchyType define component nspath hierarch for redis recommend search
|
||||||
|
CompNSPathRecommendHierarchyType
|
||||||
|
// CompTagRecommendHierarchyType define component tag hierarch for redis recommend search
|
||||||
|
CompTagRecommendHierarchyType
|
||||||
|
// ConfigRecommendHierarchyType define config hierarch for redis recommend search
|
||||||
|
ConfigRecommendHierarchyType
|
||||||
|
// MeasTagRecommendHierarchyType define measurement tag hierarch for redis recommend search
|
||||||
|
MeasTagRecommendHierarchyType
|
||||||
|
)
|
||||||
|
|
||||||
|
// String implements fmt.Stringer interface and returns the string representation of the type.
|
||||||
|
func (r RecommendHierarchyType) String() string {
|
||||||
|
switch r {
|
||||||
|
case GridRecommendHierarchyType:
|
||||||
|
return "grid_tag"
|
||||||
|
case ZoneRecommendHierarchyType:
|
||||||
|
return "zone_tag"
|
||||||
|
case StationRecommendHierarchyType:
|
||||||
|
return "station_tag"
|
||||||
|
case CompNSPathRecommendHierarchyType:
|
||||||
|
return "comp_nspath"
|
||||||
|
case CompTagRecommendHierarchyType:
|
||||||
|
return "comp_tag"
|
||||||
|
case ConfigRecommendHierarchyType:
|
||||||
|
return "config"
|
||||||
|
case MeasTagRecommendHierarchyType:
|
||||||
|
return "meas_tag"
|
||||||
|
default:
|
||||||
|
// 返回一个包含原始数值的默认字符串,以便于调试
|
||||||
|
return "unknown_recommend_type(" + string(rune(r)) + ")"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -55,8 +55,11 @@ func MeasurementRecommendHandler(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
recommends, isFuzzy, err := model.RedisSearchRecommend(c, request.Input)
|
recommendResults := model.RedisSearchRecommend(c, request.Input)
|
||||||
if err != nil {
|
payloads := make([]network.MeasurementRecommendPayload, 0, len(recommendResults))
|
||||||
|
for _, recommendResult := range recommendResults {
|
||||||
|
if recommendResult.Err != nil {
|
||||||
|
err := recommendResult.Err
|
||||||
logger.Error(c, "failed to get recommend data from redis", "input", request.Input, "error", err)
|
logger.Error(c, "failed to get recommend data from redis", "input", request.Input, "error", err)
|
||||||
c.JSON(http.StatusOK, network.FailureResponse{
|
c.JSON(http.StatusOK, network.FailureResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
|
|
@ -69,7 +72,8 @@ func MeasurementRecommendHandler(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var finalOffset int
|
var finalOffset int
|
||||||
if isFuzzy {
|
recommends := recommendResult.QueryDatas
|
||||||
|
if recommendResult.IsFuzzy {
|
||||||
var maxOffset int
|
var maxOffset int
|
||||||
for index, recommend := range recommends {
|
for index, recommend := range recommends {
|
||||||
offset := util.GetLongestCommonPrefixLength(request.Input, recommend)
|
offset := util.GetLongestCommonPrefixLength(request.Input, recommend)
|
||||||
|
|
@ -102,13 +106,16 @@ func MeasurementRecommendHandler(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, network.SuccessResponse{
|
payloads = append(payloads, network.MeasurementRecommendPayload{
|
||||||
Code: http.StatusOK,
|
|
||||||
Msg: "success",
|
|
||||||
Payload: &network.MeasurementRecommendPayload{
|
|
||||||
Input: request.Input,
|
Input: request.Input,
|
||||||
Offset: finalOffset,
|
Offset: finalOffset,
|
||||||
RecommendedList: resultRecommends,
|
RecommendedList: resultRecommends,
|
||||||
},
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, network.SuccessResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
Msg: "success",
|
||||||
|
Payload: &payloads,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -10,12 +11,22 @@ import (
|
||||||
"modelRT/constants"
|
"modelRT/constants"
|
||||||
"modelRT/diagram"
|
"modelRT/diagram"
|
||||||
"modelRT/logger"
|
"modelRT/logger"
|
||||||
|
"modelRT/util"
|
||||||
|
|
||||||
"github.com/RediSearch/redisearch-go/v2/redisearch"
|
"github.com/RediSearch/redisearch-go/v2/redisearch"
|
||||||
redigo "github.com/gomodule/redigo/redis"
|
redigo "github.com/gomodule/redigo/redis"
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SearchResult define struct to store redis query recommend search result
|
||||||
|
type SearchResult struct {
|
||||||
|
// input redis key, used to distinguish which goroutine the result belongs to
|
||||||
|
RecommendType constants.RecommendHierarchyType
|
||||||
|
QueryDatas []string
|
||||||
|
IsFuzzy bool
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
var ac *redisearch.Autocompleter
|
var ac *redisearch.Autocompleter
|
||||||
|
|
||||||
// InitAutocompleterWithPool define func of initialize the Autocompleter with redigo pool
|
// InitAutocompleterWithPool define func of initialize the Autocompleter with redigo pool
|
||||||
|
|
@ -23,76 +34,289 @@ func InitAutocompleterWithPool(pool *redigo.Pool) {
|
||||||
ac = redisearch.NewAutocompleterFromPool(pool, constants.RedisSearchDictName)
|
ac = redisearch.NewAutocompleterFromPool(pool, constants.RedisSearchDictName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func levelOneRedisSearch(ctx context.Context, rdb *redis.Client, hierarchy constants.RecommendHierarchyType, searchInput string, searchRedisKey string, fanInChan chan SearchResult) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
logger.Error(ctx, "searchFunc panicked", "panic", r)
|
||||||
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: nil,
|
||||||
|
IsFuzzy: false,
|
||||||
|
Err: errors.New("search goroutine panicked"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
exists, err := rdb.SIsMember(ctx, searchRedisKey, searchInput).Result()
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(ctx, "redis membership check failed", "key", searchRedisKey, "member", searchInput, "op", "SIsMember", "error", err)
|
||||||
|
|
||||||
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: nil,
|
||||||
|
IsFuzzy: false,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// the input key is the complete hierarchical value
|
||||||
|
if exists {
|
||||||
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: []string{"."},
|
||||||
|
IsFuzzy: false,
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// process fuzzy search result
|
||||||
|
recommends, err := runFuzzySearch(ctx, searchInput, "", hierarchy)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(ctx, fmt.Sprintf("fuzzy search failed for %s hierarchical", util.GetLevelStrByRdsKey(searchRedisKey)), "search_input", searchInput, "error", err)
|
||||||
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: nil,
|
||||||
|
IsFuzzy: false,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(recommends) > 0 {
|
||||||
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: recommends,
|
||||||
|
IsFuzzy: true,
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: []string{},
|
||||||
|
IsFuzzy: true,
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// RedisSearchRecommend define func of redis search by input string and return recommend results
|
// RedisSearchRecommend define func of redis search by input string and return recommend results
|
||||||
func RedisSearchRecommend(ctx context.Context, input string) ([]string, bool, error) {
|
func RedisSearchRecommend(ctx context.Context, input string) map[string]SearchResult {
|
||||||
rdb := diagram.GetRedisClientInstance()
|
rdb := diagram.GetRedisClientInstance()
|
||||||
|
|
||||||
if input == "" {
|
if input == "" {
|
||||||
|
fanInChan := make(chan SearchResult, 2)
|
||||||
// return all grid tagname
|
// return all grid tagname
|
||||||
return getKeyBySpecificsLevel(ctx, rdb, 1, input)
|
go getAllKeyByGridLevel(ctx, rdb, fanInChan)
|
||||||
|
// return all component nspath
|
||||||
|
go getAllKeyByNSPathLevel(ctx, rdb, fanInChan)
|
||||||
|
results := make(map[string]SearchResult)
|
||||||
|
for range 2 {
|
||||||
|
result := <-fanInChan
|
||||||
|
if result.Err != nil {
|
||||||
|
logger.Error(ctx, "return all keys at the special level from redis failed", "query_key", result.RecommendType, "error", result.Err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.RecommendType == constants.CompNSPathRecommendHierarchyType {
|
||||||
|
// TODO 增加 nspath 过滤
|
||||||
|
fmt.Println("process nspath")
|
||||||
|
}
|
||||||
|
results[result.RecommendType.String()] = result
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
inputSlice := strings.Split(input, ".")
|
inputSlice := strings.Split(input, ".")
|
||||||
inputSliceLen := len(inputSlice)
|
inputSliceLen := len(inputSlice)
|
||||||
|
|
||||||
|
fanInChan := make(chan SearchResult, 4)
|
||||||
switch inputSliceLen {
|
switch inputSliceLen {
|
||||||
case 1:
|
case 1:
|
||||||
|
searchInput := inputSlice[0]
|
||||||
// grid tagname search
|
// grid tagname search
|
||||||
gridSearchInput := inputSlice[0]
|
go levelOneRedisSearch(ctx, rdb, constants.GridRecommendHierarchyType, searchInput, constants.RedisAllGridSetKey, fanInChan)
|
||||||
gridExists, err := rdb.SIsMember(ctx, constants.RedisAllGridSetKey, gridSearchInput).Result()
|
// component nspath search
|
||||||
if err != nil {
|
go levelOneRedisSearch(ctx, rdb, constants.CompNSPathRecommendHierarchyType, searchInput, constants.RedisAllCompNSPathSetKey, fanInChan)
|
||||||
logger.Error(ctx, "check grid key exist failed ", "grid_key", input, "error", err)
|
|
||||||
return []string{}, false, err
|
results := make(map[string]SearchResult)
|
||||||
|
// TODO 后续根据支持的数据标识语法长度,进行值的变更
|
||||||
|
for range 2 {
|
||||||
|
result := <-fanInChan
|
||||||
|
if result.Err != nil {
|
||||||
|
logger.Error(ctx, "exec redis fuzzy search by key :%s failed", "query_key", result.RecommendType, "error", result.Err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if result.RecommendType == constants.CompNSPathRecommendHierarchyType {
|
||||||
|
// TODO 增加 nspath 过滤
|
||||||
|
fmt.Println("process nspath")
|
||||||
|
}
|
||||||
|
results[result.RecommendType.String()] = result
|
||||||
}
|
}
|
||||||
|
|
||||||
if gridExists {
|
return results
|
||||||
return []string{"."}, false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// start grid tagname fuzzy search
|
|
||||||
recommends, err := runFuzzySearch(ctx, gridSearchInput, "", inputSliceLen)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "fuzzy search failed for level 1", "search_input", gridSearchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(recommends) > 0 {
|
|
||||||
return recommends, true, nil
|
|
||||||
}
|
|
||||||
return []string{}, true, nil
|
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
return handleLevelFuzzySearch(ctx, rdb, 2, constants.RedisAllZoneSetKey, inputSlice)
|
// zone tagname search
|
||||||
case 3:
|
go handleLevelFuzzySearch(ctx, rdb, constants.ZoneRecommendHierarchyType, constants.RedisAllZoneSetKey, inputSlice, fanInChan)
|
||||||
return handleLevelFuzzySearch(ctx, rdb, 3, constants.RedisAllStationSetKey, inputSlice)
|
// component tagname search
|
||||||
case 4:
|
go handleLevelFuzzySearch(ctx, rdb, constants.CompTagRecommendHierarchyType, constants.RedisAllCompTagSetKey, inputSlice, fanInChan)
|
||||||
return handleLevelFuzzySearch(ctx, rdb, 4, constants.RedisAllCompNSPathSetKey, inputSlice)
|
results := make(map[string]SearchResult)
|
||||||
case 5:
|
for range 2 {
|
||||||
return handleLevelFuzzySearch(ctx, rdb, 5, constants.RedisAllCompTagSetKey, inputSlice)
|
result := <-fanInChan
|
||||||
case 6:
|
if result.Err != nil {
|
||||||
return handleLevelFuzzySearch(ctx, rdb, 6, constants.RedisAllConfigSetKey, inputSlice)
|
logger.Error(ctx, "query all keys at the special level from redis failed", "query_key", result.RecommendType, "error", result.Err)
|
||||||
case 7:
|
continue
|
||||||
return handleLevelFuzzySearch(ctx, rdb, 7, constants.RedisAllMeasTagSetKey, inputSlice)
|
}
|
||||||
|
results[result.RecommendType.String()] = result
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
case 3:
|
||||||
|
// station tanname search
|
||||||
|
go handleLevelFuzzySearch(ctx, rdb, constants.StationRecommendHierarchyType, constants.RedisAllStationSetKey, inputSlice, fanInChan)
|
||||||
|
// config search
|
||||||
|
go handleLevelFuzzySearch(ctx, rdb, constants.ConfigRecommendHierarchyType, constants.RedisAllConfigSetKey, inputSlice, fanInChan)
|
||||||
|
|
||||||
|
results := make(map[string]SearchResult)
|
||||||
|
for range 2 {
|
||||||
|
result := <-fanInChan
|
||||||
|
if result.Err != nil {
|
||||||
|
logger.Error(ctx, "query all keys at the special level from redis failed", "query_key", result.RecommendType, "error", result.Err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
results[result.RecommendType.String()] = result
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
case 4:
|
||||||
|
// component nspath search
|
||||||
|
go handleLevelFuzzySearch(ctx, rdb, constants.CompNSPathRecommendHierarchyType, constants.RedisAllCompNSPathSetKey, inputSlice, fanInChan)
|
||||||
|
// measurement tagname search
|
||||||
|
go handleLevelFuzzySearch(ctx, rdb, constants.MeasTagRecommendHierarchyType, constants.RedisAllConfigSetKey, inputSlice, fanInChan)
|
||||||
|
|
||||||
|
results := make(map[string]SearchResult)
|
||||||
|
for range 2 {
|
||||||
|
result := <-fanInChan
|
||||||
|
if result.Err != nil {
|
||||||
|
logger.Error(ctx, "query all keys at the special level from redis failed", "query_key", result.RecommendType, "error", result.Err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
results[result.RecommendType.String()] = result
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
case 5:
|
||||||
|
// component tagname search
|
||||||
|
go handleLevelFuzzySearch(ctx, rdb, constants.CompTagRecommendHierarchyType, constants.RedisAllCompTagSetKey, inputSlice, fanInChan)
|
||||||
|
|
||||||
|
results := make(map[string]SearchResult)
|
||||||
|
for range 2 {
|
||||||
|
result := <-fanInChan
|
||||||
|
if result.Err != nil {
|
||||||
|
logger.Error(ctx, "query all keys at the special level from redis failed", "query_key", result.RecommendType, "error", result.Err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
results[result.RecommendType.String()] = result
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
case 6:
|
||||||
|
// config search
|
||||||
|
go handleLevelFuzzySearch(ctx, rdb, constants.ConfigRecommendHierarchyType, constants.RedisAllConfigSetKey, inputSlice, fanInChan)
|
||||||
|
|
||||||
|
results := make(map[string]SearchResult)
|
||||||
|
for range 2 {
|
||||||
|
result := <-fanInChan
|
||||||
|
if result.Err != nil {
|
||||||
|
logger.Error(ctx, "query all keys at the special level from redis failed", "query_key", result.RecommendType, "error", result.Err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
results[result.RecommendType.String()] = result
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
case 7:
|
||||||
|
// measurement tagname search
|
||||||
|
go handleLevelFuzzySearch(ctx, rdb, constants.MeasTagRecommendHierarchyType, constants.RedisAllMeasTagSetKey, inputSlice, fanInChan)
|
||||||
|
|
||||||
|
results := make(map[string]SearchResult)
|
||||||
|
for range 2 {
|
||||||
|
result := <-fanInChan
|
||||||
|
if result.Err != nil {
|
||||||
|
logger.Error(ctx, "query all keys at the special level from redis failed", "query_key", result.RecommendType, "error", result.Err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
results[result.RecommendType.String()] = result
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
default:
|
default:
|
||||||
logger.Error(ctx, "unsupport length of search input", "input_len", inputSliceLen)
|
logger.Error(ctx, "unsupport length of search input", "input_len", inputSliceLen)
|
||||||
return []string{}, false, nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getKeyBySpecificsLevel(ctx context.Context, rdb *redis.Client, inputLen int, input string) ([]string, bool, error) {
|
func queryMemberFromSpecificsLevel(ctx context.Context, rdb *redis.Client, hierarchy constants.RecommendHierarchyType, keyPrefix string) ([]string, error) {
|
||||||
queryKey := getSpecificKeyByLength(inputLen, input)
|
queryKey := getSpecificKeyByLength(hierarchy, keyPrefix)
|
||||||
results, err := rdb.SMembers(ctx, queryKey).Result()
|
return rdb.SMembers(ctx, queryKey).Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAllKeyByGridLevel(ctx context.Context, rdb *redis.Client, fanInChan chan SearchResult) {
|
||||||
|
queryKey := constants.RedisAllGridSetKey
|
||||||
|
hierarchy := constants.GridRecommendHierarchyType
|
||||||
|
members, err := rdb.SMembers(ctx, queryKey).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []string{}, false, fmt.Errorf("get all keys failed, error: %w", err)
|
logger.Error(ctx, "get all members by special key failed", "key", queryKey, "op", "SMembers", "error", err)
|
||||||
|
|
||||||
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: nil,
|
||||||
|
IsFuzzy: false,
|
||||||
|
Err: err,
|
||||||
}
|
}
|
||||||
return results, false, nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func combineQueryResultByInput(inputSliceLen int, inputSlice []string, queryResults []string) []string {
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: members,
|
||||||
|
IsFuzzy: false,
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAllKeyByNSPathLevel(ctx context.Context, rdb *redis.Client, fanInChan chan SearchResult) {
|
||||||
|
queryKey := constants.RedisAllCompNSPathSetKey
|
||||||
|
hierarchy := constants.CompNSPathRecommendHierarchyType
|
||||||
|
members, err := rdb.SMembers(ctx, queryKey).Result()
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(ctx, "get all members by special key failed", "key", queryKey, "op", "SMembers", "error", err)
|
||||||
|
|
||||||
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: nil,
|
||||||
|
IsFuzzy: false,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: members,
|
||||||
|
IsFuzzy: false,
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func combineQueryResultByInput(hierarchy constants.RecommendHierarchyType, inputSlice []string, queryResults []string) []string {
|
||||||
prefixs := make([]string, 0, len(inputSlice))
|
prefixs := make([]string, 0, len(inputSlice))
|
||||||
recommandResults := make([]string, 0, len(queryResults))
|
recommandResults := make([]string, 0, len(queryResults))
|
||||||
switch inputSliceLen {
|
switch hierarchy {
|
||||||
|
// TODO 优化 case 为常量
|
||||||
case 2:
|
case 2:
|
||||||
prefixs = []string{inputSlice[0]}
|
prefixs = []string{inputSlice[0]}
|
||||||
case 3:
|
case 3:
|
||||||
|
|
@ -119,30 +343,32 @@ func combineQueryResultByInput(inputSliceLen int, inputSlice []string, queryResu
|
||||||
return recommandResults
|
return recommandResults
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSpecificKeyByLength(inputLen int, input string) string {
|
func getSpecificKeyByLength(hierarchy constants.RecommendHierarchyType, keyPrefix string) string {
|
||||||
switch inputLen {
|
switch hierarchy {
|
||||||
|
// TODO 优化 case 为常量
|
||||||
case 1:
|
case 1:
|
||||||
return constants.RedisAllGridSetKey
|
return constants.RedisAllGridSetKey
|
||||||
case 2:
|
case 2:
|
||||||
return fmt.Sprintf(constants.RedisSpecGridZoneSetKey, input)
|
return fmt.Sprintf(constants.RedisSpecGridZoneSetKey, keyPrefix)
|
||||||
case 3:
|
case 3:
|
||||||
return fmt.Sprintf(constants.RedisSpecZoneStationSetKey, input)
|
return fmt.Sprintf(constants.RedisSpecZoneStationSetKey, keyPrefix)
|
||||||
case 4:
|
case 4:
|
||||||
return fmt.Sprintf(constants.RedisSpecStationCompNSPATHSetKey, input)
|
return fmt.Sprintf(constants.RedisSpecStationCompNSPATHSetKey, keyPrefix)
|
||||||
case 5:
|
case 5:
|
||||||
return fmt.Sprintf(constants.RedisSpecStationCompTagSetKey, input)
|
return fmt.Sprintf(constants.RedisSpecStationCompTagSetKey, keyPrefix)
|
||||||
case 6:
|
case 6:
|
||||||
return constants.RedisAllConfigSetKey
|
return constants.RedisAllConfigSetKey
|
||||||
case 7:
|
case 7:
|
||||||
return fmt.Sprintf(constants.RedisSpecCompTagMeasSetKey, input)
|
return fmt.Sprintf(constants.RedisSpecCompTagMeasSetKey, keyPrefix)
|
||||||
default:
|
default:
|
||||||
return constants.RedisAllGridSetKey
|
return constants.RedisAllGridSetKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleLevelFuzzySearch define func to process recommendation logic for specific levels(level >= 2)
|
// handleLevelFuzzySearch define func to process recommendation logic for specific levels(level >= 2)
|
||||||
func handleLevelFuzzySearch(ctx context.Context, rdb *redis.Client, hierarchy int, keySetKey string, inputSlice []string) ([]string, bool, error) {
|
func handleLevelFuzzySearch(ctx context.Context, rdb *redis.Client, hierarchy constants.RecommendHierarchyType, redisSetKey string, inputSlice []string, fanInChan chan SearchResult) {
|
||||||
searchInputIndex := hierarchy - 1
|
inputSliceLen := len(inputSlice)
|
||||||
|
searchInputIndex := inputSliceLen - 1
|
||||||
searchInput := inputSlice[searchInputIndex]
|
searchInput := inputSlice[searchInputIndex]
|
||||||
searchPrefix := strings.Join(inputSlice[0:searchInputIndex], ".")
|
searchPrefix := strings.Join(inputSlice[0:searchInputIndex], ".")
|
||||||
|
|
||||||
|
|
@ -153,44 +379,85 @@ func handleLevelFuzzySearch(ctx context.Context, rdb *redis.Client, hierarchy in
|
||||||
specificalKey = inputSlice[specificalKeyIndex]
|
specificalKey = inputSlice[specificalKeyIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
allResults, isFuzzy, err := getKeyBySpecificsLevel(ctx, rdb, hierarchy, specificalKey)
|
members, err := queryMemberFromSpecificsLevel(ctx, rdb, hierarchy, specificalKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []string{}, false, err
|
logger.Error(ctx, "query members from redis by special key failed", "key", specificalKey, "member", searchInput, "op", "SMember", "error", err)
|
||||||
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: nil,
|
||||||
|
IsFuzzy: false,
|
||||||
|
Err: err,
|
||||||
}
|
}
|
||||||
recommandResults := combineQueryResultByInput(hierarchy, inputSlice, allResults)
|
return
|
||||||
return recommandResults, isFuzzy, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
keyExists, err := rdb.SIsMember(ctx, keySetKey, searchInput).Result()
|
recommandResults := combineQueryResultByInput(hierarchy, inputSlice, members)
|
||||||
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: recommandResults,
|
||||||
|
IsFuzzy: false,
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
keyExists, err := rdb.SIsMember(ctx, redisSetKey, searchInput).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(ctx, "check key exist failed ", "key", searchInput, "error", err)
|
logger.Error(ctx, "check key exist from redis set failed ", "key", redisSetKey, "error", err)
|
||||||
return []string{}, false, err
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: nil,
|
||||||
|
IsFuzzy: false,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if keyExists {
|
if keyExists {
|
||||||
if hierarchy == constants.MaxIdentifyHierarchy {
|
var QueryData []string
|
||||||
return []string{""}, false, nil
|
if hierarchy == constants.MaxIdentifyHierarchy || (hierarchy == constants.IdentifyHierarchy && redisSetKey == constants.RedisAllMeasTagSetKey) {
|
||||||
|
QueryData = []string{""}
|
||||||
|
} else {
|
||||||
|
QueryData = []string{"."}
|
||||||
}
|
}
|
||||||
return []string{"."}, false, nil
|
|
||||||
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: QueryData,
|
||||||
|
IsFuzzy: false,
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// start redis fuzzy search
|
// start redis fuzzy search
|
||||||
recommends, err := runFuzzySearch(ctx, searchInput, searchPrefix, hierarchy)
|
recommends, err := runFuzzySearch(ctx, searchInput, searchPrefix, hierarchy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(ctx, "fuzzy search failed by hierarchy", "hierarchy", hierarchy, "search_input", searchInput, "error", err)
|
logger.Error(ctx, "fuzzy search failed by hierarchy", "hierarchy", hierarchy, "search_input", searchInput, "error", err)
|
||||||
return []string{}, false, err
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: nil,
|
||||||
|
IsFuzzy: false,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(recommends) == 0 {
|
if len(recommends) == 0 {
|
||||||
logger.Error(ctx, "fuzzy search without result", "hierarchy", hierarchy, "search_input", searchInput, "error", err)
|
logger.Error(ctx, "fuzzy search without result", "hierarchy", hierarchy, "search_input", searchInput, "error", err)
|
||||||
return []string{}, true, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return recommends, true, nil
|
fanInChan <- SearchResult{
|
||||||
|
RecommendType: hierarchy,
|
||||||
|
QueryDatas: recommends,
|
||||||
|
IsFuzzy: true,
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// runFuzzySearch define func to process redis fuzzy search
|
// runFuzzySearch define func to process redis fuzzy search
|
||||||
func runFuzzySearch(ctx context.Context, searchInput string, searchPrefix string, inputSliceLen int) ([]string, error) {
|
func runFuzzySearch(ctx context.Context, searchInput string, searchPrefix string, hierarchy constants.RecommendHierarchyType) ([]string, error) {
|
||||||
searchInputLen := len(searchInput)
|
searchInputLen := len(searchInput)
|
||||||
|
|
||||||
for searchInputLen != 0 {
|
for searchInputLen != 0 {
|
||||||
|
|
@ -232,7 +499,7 @@ func runFuzzySearch(ctx context.Context, searchInput string, searchPrefix string
|
||||||
termSliceLen = strings.Count(result.Term, ".") + 1
|
termSliceLen = strings.Count(result.Term, ".") + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if termSliceLen == inputSliceLen && termPrefix == searchPrefix {
|
if termSliceLen == int(hierarchy) && termPrefix == searchPrefix {
|
||||||
recommends = append(recommends, result.Term)
|
recommends = append(recommends, result.Term)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -240,382 +507,3 @@ func runFuzzySearch(ctx context.Context, searchInput string, searchPrefix string
|
||||||
}
|
}
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RedisSearchRecommend1 define func of redis search by input string and return recommend results
|
|
||||||
func RedisSearchRecommend1(ctx context.Context, input string) ([]string, bool, error) {
|
|
||||||
rdb := diagram.GetRedisClientInstance()
|
|
||||||
|
|
||||||
if input == "" {
|
|
||||||
// 返回所有 grid 名
|
|
||||||
return getKeyBySpecificsLevel(ctx, rdb, 1, input)
|
|
||||||
}
|
|
||||||
|
|
||||||
inputSlice := strings.Split(input, ".")
|
|
||||||
inputSliceLen := len(inputSlice)
|
|
||||||
|
|
||||||
switch inputSliceLen {
|
|
||||||
case 1:
|
|
||||||
// grid tagname search
|
|
||||||
gridSearchInput := inputSlice[0]
|
|
||||||
gridExists, err := rdb.SIsMember(ctx, constants.RedisAllGridSetKey, gridSearchInput).Result()
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "check grid key exist failed ", "grid_key", input, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if gridExists {
|
|
||||||
return []string{"."}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// start grid tagname fuzzy search
|
|
||||||
searchInput := gridSearchInput
|
|
||||||
searchInputLen := len(searchInput)
|
|
||||||
for searchInputLen != 0 && !gridExists {
|
|
||||||
results, err := ac.SuggestOpts(searchInput, redisearch.SuggestOptions{
|
|
||||||
Num: math.MaxInt16,
|
|
||||||
Fuzzy: true,
|
|
||||||
WithScores: false,
|
|
||||||
WithPayloads: false,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "query grid key by redis fuzzy search failed", "query_key", searchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(results) == 0 {
|
|
||||||
// TODO 考虑使用其他方式代替 for 循环退一字节的查询方式
|
|
||||||
searchInput = searchInput[:len(searchInput)-1]
|
|
||||||
searchInputLen = len(searchInput)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var recommends []string
|
|
||||||
for _, result := range results {
|
|
||||||
termSlice := strings.Split(result.Term, ".")
|
|
||||||
if len(termSlice) <= inputSliceLen {
|
|
||||||
recommends = append(recommends, result.Term)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// return fuzzy search results
|
|
||||||
return recommends, true, nil
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
// zone tagname search
|
|
||||||
zoneSearchInput := inputSlice[1]
|
|
||||||
if zoneSearchInput == "" {
|
|
||||||
specificalGrid := inputSlice[0]
|
|
||||||
allZones, isFuzzy, err := getKeyBySpecificsLevel(ctx, rdb, inputSliceLen, specificalGrid)
|
|
||||||
recommandResults := combineQueryResultByInput(inputSliceLen, inputSlice, allZones)
|
|
||||||
return recommandResults, isFuzzy, err
|
|
||||||
}
|
|
||||||
|
|
||||||
zoneExists, err := rdb.SIsMember(ctx, constants.RedisAllZoneSetKey, zoneSearchInput).Result()
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "check zone key exist failed ", "zone_key", zoneSearchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if zoneExists {
|
|
||||||
return []string{"."}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// start zone tagname fuzzy search
|
|
||||||
searchInput := zoneSearchInput
|
|
||||||
searchInputLen := len(searchInput)
|
|
||||||
for searchInputLen != 0 && !zoneExists {
|
|
||||||
results, err := ac.SuggestOpts(searchInput, redisearch.SuggestOptions{
|
|
||||||
Num: math.MaxInt16,
|
|
||||||
Fuzzy: true,
|
|
||||||
WithScores: false,
|
|
||||||
WithPayloads: false,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "query zone key by redis fuzzy search failed", "query_key", searchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(results) == 0 {
|
|
||||||
// TODO 考虑使用其他方式代替 for 循环退一字节的查询方式
|
|
||||||
searchInput = searchInput[:len(searchInput)-1]
|
|
||||||
searchInputLen = len(searchInput)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var recommends []string
|
|
||||||
for _, result := range results {
|
|
||||||
termSlice := strings.Split(result.Term, ".")
|
|
||||||
if len(termSlice) <= inputSliceLen {
|
|
||||||
recommends = append(recommends, result.Term)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// return fuzzy search results
|
|
||||||
return combineQueryResultByInput(inputSliceLen, inputSlice, recommends), true, nil
|
|
||||||
}
|
|
||||||
case 3:
|
|
||||||
// station tagname search
|
|
||||||
stationSearchInput := inputSlice[2]
|
|
||||||
if stationSearchInput == "" {
|
|
||||||
specificalZone := inputSlice[1]
|
|
||||||
allStations, isFuzzy, err := getKeyBySpecificsLevel(ctx, rdb, inputSliceLen, specificalZone)
|
|
||||||
recommandResults := combineQueryResultByInput(inputSliceLen, inputSlice, allStations)
|
|
||||||
return recommandResults, isFuzzy, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stationExists, err := rdb.SIsMember(ctx, constants.RedisAllStationSetKey, stationSearchInput).Result()
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "check station key exist failed ", "station_key", stationSearchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if stationExists {
|
|
||||||
return []string{"."}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// start station tagname fuzzy search
|
|
||||||
searchInput := stationSearchInput
|
|
||||||
searchInputLen := len(searchInput)
|
|
||||||
for searchInputLen != 0 && !stationExists {
|
|
||||||
results, err := ac.SuggestOpts(searchInput, redisearch.SuggestOptions{
|
|
||||||
Num: math.MaxInt16,
|
|
||||||
Fuzzy: true,
|
|
||||||
WithScores: false,
|
|
||||||
WithPayloads: false,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "query station key by redis fuzzy search failed", "query_key", searchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(results) == 0 {
|
|
||||||
// TODO 考虑使用其他方式代替 for 循环退一字节的查询方式
|
|
||||||
searchInput = searchInput[:len(searchInput)-1]
|
|
||||||
searchInputLen = len(searchInput)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var recommends []string
|
|
||||||
for _, result := range results {
|
|
||||||
termSlice := strings.Split(result.Term, ".")
|
|
||||||
if len(termSlice) <= inputSliceLen {
|
|
||||||
recommends = append(recommends, result.Term)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// return fuzzy search results
|
|
||||||
return combineQueryResultByInput(inputSliceLen, inputSlice, recommends), true, nil
|
|
||||||
}
|
|
||||||
case 4:
|
|
||||||
// component nspath search
|
|
||||||
compNSPSearchInput := inputSlice[3]
|
|
||||||
if compNSPSearchInput == "" {
|
|
||||||
specificalStation := inputSlice[2]
|
|
||||||
allCompNSPaths, isFuzzy, err := getKeyBySpecificsLevel(ctx, rdb, inputSliceLen, specificalStation)
|
|
||||||
recommandResults := combineQueryResultByInput(inputSliceLen, inputSlice, allCompNSPaths)
|
|
||||||
return recommandResults, isFuzzy, err
|
|
||||||
}
|
|
||||||
|
|
||||||
compNSPathExists, err := rdb.SIsMember(ctx, constants.RedisAllCompNSPathSetKey, compNSPSearchInput).Result()
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "check component nspath key exist failed ", "component_nspath_key", compNSPSearchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if compNSPathExists {
|
|
||||||
return []string{"."}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// start grid fuzzy search
|
|
||||||
searchInput := compNSPSearchInput
|
|
||||||
searchInputLen := len(searchInput)
|
|
||||||
for searchInputLen != 0 && !compNSPathExists {
|
|
||||||
results, err := ac.SuggestOpts(searchInput, redisearch.SuggestOptions{
|
|
||||||
Num: math.MaxInt16,
|
|
||||||
Fuzzy: true,
|
|
||||||
WithScores: false,
|
|
||||||
WithPayloads: false,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "query component nspath key by redis fuzzy search failed", "query_key", searchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(results) == 0 {
|
|
||||||
// TODO 考虑使用其他方式代替 for 循环退一字节的查询方式
|
|
||||||
searchInput = searchInput[:len(searchInput)-1]
|
|
||||||
searchInputLen = len(searchInput)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var recommends []string
|
|
||||||
for _, result := range results {
|
|
||||||
termSlice := strings.Split(result.Term, ".")
|
|
||||||
if len(termSlice) <= inputSliceLen {
|
|
||||||
recommends = append(recommends, result.Term)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// return fuzzy search results
|
|
||||||
return combineQueryResultByInput(inputSliceLen, inputSlice, recommends), true, nil
|
|
||||||
}
|
|
||||||
case 5:
|
|
||||||
// component tag search
|
|
||||||
compTagSearchInput := inputSlice[4]
|
|
||||||
if compTagSearchInput == "" {
|
|
||||||
// TODO 优化考虑是否使用 station 作为 key 的一部分
|
|
||||||
specificalStation := inputSlice[2]
|
|
||||||
allCompNSPaths, isFuzzy, err := getKeyBySpecificsLevel(ctx, rdb, inputSliceLen, specificalStation)
|
|
||||||
recommandResults := combineQueryResultByInput(inputSliceLen, inputSlice, allCompNSPaths)
|
|
||||||
return recommandResults, isFuzzy, err
|
|
||||||
}
|
|
||||||
|
|
||||||
compTagExists, err := rdb.SIsMember(ctx, constants.RedisAllCompTagSetKey, compTagSearchInput).Result()
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "check component tag key exist failed ", "component_tag_key", compTagSearchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if compTagExists {
|
|
||||||
return []string{"."}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// start grid fuzzy search
|
|
||||||
searchInput := compTagSearchInput
|
|
||||||
searchInputLen := len(searchInput)
|
|
||||||
for searchInputLen != 0 && !compTagExists {
|
|
||||||
results, err := ac.SuggestOpts(searchInput, redisearch.SuggestOptions{
|
|
||||||
Num: math.MaxInt16,
|
|
||||||
Fuzzy: true,
|
|
||||||
WithScores: false,
|
|
||||||
WithPayloads: false,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "query component tag key by redis fuzzy search failed", "query_key", searchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(results) == 0 {
|
|
||||||
// TODO 考虑使用其他方式代替 for 循环退一字节的查询方式
|
|
||||||
searchInput = searchInput[:len(searchInput)-1]
|
|
||||||
searchInputLen = len(searchInput)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var recommends []string
|
|
||||||
for _, result := range results {
|
|
||||||
termSlice := strings.Split(result.Term, ".")
|
|
||||||
if len(termSlice) <= inputSliceLen {
|
|
||||||
recommends = append(recommends, result.Term)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// return fuzzy search results
|
|
||||||
return combineQueryResultByInput(inputSliceLen, inputSlice, recommends), true, nil
|
|
||||||
}
|
|
||||||
case 6:
|
|
||||||
// configuration search
|
|
||||||
// TODO 优化
|
|
||||||
configSearchInput := inputSlice[5]
|
|
||||||
if configSearchInput == "" {
|
|
||||||
allCompNSPaths, isFuzzy, err := getKeyBySpecificsLevel(ctx, rdb, inputSliceLen, "")
|
|
||||||
recommandResults := combineQueryResultByInput(inputSliceLen, inputSlice, allCompNSPaths)
|
|
||||||
return recommandResults, isFuzzy, err
|
|
||||||
}
|
|
||||||
|
|
||||||
configExists, err := rdb.SIsMember(ctx, constants.RedisAllConfigSetKey, configSearchInput).Result()
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "check config key exist failed ", "config_key", configSearchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if configExists {
|
|
||||||
return []string{"."}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// start grid fuzzy search
|
|
||||||
searchInput := configSearchInput
|
|
||||||
searchInputLen := len(searchInput)
|
|
||||||
for searchInputLen != 0 && !configExists {
|
|
||||||
results, err := ac.SuggestOpts(searchInput, redisearch.SuggestOptions{
|
|
||||||
Num: math.MaxInt16,
|
|
||||||
Fuzzy: true,
|
|
||||||
WithScores: false,
|
|
||||||
WithPayloads: false,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "query config key by redis fuzzy search failed", "query_key", searchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(results) == 0 {
|
|
||||||
// TODO 考虑使用其他方式代替 for 循环退一字节的查询方式
|
|
||||||
searchInput = searchInput[:len(searchInput)-1]
|
|
||||||
searchInputLen = len(searchInput)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var recommends []string
|
|
||||||
for _, result := range results {
|
|
||||||
termSlice := strings.Split(result.Term, ".")
|
|
||||||
if len(termSlice) <= inputSliceLen {
|
|
||||||
recommends = append(recommends, result.Term)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// return fuzzy search results
|
|
||||||
return combineQueryResultByInput(inputSliceLen, inputSlice, recommends), true, nil
|
|
||||||
}
|
|
||||||
case 7:
|
|
||||||
// measurement search
|
|
||||||
measSearchInput := inputSlice[6]
|
|
||||||
if measSearchInput == "" {
|
|
||||||
// use compoent tag for redis unique key prefix
|
|
||||||
specificalCompTag := inputSlice[4]
|
|
||||||
allMeasTags, isFuzzy, err := getKeyBySpecificsLevel(ctx, rdb, inputSliceLen, specificalCompTag)
|
|
||||||
recommandResults := combineQueryResultByInput(inputSliceLen, inputSlice, allMeasTags)
|
|
||||||
return recommandResults, isFuzzy, err
|
|
||||||
}
|
|
||||||
|
|
||||||
measTagExists, err := rdb.SIsMember(ctx, constants.RedisAllMeasTagSetKey, measSearchInput).Result()
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "check component tag key exist failed ", "component_tag_key", measSearchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if measTagExists {
|
|
||||||
return []string{"."}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// start measurement tag fuzzy search
|
|
||||||
searchInput := measSearchInput
|
|
||||||
searchInputLen := len(searchInput)
|
|
||||||
for searchInputLen != 0 && !measTagExists {
|
|
||||||
results, err := ac.SuggestOpts(searchInput, redisearch.SuggestOptions{
|
|
||||||
Num: math.MaxInt16,
|
|
||||||
Fuzzy: true,
|
|
||||||
WithScores: false,
|
|
||||||
WithPayloads: false,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "query measurement tag key by redis fuzzy search failed", "query_key", searchInput, "error", err)
|
|
||||||
return []string{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(results) == 0 {
|
|
||||||
// TODO 考虑使用其他方式代替 for 循环退一字节的查询方式
|
|
||||||
searchInput = searchInput[:len(searchInput)-1]
|
|
||||||
searchInputLen = len(searchInput)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var recommends []string
|
|
||||||
for _, result := range results {
|
|
||||||
termSlice := strings.Split(result.Term, ".")
|
|
||||||
if len(termSlice) <= inputSliceLen {
|
|
||||||
recommends = append(recommends, result.Term)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// return fuzzy search results
|
|
||||||
return combineQueryResultByInput(inputSliceLen, inputSlice, recommends), true, nil
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
logger.Error(ctx, "unsupport length of search input", "input_len", inputSliceLen)
|
|
||||||
return []string{}, false, nil
|
|
||||||
}
|
|
||||||
return []string{}, false, nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Package util provide some utility functions
|
||||||
|
package util
|
||||||
|
|
||||||
|
import "modelRT/constants"
|
||||||
|
|
||||||
|
// GetLevelStrByRdsKey define func to return hierarchical by special redis key
|
||||||
|
func GetLevelStrByRdsKey(key string) string {
|
||||||
|
switch key {
|
||||||
|
case constants.RedisAllGridSetKey:
|
||||||
|
return "grid"
|
||||||
|
case constants.RedisAllZoneSetKey:
|
||||||
|
return "zone"
|
||||||
|
case constants.RedisAllStationSetKey:
|
||||||
|
return "station"
|
||||||
|
case constants.RedisAllCompNSPathSetKey:
|
||||||
|
return "component nspaht"
|
||||||
|
case constants.RedisAllCompTagSetKey:
|
||||||
|
return "component tag"
|
||||||
|
case constants.RedisAllConfigSetKey:
|
||||||
|
return "config"
|
||||||
|
case constants.RedisAllMeasTagSetKey:
|
||||||
|
return "measurement tag"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue