modelRT/model/redis_recommend.go

214 lines
6.2 KiB
Go
Raw Normal View History

// Package model define model struct of model runtime service
package model
import (
"context"
"fmt"
"math"
"strings"
"modelRT/constants"
"modelRT/diagram"
2025-09-25 16:39:45 +08:00
"modelRT/logger"
"github.com/RediSearch/redisearch-go/v2/redisearch"
redigo "github.com/gomodule/redigo/redis"
)
var ac *redisearch.Autocompleter
// InitAutocompleterWithPool define func of initialize the Autocompleter with redigo pool
func InitAutocompleterWithPool(pool *redigo.Pool) {
ac = redisearch.NewAutocompleterFromPool(pool, constants.RedisSearchDictName)
}
2025-09-25 16:39:45 +08:00
// RedisSearchRecommend define func of redis search by input string and return recommend results
2025-10-16 17:18:57 +08:00
func RedisSearchRecommend(ctx context.Context, input string) ([]string, bool, error) {
2025-09-24 17:26:46 +08:00
rdb := diagram.GetRedisClientInstance()
if input == "" {
// 返回所有 grid 名
return getAllGridKeys(ctx, constants.RedisAllGridSetKey)
}
2025-10-20 15:06:23 +08:00
inputSlice := strings.Split(input, ".")
inputSliceLen := len(inputSlice)
originInputLen := len(inputSlice)
switch inputSliceLen {
2025-09-25 16:39:45 +08:00
case 1:
2025-10-16 17:18:57 +08:00
// TODO 优化成NewSet的形式
2025-09-25 16:39:45 +08:00
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)
2025-10-16 17:18:57 +08:00
return []string{}, false, err
2025-09-25 16:39:45 +08:00
}
2025-10-16 17:18:57 +08:00
searchInput := input
2025-10-20 15:06:23 +08:00
inputLen := inputSliceLen
2025-10-16 17:18:57 +08:00
for inputLen != 0 && !gridExist {
results, err := ac.SuggestOpts(searchInput, redisearch.SuggestOptions{
Num: math.MaxInt16,
2025-09-25 16:39:45 +08:00
Fuzzy: true,
WithScores: false,
WithPayloads: false,
2025-09-25 16:39:45 +08:00
})
if err != nil {
logger.Error(ctx, "query info by fuzzy failed", "query_key", input, "error", err)
2025-10-16 17:18:57 +08:00
return []string{}, false, err
2025-09-25 16:39:45 +08:00
}
if len(results) == 0 {
// TODO 构建 for 循环返回所有可能的补全
2025-10-20 15:06:23 +08:00
searchInput = searchInput[:len(searchInput)-1]
2025-10-16 17:18:57 +08:00
inputLen = len(searchInput)
continue
}
2025-10-20 15:06:23 +08:00
var recommends []string
2025-09-25 16:39:45 +08:00
for _, result := range results {
2025-10-20 15:06:23 +08:00
termSlice := strings.Split(result.Term, ".")
if len(termSlice) <= originInputLen {
recommends = append(recommends, result.Term)
}
2025-09-25 16:39:45 +08:00
}
// 返回模糊查询结果
2025-10-20 15:06:23 +08:00
return recommends, true, nil
2025-09-25 16:39:45 +08:00
}
2025-09-25 16:39:45 +08:00
// 处理 input 不为空、不含有.并且 input 是一个完整的 grid key 的情况
if strings.HasSuffix(input, ".") == false {
2025-10-20 15:06:23 +08:00
recommend := input + "."
return []string{recommend}, false, nil
2025-09-25 16:39:45 +08:00
}
default:
2025-10-20 15:06:23 +08:00
lastInput := inputSlice[inputSliceLen-1]
// 判断 queryKey 是否是空值空值则返回上一级别下的所有key
2025-10-16 17:18:57 +08:00
if lastInput == "" {
2025-10-20 15:06:23 +08:00
setKey := getCombinedConstantsKeyByLength(inputSlice[inputSliceLen-2], inputSliceLen)
2025-09-25 16:39:45 +08:00
targetSet := diagram.NewRedisSet(ctx, setKey, 10, true)
2025-10-20 15:06:23 +08:00
keys, err := targetSet.SMembers(setKey)
if err != nil {
logger.Error(ctx, "get all recommend key by setKey failed", "set_key", setKey, "error", err)
2025-10-16 17:18:57 +08:00
return []string{}, false, fmt.Errorf("get all recommend key by setKey failed,%w", err)
}
2025-10-20 15:06:23 +08:00
var results []string
for _, key := range keys {
result := input + key
results = append(results, result)
}
2025-10-16 17:18:57 +08:00
return results, false, nil
2025-09-25 16:39:45 +08:00
}
2025-10-20 15:06:23 +08:00
setKey := getCombinedConstantsKeyByLength(inputSlice[inputSliceLen-2], inputSliceLen)
2025-09-25 16:39:45 +08:00
targetSet := diagram.NewRedisSet(ctx, setKey, 10, true)
2025-10-16 17:18:57 +08:00
exist, err := targetSet.SIsMember(setKey, lastInput)
2025-09-25 16:39:45 +08:00
if err != nil {
2025-10-16 17:18:57 +08:00
logger.Error(ctx, "check keys exist failed", "set_key", setKey, "query_key", lastInput, "error", err)
return []string{}, false, fmt.Errorf("check keys failed,%w", err)
2025-09-25 16:39:45 +08:00
}
2025-10-16 17:18:57 +08:00
searchInput := input
inputLen := len(searchInput)
for inputLen != 0 && !exist {
logger.Info(ctx, "use fuzzy query", "input", input)
2025-10-16 17:18:57 +08:00
results, err := ac.SuggestOpts(searchInput, redisearch.SuggestOptions{
Num: math.MaxInt16,
Fuzzy: true,
2025-10-16 17:18:57 +08:00
WithScores: false,
WithPayloads: false,
})
if err != nil {
logger.Error(ctx, "query info by fuzzy failed", "query_key", input, "error", err)
2025-10-16 17:18:57 +08:00
return []string{}, false, err
}
if len(results) == 0 {
// TODO 构建 for 循环返回所有可能的补全
searchInput = input[:inputLen-1]
inputLen = len(searchInput)
continue
}
var terms []string
for _, result := range results {
terms = append(terms, result.Term)
}
// 返回模糊查询结果
2025-10-16 17:18:57 +08:00
return terms, true, nil
2025-09-25 16:39:45 +08:00
}
2025-10-16 17:18:57 +08:00
return []string{input}, false, nil
}
2025-10-16 17:18:57 +08:00
return []string{}, false, nil
}
2025-10-16 17:18:57 +08:00
func getAllGridKeys(ctx context.Context, setKey string) ([]string, bool, error) {
2025-09-25 16:39:45 +08:00
// 从redis set 中获取所有的 grid key
gridSets := diagram.NewRedisSet(ctx, setKey, 10, true)
keys, err := gridSets.SMembers("grid_keys")
if err != nil {
2025-10-16 17:18:57 +08:00
return []string{}, false, fmt.Errorf("get all root keys failed, error: %v", err)
}
2025-10-16 17:18:57 +08:00
return keys, false, nil
}
2025-10-20 15:06:23 +08:00
func getSpecificZoneKeys(ctx context.Context, input string) ([]string, bool, error) {
setKey := fmt.Sprintf(constants.RedisSpecGridZoneSetKey, input)
2025-09-25 16:39:45 +08:00
// TODO 从redis set 中获取指定 grid 下的 zone key
zoneSets := diagram.NewRedisSet(ctx, setKey, 10, true)
2025-10-16 17:18:57 +08:00
keys, err := zoneSets.SMembers(setKey)
if err != nil {
2025-10-16 17:18:57 +08:00
return []string{}, false, fmt.Errorf("get all root keys failed, error: %v", err)
}
2025-10-20 15:06:23 +08:00
var results []string
for _, key := range keys {
result := input + "." + key
results = append(results, result)
}
return results, false, nil
}
2025-09-25 16:39:45 +08:00
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
}
}
2025-09-27 15:56:46 +08:00
2025-10-16 17:18:57 +08:00
func getCombinedConstantsKeyByLength(key string, inputLen int) string {
switch inputLen {
case 2:
return fmt.Sprintf(constants.RedisSpecGridZoneSetKey, key)
case 3:
return fmt.Sprintf(constants.RedisSpecZoneStationSetKey, key)
case 4:
return fmt.Sprintf(constants.RedisSpecStationComponentSetKey, key)
default:
return constants.RedisAllGridSetKey
}
}
2025-09-27 15:56:46 +08:00
// GetLongestCommonPrefixLength define func of get longest common prefix length between two strings
2025-09-29 16:37:38 +08:00
func GetLongestCommonPrefixLength(input string, recommendResult string) int {
if input == "" {
return 0
2025-09-27 15:56:46 +08:00
}
2025-09-29 16:37:38 +08:00
minLen := min(len(input), len(recommendResult))
for i := range minLen {
if input[i] != recommendResult[i] {
2025-09-27 15:56:46 +08:00
return i
}
}
return minLen
}