modelRT/model/redis_recommend.go

621 lines
20 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"
2025-12-03 16:55:14 +08:00
"github.com/redis/go-redis/v9"
)
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()
2025-12-04 17:26:35 +08:00
if input == "" {
// return all grid tagname
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, nil
}
// start grid tagname fuzzy search
recommends, err := runFuzzySearch(ctx, gridSearchInput, "", inputSliceLen)
2025-12-04 17:26:35 +08:00
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:
return handleLevelFuzzySearch(ctx, rdb, 2, constants.RedisAllZoneSetKey, inputSlice)
case 3:
return handleLevelFuzzySearch(ctx, rdb, 3, constants.RedisAllStationSetKey, inputSlice)
case 4:
return handleLevelFuzzySearch(ctx, rdb, 4, constants.RedisAllCompNSPathSetKey, inputSlice)
case 5:
return handleLevelFuzzySearch(ctx, rdb, 5, constants.RedisAllCompTagSetKey, inputSlice)
case 6:
return handleLevelFuzzySearch(ctx, rdb, 6, constants.RedisAllConfigSetKey, inputSlice)
case 7:
return handleLevelFuzzySearch(ctx, rdb, 7, constants.RedisAllMeasTagSetKey, inputSlice)
default:
logger.Error(ctx, "unsupport length of search input", "input_len", inputSliceLen)
return []string{}, false, nil
}
}
func getKeyBySpecificsLevel(ctx context.Context, rdb *redis.Client, inputLen int, input string) ([]string, bool, error) {
queryKey := getSpecificKeyByLength(inputLen, input)
results, err := rdb.SMembers(ctx, queryKey).Result()
if err != nil {
return []string{}, false, fmt.Errorf("get all keys failed, error: %w", err)
}
return results, false, nil
}
func combineQueryResultByInput(inputSliceLen int, inputSlice []string, queryResults []string) []string {
prefixs := make([]string, 0, len(inputSlice))
recommandResults := make([]string, 0, len(queryResults))
switch inputSliceLen {
case 2:
prefixs = []string{inputSlice[0]}
case 3:
prefixs = inputSlice[0:2]
case 4:
prefixs = inputSlice[0:3]
case 5:
prefixs = inputSlice[0:4]
case 6:
prefixs = inputSlice[0:5]
case 7:
prefixs = inputSlice[0:6]
default:
return []string{}
}
for _, queryResult := range queryResults {
combineStrs := make([]string, 0, len(inputSlice))
combineStrs = append(combineStrs, prefixs...)
combineStrs = append(combineStrs, queryResult)
recommandResult := strings.Join(combineStrs, ".")
recommandResults = append(recommandResults, recommandResult)
}
return recommandResults
}
func getSpecificKeyByLength(inputLen int, input string) string {
switch inputLen {
case 1:
return constants.RedisAllGridSetKey
case 2:
return fmt.Sprintf(constants.RedisSpecGridZoneSetKey, input)
case 3:
return fmt.Sprintf(constants.RedisSpecZoneStationSetKey, input)
case 4:
return fmt.Sprintf(constants.RedisSpecStationCompNSPATHSetKey, input)
case 5:
return fmt.Sprintf(constants.RedisSpecStationCompTagSetKey, input)
case 6:
return constants.RedisAllConfigSetKey
case 7:
return fmt.Sprintf(constants.RedisSpecCompTagMeasSetKey, input)
default:
return constants.RedisAllGridSetKey
}
}
// 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) {
searchInputIndex := hierarchy - 1
2025-12-04 17:26:35 +08:00
searchInput := inputSlice[searchInputIndex]
searchPrefix := strings.Join(inputSlice[0:searchInputIndex], ".")
2025-12-04 17:26:35 +08:00
if searchInput == "" {
var specificalKey string
specificalKeyIndex := searchInputIndex - 1
if specificalKeyIndex >= 0 {
specificalKey = inputSlice[specificalKeyIndex]
}
allResults, isFuzzy, err := getKeyBySpecificsLevel(ctx, rdb, hierarchy, specificalKey)
2025-12-04 17:26:35 +08:00
if err != nil {
return []string{}, false, err
}
recommandResults := combineQueryResultByInput(hierarchy, inputSlice, allResults)
2025-12-04 17:26:35 +08:00
return recommandResults, isFuzzy, nil
}
keyExists, err := rdb.SIsMember(ctx, keySetKey, searchInput).Result()
if err != nil {
logger.Error(ctx, "check key exist failed ", "key", searchInput, "error", err)
return []string{}, false, err
}
if keyExists {
if hierarchy == constants.MaxIdentifyHierarchy {
return []string{""}, false, nil
}
2025-12-04 17:26:35 +08:00
return []string{"."}, false, nil
}
// start redis fuzzy search
recommends, err := runFuzzySearch(ctx, searchInput, searchPrefix, hierarchy)
2025-12-04 17:26:35 +08:00
if err != nil {
logger.Error(ctx, "fuzzy search failed by hierarchy", "hierarchy", hierarchy, "search_input", searchInput, "error", err)
2025-12-04 17:26:35 +08:00
return []string{}, false, err
}
if len(recommends) == 0 {
logger.Error(ctx, "fuzzy search without result", "hierarchy", hierarchy, "search_input", searchInput, "error", err)
2025-12-04 17:26:35 +08:00
return []string{}, true, nil
}
return combineQueryResultByInput(hierarchy, inputSlice, recommends), true, nil
2025-12-04 17:26:35 +08:00
}
// runFuzzySearch define func to process redis fuzzy search
func runFuzzySearch(ctx context.Context, searchInput string, searchPrefix string, inputSliceLen int) ([]string, error) {
2025-12-04 17:26:35 +08:00
searchInputLen := len(searchInput)
for searchInputLen != 0 {
results, err := ac.SuggestOpts(searchInput, redisearch.SuggestOptions{
Num: math.MaxInt16,
Fuzzy: true,
WithScores: false,
WithPayloads: false,
})
if err != nil {
logger.Error(ctx, "query key by redis fuzzy search failed", "query_key", searchInput, "error", err)
return nil, fmt.Errorf("redisearch suggest failed: %w", err)
}
if len(results) == 0 {
// 如果没有结果,退一步(删除最后一个字节)并继续循环
// TODO 考虑使用其他方式代替 for 循环退一字节的查询方式
searchInput = searchInput[:len(searchInput)-1]
searchInputLen = len(searchInput)
continue
}
var recommends []string
for _, result := range results {
term := result.Term
var termSliceLen int
var termPrefix string
lastDotIndex := strings.LastIndex(term, ".")
if lastDotIndex == -1 {
termPrefix = ""
} else {
termPrefix = term[:lastDotIndex]
}
if result.Term == "" {
termSliceLen = 1
} else {
termSliceLen = strings.Count(result.Term, ".") + 1
}
if termSliceLen == inputSliceLen && termPrefix == searchPrefix {
2025-12-04 17:26:35 +08:00
recommends = append(recommends, result.Term)
}
}
return recommends, 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 名
2025-12-03 16:55:14 +08:00
return getKeyBySpecificsLevel(ctx, rdb, 1, input)
}
2025-10-20 15:06:23 +08:00
inputSlice := strings.Split(input, ".")
inputSliceLen := len(inputSlice)
switch inputSliceLen {
2025-09-25 16:39:45 +08:00
case 1:
2025-12-04 17:26:35 +08:00
// grid tagname search
2025-12-03 16:55:14 +08:00
gridSearchInput := inputSlice[0]
gridExists, err := rdb.SIsMember(ctx, constants.RedisAllGridSetKey, gridSearchInput).Result()
2025-09-25 16:39:45 +08:00
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
2025-12-03 16:55:14 +08:00
if gridExists {
return []string{"."}, false, err
}
2025-12-04 17:26:35 +08:00
// start grid tagname fuzzy search
2025-12-03 16:55:14 +08:00
searchInput := gridSearchInput
searchInputLen := len(searchInput)
for searchInputLen != 0 && !gridExists {
2025-10-16 17:18:57 +08:00
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 {
2025-12-03 16:55:14 +08:00
logger.Error(ctx, "query grid key by redis fuzzy search failed", "query_key", searchInput, "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 {
2025-12-03 16:55:14 +08:00
// TODO 考虑使用其他方式代替 for 循环退一字节的查询方式
2025-10-20 15:06:23 +08:00
searchInput = searchInput[:len(searchInput)-1]
2025-12-03 16:55:14 +08:00
searchInputLen = len(searchInput)
2025-10-16 17:18:57 +08:00
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, ".")
2025-12-03 16:55:14 +08:00
if len(termSlice) <= inputSliceLen {
2025-10-20 15:06:23 +08:00
recommends = append(recommends, result.Term)
}
2025-09-25 16:39:45 +08:00
}
2025-12-03 16:55:14 +08:00
// return fuzzy search results
2025-10-20 15:06:23 +08:00
return recommends, true, nil
2025-09-25 16:39:45 +08:00
}
2025-12-03 16:55:14 +08:00
case 2:
2025-12-04 17:26:35 +08:00
// zone tagname search
2025-12-03 16:55:14 +08:00
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
}
2025-12-04 17:26:35 +08:00
// start zone tagname fuzzy search
2025-12-03 16:55:14 +08:00
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:
2025-12-04 17:26:35 +08:00
// station tagname search
2025-12-03 16:55:14 +08:00
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
}
2025-12-04 17:26:35 +08:00
// start station tagname fuzzy search
2025-12-03 16:55:14 +08:00
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
2025-12-04 17:26:35 +08:00
compNSPSearchInput := inputSlice[3]
if compNSPSearchInput == "" {
specificalStation := inputSlice[2]
allCompNSPaths, isFuzzy, err := getKeyBySpecificsLevel(ctx, rdb, inputSliceLen, specificalStation)
recommandResults := combineQueryResultByInput(inputSliceLen, inputSlice, allCompNSPaths)
2025-12-03 16:55:14 +08:00
return recommandResults, isFuzzy, err
}
2025-12-04 17:26:35 +08:00
compNSPathExists, err := rdb.SIsMember(ctx, constants.RedisAllCompNSPathSetKey, compNSPSearchInput).Result()
2025-12-03 16:55:14 +08:00
if err != nil {
2025-12-04 17:26:35 +08:00
logger.Error(ctx, "check component nspath key exist failed ", "component_nspath_key", compNSPSearchInput, "error", err)
2025-12-03 16:55:14 +08:00
return []string{}, false, err
}
2025-12-04 17:26:35 +08:00
if compNSPathExists {
2025-12-03 16:55:14 +08:00
return []string{"."}, false, err
}
// start grid fuzzy search
2025-12-04 17:26:35 +08:00
searchInput := compNSPSearchInput
2025-12-03 16:55:14 +08:00
searchInputLen := len(searchInput)
2025-12-04 17:26:35 +08:00
for searchInputLen != 0 && !compNSPathExists {
2025-12-03 16:55:14 +08:00
results, err := ac.SuggestOpts(searchInput, redisearch.SuggestOptions{
Num: math.MaxInt16,
Fuzzy: true,
WithScores: false,
WithPayloads: false,
})
if err != nil {
2025-12-04 17:26:35 +08:00
logger.Error(ctx, "query component nspath key by redis fuzzy search failed", "query_key", searchInput, "error", err)
2025-12-03 16:55:14 +08:00
return []string{}, false, err
}
if len(results) == 0 {
// TODO 考虑使用其他方式代替 for 循环退一字节的查询方式
searchInput = searchInput[:len(searchInput)-1]
searchInputLen = len(searchInput)
continue
}
2025-12-03 16:55:14 +08:00
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
2025-09-25 16:39:45 +08:00
}
2025-12-03 16:55:14 +08:00
case 5:
// component tag search
compTagSearchInput := inputSlice[4]
2025-12-04 17:26:35 +08:00
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
2025-09-25 16:39:45 +08:00
}
2025-12-04 17:26:35 +08:00
compTagExists, err := rdb.SIsMember(ctx, constants.RedisAllCompTagSetKey, compTagSearchInput).Result()
2025-09-25 16:39:45 +08:00
if err != nil {
2025-12-04 17:26:35 +08:00
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
2025-09-25 16:39:45 +08:00
}
2025-12-04 17:26:35 +08:00
// start grid fuzzy search
searchInput := compTagSearchInput
searchInputLen := len(searchInput)
for searchInputLen != 0 && !compTagExists {
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 {
2025-12-04 17:26:35 +08:00
logger.Error(ctx, "query component tag key by redis fuzzy search failed", "query_key", searchInput, "error", err)
2025-10-16 17:18:57 +08:00
return []string{}, false, err
}
2025-12-04 17:26:35 +08:00
2025-10-16 17:18:57 +08:00
if len(results) == 0 {
2025-12-04 17:26:35 +08:00
// TODO 考虑使用其他方式代替 for 循环退一字节的查询方式
searchInput = searchInput[:len(searchInput)-1]
searchInputLen = len(searchInput)
2025-10-16 17:18:57 +08:00
continue
}
2025-12-04 17:26:35 +08:00
var recommends []string
for _, result := range results {
2025-12-04 17:26:35 +08:00
termSlice := strings.Split(result.Term, ".")
if len(termSlice) <= inputSliceLen {
recommends = append(recommends, result.Term)
}
}
2025-12-04 17:26:35 +08:00
// 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
2025-09-25 16:39:45 +08:00
}
2025-12-04 17:26:35 +08:00
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
}
2025-12-04 17:26:35 +08:00
if configExists {
return []string{"."}, false, err
}
2025-12-03 16:55:14 +08:00
2025-12-04 17:26:35 +08:00
// 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
}
2025-09-25 16:39:45 +08:00
2025-12-04 17:26:35 +08:00
if len(results) == 0 {
// TODO 考虑使用其他方式代替 for 循环退一字节的查询方式
searchInput = searchInput[:len(searchInput)-1]
searchInputLen = len(searchInput)
continue
}
2025-09-27 15:56:46 +08:00
2025-12-04 17:26:35 +08:00
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
}
2025-12-03 16:55:14 +08:00
2025-12-04 17:26:35 +08:00
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
}
2025-10-16 17:18:57 +08:00
2025-12-04 17:26:35 +08:00
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
}
2025-09-27 15:56:46 +08:00
2025-12-04 17:26:35 +08:00
if len(results) == 0 {
// TODO 考虑使用其他方式代替 for 循环退一字节的查询方式
searchInput = searchInput[:len(searchInput)-1]
searchInputLen = len(searchInput)
continue
}
2025-09-29 16:37:38 +08:00
2025-12-04 17:26:35 +08:00
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
2025-09-27 15:56:46 +08:00
}
2025-12-04 17:26:35 +08:00
default:
logger.Error(ctx, "unsupport length of search input", "input_len", inputSliceLen)
return []string{}, false, nil
2025-09-27 15:56:46 +08:00
}
2025-12-04 17:26:35 +08:00
return []string{}, false, nil
2025-09-27 15:56:46 +08:00
}