refactor: simplify redis recommendation concurrency
- replace fan-in channel recommendation searches with errgroup-based execution - return SearchResult directly from Redis recommendation helper functions - fallback leading-dot recommendation input to initial token suggestions - remove unused recommendLenType parameter from fuzzy member set validation - clean up small model selection and naming issues
This commit is contained in:
parent
f9824e2b24
commit
d8668afa46
|
|
@ -2,6 +2,8 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"modelRT/constants"
|
||||
"modelRT/database"
|
||||
"modelRT/logger"
|
||||
|
|
@ -152,6 +154,8 @@ func validateBatchImportParams(params map[string]any) bool {
|
|||
func validateTestTaskParams(params map[string]any) bool {
|
||||
// Test task has optional parameters, all are valid
|
||||
// sleep_duration defaults to 60 seconds if not provided
|
||||
// TODO Add more validation logic for test task parameters if needed
|
||||
fmt.Println(params)
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,6 +90,6 @@ func (s *ShortAttrInfo) IsLocal() bool {
|
|||
}
|
||||
|
||||
// GetAttrValue define return the attribute value
|
||||
func (l *ShortAttrInfo) GetAttrValue() any {
|
||||
return l.AttrValue
|
||||
func (s *ShortAttrInfo) GetAttrValue() any {
|
||||
return s.AttrValue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// Package model define model struct of model runtime service
|
||||
package model
|
||||
|
||||
import (
|
||||
|
|
@ -7,11 +8,12 @@ import (
|
|||
|
||||
// SelectModelByType define select the data structure for parsing based on the input model type
|
||||
func SelectModelByType(modelType int) BasicModelInterface {
|
||||
if modelType == constants.BusbarType {
|
||||
switch modelType {
|
||||
case constants.BusbarType:
|
||||
return &orm.BusbarSection{}
|
||||
} else if modelType == constants.AsyncMotorType {
|
||||
case constants.AsyncMotorType:
|
||||
return &orm.AsyncMotor{}
|
||||
} else if modelType == constants.DemoType {
|
||||
case constants.DemoType:
|
||||
return &orm.Demo{}
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"modelRT/constants"
|
||||
"modelRT/diagram"
|
||||
|
|
@ -16,6 +17,7 @@ import (
|
|||
"github.com/RediSearch/redisearch-go/v2/redisearch"
|
||||
redigo "github.com/gomodule/redigo/redis"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// SearchResult define struct to store redis query recommend search result
|
||||
|
|
@ -36,12 +38,44 @@ func InitAutocompleterWithPool(pool *redigo.Pool) {
|
|||
ac = redisearch.NewAutocompleterFromPool(pool, constants.RedisSearchDictName)
|
||||
}
|
||||
|
||||
type recommendSearchJob func() SearchResult
|
||||
|
||||
func runRecommendSearches(ctx context.Context, logMsg string, filterCompNSPath bool, jobs ...recommendSearchJob) map[string]SearchResult {
|
||||
results := make(map[string]SearchResult)
|
||||
var mu sync.Mutex
|
||||
var group errgroup.Group
|
||||
|
||||
for _, job := range jobs {
|
||||
job := job
|
||||
group.Go(func() error {
|
||||
result := job()
|
||||
if result.Err != nil {
|
||||
return fmt.Errorf("%s: %w", result.RecommendType, result.Err)
|
||||
}
|
||||
|
||||
if filterCompNSPath && result.RecommendType == constants.CompNSPathRecommendHierarchyType {
|
||||
result.QueryDatas = filterLocalNSPathResults(result.QueryDatas)
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
results[result.RecommendType.String()] = result
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if err := group.Wait(); err != nil {
|
||||
logger.Error(ctx, logMsg, "error", err)
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// levelOneRedisSearch 处理第一段输入的搜索, 例如 grid 或本地 nspath。
|
||||
func levelOneRedisSearch(ctx context.Context, rdb *redis.Client, hierarchy constants.RecommendHierarchyType, recommendLenType string, searchInput string, searchRedisKey string, fanInChan chan SearchResult) {
|
||||
func levelOneRedisSearch(ctx context.Context, rdb *redis.Client, hierarchy constants.RecommendHierarchyType, recommendLenType string, searchInput string, searchRedisKey string) (result SearchResult) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logger.Error(ctx, "searchFunc panicked", "panic", r)
|
||||
fanInChan <- SearchResult{
|
||||
result = SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: false,
|
||||
|
|
@ -54,64 +88,59 @@ func levelOneRedisSearch(ctx context.Context, rdb *redis.Client, hierarchy const
|
|||
if err != nil {
|
||||
logger.Error(ctx, "redis membership check failed", "key", searchRedisKey, "member", searchInput, "op", "SIsMember", "error", err)
|
||||
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: false,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// the input key is the complete hierarchical value
|
||||
if exists {
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: []string{"."},
|
||||
IsFuzzy: false,
|
||||
Err: nil,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// process fuzzy search result
|
||||
recommends, offset, err := runFuzzySearch(ctx, rdb, searchInput, "", hierarchy, recommendLenType)
|
||||
if err != nil {
|
||||
logger.Error(ctx, fmt.Sprintf("fuzzy search failed for %s hierarchical", util.GetLevelStrByRdsKey(searchRedisKey)), "search_input", searchInput, "error", err)
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: false,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if len(recommends) > 0 {
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: recommends,
|
||||
IsFuzzy: true,
|
||||
Offset: offset,
|
||||
Err: nil,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
recommends, err = fallbackAllCurrentLevel(ctx, rdb, hierarchy)
|
||||
if err != nil {
|
||||
logger.Error(ctx, "fallback all keys at current level failed", "hierarchy", hierarchy, "search_input", searchInput, "error", err)
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: true,
|
||||
IsFallback: true,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: recommends,
|
||||
IsFuzzy: true,
|
||||
|
|
@ -124,165 +153,102 @@ func levelOneRedisSearch(ctx context.Context, rdb *redis.Client, hierarchy const
|
|||
// RedisSearchRecommend define func of redis search by input string and return recommend results
|
||||
func RedisSearchRecommend(ctx context.Context, input string) map[string]SearchResult {
|
||||
rdb := diagram.GetRedisClientInstance()
|
||||
finalizeResults := func(results map[string]SearchResult) map[string]SearchResult {
|
||||
finalizeResults := func(normalizeInput string, results map[string]SearchResult) map[string]SearchResult {
|
||||
results = suppressFallbackResultsWhenConcreteHitExists(results)
|
||||
return normalizeRecommendResults(input, results)
|
||||
return normalizeRecommendResults(normalizeInput, results)
|
||||
}
|
||||
|
||||
if input == "" {
|
||||
fanInChan := make(chan SearchResult, 2)
|
||||
// return all grid tagname
|
||||
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", "recommend_type", result.RecommendType, "error", result.Err)
|
||||
continue
|
||||
}
|
||||
|
||||
if result.RecommendType == constants.CompNSPathRecommendHierarchyType {
|
||||
result.QueryDatas = filterLocalNSPathResults(result.QueryDatas)
|
||||
}
|
||||
results[result.RecommendType.String()] = result
|
||||
}
|
||||
|
||||
return finalizeResults(results)
|
||||
if input == "" || shouldFallbackToInitialRecommend(input) {
|
||||
results := runRecommendSearches(ctx, "return all keys at the special level from redis failed", true,
|
||||
func() SearchResult {
|
||||
return getAllKeyByGridLevel(ctx, rdb)
|
||||
},
|
||||
func() SearchResult {
|
||||
return getAllKeyByNSPathLevel(ctx, rdb)
|
||||
},
|
||||
)
|
||||
return finalizeResults("", results)
|
||||
}
|
||||
|
||||
inputSlice := strings.Split(input, ".")
|
||||
inputSliceLen := len(inputSlice)
|
||||
|
||||
fanInChan := make(chan SearchResult, 4)
|
||||
switch inputSliceLen {
|
||||
case 1:
|
||||
searchInput := inputSlice[0]
|
||||
// grid tagname search
|
||||
go levelOneRedisSearch(ctx, rdb, constants.GridRecommendHierarchyType, constants.FullRecommendLength, searchInput, constants.RedisAllGridSetKey, fanInChan)
|
||||
// component nspath search
|
||||
go levelOneRedisSearch(ctx, rdb, constants.CompNSPathRecommendHierarchyType, constants.IsLocalRecommendLength, searchInput, constants.RedisAllCompNSPathSetKey, fanInChan)
|
||||
|
||||
results := make(map[string]SearchResult)
|
||||
// TODO 后续根据支持的数据标识语法长度,进行值的变更
|
||||
for range 2 {
|
||||
result := <-fanInChan
|
||||
if result.Err != nil {
|
||||
logger.Error(ctx, "exec redis fuzzy search by key failed", "recommend_type", result.RecommendType, "error", result.Err)
|
||||
continue
|
||||
}
|
||||
|
||||
if result.RecommendType == constants.CompNSPathRecommendHierarchyType {
|
||||
result.QueryDatas = filterLocalNSPathResults(result.QueryDatas)
|
||||
}
|
||||
results[result.RecommendType.String()] = result
|
||||
}
|
||||
|
||||
return finalizeResults(results)
|
||||
results := runRecommendSearches(ctx, "exec redis fuzzy search by key failed", true,
|
||||
func() SearchResult {
|
||||
return levelOneRedisSearch(ctx, rdb, constants.GridRecommendHierarchyType, constants.FullRecommendLength, searchInput, constants.RedisAllGridSetKey)
|
||||
},
|
||||
func() SearchResult {
|
||||
return levelOneRedisSearch(ctx, rdb, constants.CompNSPathRecommendHierarchyType, constants.IsLocalRecommendLength, searchInput, constants.RedisAllCompNSPathSetKey)
|
||||
},
|
||||
)
|
||||
return finalizeResults(input, results)
|
||||
case 2:
|
||||
// zone tagname search
|
||||
go handleLevelFuzzySearch(ctx, rdb, constants.ZoneRecommendHierarchyType, constants.FullRecommendLength, constants.RedisAllZoneSetKey, inputSlice, fanInChan)
|
||||
// component tagname search
|
||||
go handleLevelFuzzySearch(ctx, rdb, constants.CompTagRecommendHierarchyType, constants.IsLocalRecommendLength, constants.RedisAllCompTagSetKey, inputSlice, fanInChan)
|
||||
// measurement tagname search by token4-token7 shorthand
|
||||
go handleNSPathMeasSearch(ctx, rdb, inputSlice, fanInChan)
|
||||
results := make(map[string]SearchResult)
|
||||
for range 3 {
|
||||
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 finalizeResults(results)
|
||||
results := runRecommendSearches(ctx, "query all keys at the special level from redis failed", false,
|
||||
func() SearchResult {
|
||||
return handleLevelFuzzySearch(ctx, rdb, constants.ZoneRecommendHierarchyType, constants.FullRecommendLength, constants.RedisAllZoneSetKey, inputSlice)
|
||||
},
|
||||
func() SearchResult {
|
||||
return handleLevelFuzzySearch(ctx, rdb, constants.CompTagRecommendHierarchyType, constants.IsLocalRecommendLength, constants.RedisAllCompTagSetKey, inputSlice)
|
||||
},
|
||||
func() SearchResult {
|
||||
return handleNSPathMeasSearch(ctx, rdb, inputSlice)
|
||||
},
|
||||
)
|
||||
return finalizeResults(input, results)
|
||||
case 3:
|
||||
// station tanname search
|
||||
go handleLevelFuzzySearch(ctx, rdb, constants.StationRecommendHierarchyType, constants.FullRecommendLength, constants.RedisAllStationSetKey, inputSlice, fanInChan)
|
||||
// config search
|
||||
go handleLevelFuzzySearch(ctx, rdb, constants.ConfigRecommendHierarchyType, constants.IsLocalRecommendLength, 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 finalizeResults(results)
|
||||
results := runRecommendSearches(ctx, "query all keys at the special level from redis failed", false,
|
||||
func() SearchResult {
|
||||
return handleLevelFuzzySearch(ctx, rdb, constants.StationRecommendHierarchyType, constants.FullRecommendLength, constants.RedisAllStationSetKey, inputSlice)
|
||||
},
|
||||
func() SearchResult {
|
||||
return handleLevelFuzzySearch(ctx, rdb, constants.ConfigRecommendHierarchyType, constants.IsLocalRecommendLength, constants.RedisAllConfigSetKey, inputSlice)
|
||||
},
|
||||
)
|
||||
return finalizeResults(input, results)
|
||||
case 4:
|
||||
// component nspath search
|
||||
go handleLevelFuzzySearch(ctx, rdb, constants.CompNSPathRecommendHierarchyType, constants.FullRecommendLength, constants.RedisAllCompNSPathSetKey, inputSlice, fanInChan)
|
||||
// measurement tagname search
|
||||
go handleLevelFuzzySearch(ctx, rdb, constants.MeasTagRecommendHierarchyType, constants.IsLocalRecommendLength, 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 finalizeResults(results)
|
||||
results := runRecommendSearches(ctx, "query all keys at the special level from redis failed", false,
|
||||
func() SearchResult {
|
||||
return handleLevelFuzzySearch(ctx, rdb, constants.CompNSPathRecommendHierarchyType, constants.FullRecommendLength, constants.RedisAllCompNSPathSetKey, inputSlice)
|
||||
},
|
||||
func() SearchResult {
|
||||
return handleLevelFuzzySearch(ctx, rdb, constants.MeasTagRecommendHierarchyType, constants.IsLocalRecommendLength, constants.RedisAllConfigSetKey, inputSlice)
|
||||
},
|
||||
)
|
||||
return finalizeResults(input, results)
|
||||
case 5:
|
||||
// component tagname search
|
||||
go handleLevelFuzzySearch(ctx, rdb, constants.CompTagRecommendHierarchyType, constants.FullRecommendLength, constants.RedisAllCompTagSetKey, inputSlice, fanInChan)
|
||||
|
||||
results := make(map[string]SearchResult)
|
||||
for range 1 {
|
||||
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 finalizeResults(results)
|
||||
results := runRecommendSearches(ctx, "query all keys at the special level from redis failed", false,
|
||||
func() SearchResult {
|
||||
return handleLevelFuzzySearch(ctx, rdb, constants.CompTagRecommendHierarchyType, constants.FullRecommendLength, constants.RedisAllCompTagSetKey, inputSlice)
|
||||
},
|
||||
)
|
||||
return finalizeResults(input, results)
|
||||
case 6:
|
||||
// config search
|
||||
go handleLevelFuzzySearch(ctx, rdb, constants.ConfigRecommendHierarchyType, constants.FullRecommendLength, constants.RedisAllConfigSetKey, inputSlice, fanInChan)
|
||||
|
||||
results := make(map[string]SearchResult)
|
||||
for range 1 {
|
||||
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 finalizeResults(results)
|
||||
results := runRecommendSearches(ctx, "query all keys at the special level from redis failed", false,
|
||||
func() SearchResult {
|
||||
return handleLevelFuzzySearch(ctx, rdb, constants.ConfigRecommendHierarchyType, constants.FullRecommendLength, constants.RedisAllConfigSetKey, inputSlice)
|
||||
},
|
||||
)
|
||||
return finalizeResults(input, results)
|
||||
case 7:
|
||||
// measurement tagname search
|
||||
go handleLevelFuzzySearch(ctx, rdb, constants.MeasTagRecommendHierarchyType, constants.FullRecommendLength, constants.RedisAllMeasTagSetKey, inputSlice, fanInChan)
|
||||
|
||||
results := make(map[string]SearchResult)
|
||||
for range 1 {
|
||||
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 finalizeResults(results)
|
||||
results := runRecommendSearches(ctx, "query all keys at the special level from redis failed", false,
|
||||
func() SearchResult {
|
||||
return handleLevelFuzzySearch(ctx, rdb, constants.MeasTagRecommendHierarchyType, constants.FullRecommendLength, constants.RedisAllMeasTagSetKey, inputSlice)
|
||||
},
|
||||
)
|
||||
return finalizeResults(input, results)
|
||||
default:
|
||||
logger.Error(ctx, "unsupport length of search input", "input_len", inputSliceLen)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func shouldFallbackToInitialRecommend(input string) bool {
|
||||
return strings.HasPrefix(input, ".")
|
||||
}
|
||||
|
||||
// suppressFallbackResultsWhenConcreteHitExists 有明确命中时丢弃兜底结果, 避免返回过宽推荐。
|
||||
func suppressFallbackResultsWhenConcreteHitExists(results map[string]SearchResult) map[string]SearchResult {
|
||||
hasConcreteHit := false
|
||||
|
|
@ -494,23 +460,22 @@ func getAllSetKeyByHierarchy(hierarchy constants.RecommendHierarchyType) (string
|
|||
}
|
||||
|
||||
// getAllKeyByGridLevel 返回所有 grid tag, 用于空输入时的初始推荐。
|
||||
func getAllKeyByGridLevel(ctx context.Context, rdb *redis.Client, fanInChan chan SearchResult) {
|
||||
func getAllKeyByGridLevel(ctx context.Context, rdb *redis.Client) SearchResult {
|
||||
setKey := constants.RedisAllGridSetKey
|
||||
hierarchy := constants.GridRecommendHierarchyType
|
||||
members, err := rdb.SMembers(ctx, setKey).Result()
|
||||
if err != nil && err != redigo.ErrNil {
|
||||
logger.Error(ctx, "get all members from redis by special key failed", "key", setKey, "op", "SMembers", "error", err)
|
||||
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: false,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: members,
|
||||
IsFuzzy: false,
|
||||
|
|
@ -519,23 +484,22 @@ func getAllKeyByGridLevel(ctx context.Context, rdb *redis.Client, fanInChan chan
|
|||
}
|
||||
|
||||
// getAllKeyByNSPathLevel 返回所有组件 nspath, 用于空输入时的初始推荐。
|
||||
func getAllKeyByNSPathLevel(ctx context.Context, rdb *redis.Client, fanInChan chan SearchResult) {
|
||||
func getAllKeyByNSPathLevel(ctx context.Context, rdb *redis.Client) SearchResult {
|
||||
queryKey := constants.RedisAllCompNSPathSetKey
|
||||
hierarchy := constants.CompNSPathRecommendHierarchyType
|
||||
members, err := rdb.SMembers(ctx, queryKey).Result()
|
||||
if err != nil && err != redigo.ErrNil {
|
||||
logger.Error(ctx, "get all members by special key failed", "key", queryKey, "op", "SMembers", "error", err)
|
||||
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: false,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: members,
|
||||
IsFuzzy: false,
|
||||
|
|
@ -611,7 +575,7 @@ func getSpecificKeyByLength(hierarchy constants.RecommendHierarchyType, keyPrefi
|
|||
}
|
||||
|
||||
// handleNSPathMeasSearch 处理 nspath.measurement 的简写搜索路径。
|
||||
func handleNSPathMeasSearch(ctx context.Context, rdb *redis.Client, inputSlice []string, fanInChan chan SearchResult) {
|
||||
func handleNSPathMeasSearch(ctx context.Context, rdb *redis.Client, inputSlice []string) SearchResult {
|
||||
hierarchy := constants.MeasTagRecommendHierarchyType
|
||||
nsPath := inputSlice[0]
|
||||
searchInput := inputSlice[1]
|
||||
|
|
@ -619,22 +583,20 @@ func handleNSPathMeasSearch(ctx context.Context, rdb *redis.Client, inputSlice [
|
|||
nsPathExists, err := rdb.SIsMember(ctx, constants.RedisAllCompNSPathSetKey, nsPath).Result()
|
||||
if err != nil {
|
||||
logger.Error(ctx, "check nspath exist from redis set failed", "key", constants.RedisAllCompNSPathSetKey, "nspath", nsPath, "error", err)
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: false,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
if !nsPathExists {
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: []string{},
|
||||
IsFuzzy: false,
|
||||
Err: nil,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
queryKey := fmt.Sprintf(constants.RedisSpecCompNSPathMeasSetKey, nsPath)
|
||||
|
|
@ -642,57 +604,52 @@ func handleNSPathMeasSearch(ctx context.Context, rdb *redis.Client, inputSlice [
|
|||
members, err := rdb.SMembers(ctx, queryKey).Result()
|
||||
if err != nil && err != redis.Nil {
|
||||
logger.Error(ctx, "query measurement tags by nspath failed", "key", queryKey, "nspath", nsPath, "error", err)
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: false,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: combineNSPathMeasResults(nsPath, members),
|
||||
IsFuzzy: false,
|
||||
Err: nil,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
measTagExists, err := rdb.SIsMember(ctx, queryKey, searchInput).Result()
|
||||
if err != nil {
|
||||
logger.Error(ctx, "check measurement tag exist from nspath set failed", "key", queryKey, "meas_tag", searchInput, "error", err)
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: false,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
if measTagExists {
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: []string{""},
|
||||
IsFuzzy: false,
|
||||
Err: nil,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
recommends, offset, err := runNSPathMeasFuzzySearch(ctx, nsPath, searchInput)
|
||||
if err != nil {
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: true,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: recommends,
|
||||
IsFuzzy: true,
|
||||
|
|
@ -760,7 +717,7 @@ func splitLastToken(term string) (string, string) {
|
|||
}
|
||||
|
||||
// handleLevelFuzzySearch 处理第二层及以后层级的精确、模糊和兜底推荐。
|
||||
func handleLevelFuzzySearch(ctx context.Context, rdb *redis.Client, hierarchy constants.RecommendHierarchyType, recommendLenType string, redisSetKey string, inputSlice []string, fanInChan chan SearchResult) {
|
||||
func handleLevelFuzzySearch(ctx context.Context, rdb *redis.Client, hierarchy constants.RecommendHierarchyType, recommendLenType string, redisSetKey string, inputSlice []string) SearchResult {
|
||||
inputSliceLen := len(inputSlice)
|
||||
searchInputIndex := inputSliceLen - 1
|
||||
searchInput := inputSlice[searchInputIndex]
|
||||
|
|
@ -783,36 +740,33 @@ func handleLevelFuzzySearch(ctx context.Context, rdb *redis.Client, hierarchy co
|
|||
keyExists, err := rdb.SIsMember(ctx, redisSetKey, specificalKey).Result()
|
||||
if err != nil {
|
||||
logger.Error(ctx, "check key exist from redis set failed ", "key", redisSetKey, "error", err)
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: false,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !keyExists {
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: []string{},
|
||||
IsFuzzy: false,
|
||||
Err: nil,
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
members, err := queryMemberFromSpecificsLevel(ctx, rdb, hierarchy, specificalKey)
|
||||
if err != nil && err != redis.Nil {
|
||||
logger.Error(ctx, "query members from redis by special key failed", "key", specificalKey, "member", searchInput, "op", "SMember", "error", err)
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: false,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
recommandResults := combineQueryResultByInput(hierarchy, recommendLenType, inputSlice, members)
|
||||
|
|
@ -838,25 +792,23 @@ func handleLevelFuzzySearch(ctx context.Context, rdb *redis.Client, hierarchy co
|
|||
}
|
||||
recommandResults = secondConfirmResults
|
||||
}
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: recommandResults,
|
||||
IsFuzzy: false,
|
||||
Err: nil,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
keyExists, err := rdb.SIsMember(ctx, redisSetKey, searchInput).Result()
|
||||
if err != nil {
|
||||
logger.Error(ctx, "check key exist from redis set failed ", "key", redisSetKey, "error", err)
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: false,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if keyExists {
|
||||
|
|
@ -867,26 +819,24 @@ func handleLevelFuzzySearch(ctx context.Context, rdb *redis.Client, hierarchy co
|
|||
QueryData = []string{"."}
|
||||
}
|
||||
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: QueryData,
|
||||
IsFuzzy: false,
|
||||
Err: nil,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// start redis fuzzy search
|
||||
recommends, offset, err := runFuzzySearch(ctx, rdb, searchInput, searchPrefix, hierarchy, recommendLenType)
|
||||
if err != nil {
|
||||
logger.Error(ctx, "fuzzy search failed by hierarchy", "hierarchy", hierarchy, "search_input", searchInput, "error", err)
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: false,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
isFallback := false
|
||||
|
|
@ -895,20 +845,19 @@ func handleLevelFuzzySearch(ctx context.Context, rdb *redis.Client, hierarchy co
|
|||
recommends, err = fallbackCurrentLevelByInput(ctx, rdb, hierarchy, inputSlice)
|
||||
if err != nil {
|
||||
logger.Error(ctx, "fallback all keys at current level failed", "hierarchy", hierarchy, "search_input", searchInput, "error", err)
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: nil,
|
||||
IsFuzzy: true,
|
||||
IsFallback: true,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
isFallback = true
|
||||
offset = 0
|
||||
}
|
||||
|
||||
fanInChan <- SearchResult{
|
||||
return SearchResult{
|
||||
RecommendType: hierarchy,
|
||||
QueryDatas: recommends,
|
||||
IsFuzzy: true,
|
||||
|
|
@ -992,7 +941,7 @@ func runFuzzySearch(ctx context.Context, rdb *redis.Client, searchInput string,
|
|||
}
|
||||
|
||||
if termHierarchyLen == compareHierarchyLen && termPrefix == comparePrefix && strings.HasPrefix(termLastPart, searchInput) {
|
||||
exists, err := fuzzyRecommendMemberExists(ctx, rdb, hierarchy, recommendLenType, comparePrefix, termLastPart)
|
||||
exists, err := fuzzyRecommendMemberExists(ctx, rdb, hierarchy, comparePrefix, termLastPart)
|
||||
if err != nil || !exists {
|
||||
logger.Info(ctx, "fuzzy recommend term not found in specific redis set",
|
||||
"hierarchy", hierarchy,
|
||||
|
|
@ -1034,8 +983,8 @@ func fuzzyRecommendOffset(searchPrefix string, searchInput string) int {
|
|||
}
|
||||
|
||||
// fuzzyRecommendMemberExists 校验模糊候选末级 token 是否存在于对应 Redis set。
|
||||
func fuzzyRecommendMemberExists(ctx context.Context, rdb *redis.Client, hierarchy constants.RecommendHierarchyType, recommendLenType string, comparePrefix string, termLastPart string) (bool, error) {
|
||||
setKey, ok := fuzzyRecommendMemberSetKey(hierarchy, recommendLenType, comparePrefix)
|
||||
func fuzzyRecommendMemberExists(ctx context.Context, rdb *redis.Client, hierarchy constants.RecommendHierarchyType, comparePrefix string, termLastPart string) (bool, error) {
|
||||
setKey, ok := fuzzyRecommendMemberSetKey(hierarchy, comparePrefix)
|
||||
if !ok {
|
||||
return true, nil
|
||||
}
|
||||
|
|
@ -1043,7 +992,7 @@ func fuzzyRecommendMemberExists(ctx context.Context, rdb *redis.Client, hierarch
|
|||
}
|
||||
|
||||
// fuzzyRecommendMemberSetKey 返回模糊候选校验时应使用的 Redis set key。
|
||||
func fuzzyRecommendMemberSetKey(hierarchy constants.RecommendHierarchyType, recommendLenType string, comparePrefix string) (string, bool) {
|
||||
func fuzzyRecommendMemberSetKey(hierarchy constants.RecommendHierarchyType, comparePrefix string) (string, bool) {
|
||||
switch hierarchy {
|
||||
case constants.GridRecommendHierarchyType:
|
||||
return constants.RedisAllGridSetKey, true
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// GenNanoTsStr define func to generate nanosecond timestamp string by current time
|
||||
func GenNanoTsStr() string {
|
||||
// GenNanoTSStr define func to generate nanosecond timestamp string by current time
|
||||
func GenNanoTSStr() string {
|
||||
now := time.Now()
|
||||
nanoseconds := now.UnixNano()
|
||||
timestampStr := strconv.FormatInt(nanoseconds, 10)
|
||||
|
|
|
|||
Loading…
Reference in New Issue