// Package model define model struct of model runtime service package model import ( "context" "fmt" "strings" "modelRT/constants" "modelRT/diagram" "modelRT/logger" "github.com/RediSearch/redisearch-go/redisearch" ) // RedisSearchRecommend define func of redis search by input string and return recommend results func RedisSearchRecommend(ctx context.Context, input string) ([]string, error) { rdb := diagram.GetRedisClientInstance() if input == "" { // 返回所有 grid 名 return getAllGridKeys(ctx, constants.RedisAllGridSetKey) } inputs := strings.Split(input, ".") inputLen := len(inputs) switch inputLen { case 1: gridExist, err := rdb.SIsMember(ctx, constants.RedisAllGridSetKey, input).Result() if err != nil { logger.Error(ctx, "check grid key exist failed ", "grid_key", input, "error", err) return []string{}, err } if !gridExist { // TODO 检测name是不是 tire 树名 ac := redisearch.NewAutocompleter("localhost:6379", "my-autocomplete-dict") results, err := ac.SuggestOpts(input, redisearch.SuggestOptions{ // TODO 测试如何返回全部的可能模糊结果 Num: 5, Fuzzy: true, WithScores: true, WithPayloads: true, }) if err != nil { logger.Error(ctx, "query info by fuzzy failed", "query_key", input, "error", err) return []string{}, err } var grids []string for _, result := range results { grids = append(grids, result.Term) } // 返回模糊查询结果 return grids, nil } // 处理 input 不为空、不含有.并且 input 是一个完整的 grid key 的情况 if strings.HasSuffix(input, ".") == false { return []string{"."}, nil } // 处理 input 不为空并且以.结尾的情况 if strings.HasSuffix(input, ".") == true { setKey := fmt.Sprintf(constants.RedisSpecGridZoneSetKey, input) return getSpecificZoneKeys(ctx, setKey) } default: lastToken := inputs[inputLen-1] // 判断 queryKey 是否是空值,空值则返回上一级别下的所有key if lastToken == "" { setKey := getConstantsKeyByLength(inputLen - 1) targetSet := diagram.NewRedisSet(ctx, setKey, 10, true) results, err := targetSet.SMembers(setKey) if err != nil { logger.Error(ctx, "get all recommend key by setKey failed", "set_key", setKey, "error", err) return []string{}, fmt.Errorf("get all recommend key by setKey failed,%w", err) } return results, nil } querykey := lastToken setKey := getConstantsKeyByLength(inputLen) targetSet := diagram.NewRedisSet(ctx, setKey, 10, true) exist, err := targetSet.SIsMember(setKey, querykey) if err != nil { logger.Error(ctx, "check keys exist failed", "set_key", setKey, "query_key", querykey, "error", err) return []string{}, fmt.Errorf("check keys failed,%w", err) } if !exist { fmt.Println("use fuzzy query") // TODO 检测name是不是 tire 树名 ac := redisearch.NewAutocompleter("localhost:6379", "my-autocomplete-dict") results, err := ac.SuggestOpts(input, redisearch.SuggestOptions{ // TODO 测试如何返回全部的可能模糊结果 Num: 5, Fuzzy: true, WithScores: true, WithPayloads: true, }) if err != nil { logger.Error(ctx, "query info by fuzzy failed", "query_key", input, "error", err) return []string{}, err } var terms []string for _, result := range results { terms = append(terms, result.Term) } // 返回模糊查询结果 return terms, nil } return []string{}, nil } return []string{}, nil } func getAllGridKeys(ctx context.Context, setKey string) ([]string, error) { // 从redis set 中获取所有的 grid key gridSets := diagram.NewRedisSet(ctx, setKey, 10, true) keys, err := gridSets.SMembers("grid_keys") if err != nil { return []string{}, fmt.Errorf("get all root keys failed, error: %v", err) } return keys, nil } func getSpecificZoneKeys(ctx context.Context, setKey string) ([]string, error) { // TODO 从redis set 中获取指定 grid 下的 zone key zoneSets := diagram.NewRedisSet(ctx, setKey, 10, true) keys, err := zoneSets.SMembers("grid_keys") if err != nil { return []string{}, fmt.Errorf("get all root keys failed, error: %v", err) } return keys, nil } func getConstantsKeyByLength(inputLen int) string { switch inputLen { case 1: return constants.RedisAllGridSetKey case 2: return constants.RedisAllZoneSetKey case 3: return constants.RedisAllStationSetKey case 4: return constants.RedisAllComponentSetKey default: return constants.RedisAllGridSetKey } } // GetLongestCommonPrefixLength define func of get longest common prefix length between two strings func GetLongestCommonPrefixLength(s1 string, s2 string) int { // TODO 增加对特殊字符串例如 "" 的处理 minLen := len(s1) if len(s2) < minLen { minLen = len(s2) } for i := 0; i < minLen; i++ { if s1[i] != s2[i] { return i } } return minLen }