sort/sort.go (191 lines of code) (raw):

package sort import ( "encoding/json" "fmt" "time" "github.com/alibaba/pairec/v2/context" "github.com/alibaba/pairec/v2/log" "github.com/alibaba/pairec/v2/module" "github.com/alibaba/pairec/v2/recconf" "github.com/alibaba/pairec/v2/utils" ) var sortMapping = make(map[string]ISort) var sortSigns = make(map[string]string) var sortService *SortService // var sortMapping map[string]ISort func init() { sortService = &SortService{} sortService.SortStrategies = make(map[string][]ISort, 0) } type SortData struct { Data interface{} Context *context.RecommendContext User *module.User PipelineName string } type ISort interface { Sort(sortData *SortData) error } type ICloneSort interface { CloneWithConfig(params map[string]interface{}) ISort GetSortName() string } type SortService struct { SortStrategies map[string][]ISort } func (ss *SortService) AddSort(scene string, s ISort) { sorts, ok := ss.SortStrategies[scene] if ok { for _, sort := range sorts { if sort == s { return } } sorts = append(sorts, s) ss.SortStrategies[scene] = sorts } else { sorts := []ISort{s} ss.SortStrategies[scene] = sorts } } func (ss *SortService) AddSorts(scene string, sorts []ISort) { ss.SortStrategies[scene] = sorts } func (ss *SortService) Sort(data *SortData, tag string) { var scene string ctx := data.Context s := ctx.GetParameter("scene") if _, ok := s.(string); ok { scene = s.(string) } var categoryName string c := ctx.GetParameter("category") if _, ok := c.(string); ok { categoryName = c.(string) } else { categoryName = "default" } sorts := make([]ISort, 0) if ctx.ExperimentResult != nil { names := ctx.ExperimentResult.GetExperimentParams().Get(categoryName+".SortNames", nil) if names != nil { if values, ok := names.([]interface{}); ok { for _, v := range values { if name, okay := v.(string); okay { if sort, found := sortMapping[name]; found { sorts = append(sorts, sort) } } } } } } if len(sorts) == 0 { scene = scene + tag var ok bool sorts, ok = ss.SortStrategies[scene] if !ok { sorts, ok = ss.SortStrategies[categoryName] } if !ok || sorts == nil || len(sorts) == 0 { sorts = make([]ISort, 1) sorts[0] = NewItemRankScoreSort() ctx.LogInfo(fmt.Sprintf("defaultSort=ItemRankScore\tscene=%s", scene)) } } for _, sort := range sorts { newSort := sort if cloneSort, ok := sort.(ICloneSort); ok && ctx.ExperimentResult != nil { sortConfig := ctx.ExperimentResult.GetExperimentParams().Get("sort."+cloneSort.GetSortName(), nil) if sortConfig != nil { if params, ok := sortConfig.(map[string]interface{}); ok { if sortInstance := cloneSort.CloneWithConfig(params); !utils.IsNil(sortInstance) { newSort = sortInstance } } } } newSort.Sort(data) } } func Load(config *recconf.RecommendConfig) { for scene, names := range config.SortNames { var sorts []ISort for _, name := range names { if sort, ok := sortMapping[name]; ok { sorts = append(sorts, sort) } } sortService.AddSorts(scene, sorts) } } func Sort(sortData *SortData, tag string) { sortService.Sort(sortData, tag) } func RegisterSort(name string, s ISort) { if s == nil { panic("Sort is nil, name:" + name) } if _, ok := sortMapping[name]; !ok { sortMapping[name] = s } } // GetSort return sort by name func GetSort(name string) (ISort, error) { sort, ok := sortMapping[name] if !ok { return nil, fmt.Errorf("ISort not found, name:%s", name) } return sort, nil } func RegisterSortWithConfig(config *recconf.RecommendConfig) { for _, conf := range config.SortConfs { if _, ok := sortMapping[conf.Name]; ok { sign, _ := json.Marshal(&conf) if utils.Md5(string(sign)) == sortSigns[conf.Name] { continue } } var s ISort if conf.SortType == "DPPSort" { s = NewDPPSort(conf.DPPConf) } else if conf.SortType == "SSDSort" { s = NewSSDSort(conf.SSDConf) } else if conf.SortType == "MultiRecallMixSort" { s = NewMultiRecallMixSort(conf) } else if conf.SortType == "BoostScoreSort" { s = NewBoostScoreSort(conf) } else if conf.SortType == "DiversityRuleSort" { s = NewDiversityRuleSort(conf) } else if conf.SortType == "AlgoScoreSort" { s = NewAlgoScoreSort(conf) } else if conf.SortType == "TrafficControlSort" { s = NewTrafficControlSort(conf) } else if conf.SortType == "BoostScoreByWeight" { s = NewBoostScoreByWeight(conf) } else if conf.SortType == "DistinctIdSort" { s = NewDistinctIdSort(conf) } if s == nil { panic("Sort is nil, name:" + conf.Name) } sign, _ := json.Marshal(&conf) registerSortWithSign(conf.Name, s, utils.Md5(string(sign))) } } func registerSortWithSign(name string, sort ISort, sign string) { sortMapping[name] = sort sortSigns[name] = sign } func sortInfoLog(sortData *SortData, module string, count int, start time.Time) { if sortData.PipelineName != "" { log.Info(fmt.Sprintf("requestId=%s\tmodule=%s\tpipeline=%s\tcount=%d\tcost=%d", sortData.Context.RecommendId, module, sortData.PipelineName, count, utils.CostTime(start))) } else { log.Info(fmt.Sprintf("requestId=%s\tmodule=%s\tcount=%d\tcost=%d", sortData.Context.RecommendId, module, count, utils.CostTime(start))) } } func sortInfoLogWithName(sortData *SortData, module, name string, count int, start time.Time) { if sortData.PipelineName != "" { log.Info(fmt.Sprintf("requestId=%s\tmodule=%s\tname=%s\tpipeline=%s\tcount=%d\tcost=%d", sortData.Context.RecommendId, module, name, sortData.PipelineName, count, utils.CostTime(start))) } else { log.Info(fmt.Sprintf("requestId=%s\tmodule=%s\tname=%s\tcount=%d\tcost=%d", sortData.Context.RecommendId, module, name, count, utils.CostTime(start))) } }