package service import ( "fmt" "sync" "time" "gitlab.alibaba-inc.com/pai_biz_arch/pairec/context" "gitlab.alibaba-inc.com/pai_biz_arch/pairec/log" "gitlab.alibaba-inc.com/pai_biz_arch/pairec/module" "gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf" "gitlab.alibaba-inc.com/pai_biz_arch/pairec/service/feature" "gitlab.alibaba-inc.com/pai_biz_arch/pairec/utils" ) var featureService *FeatureService type FeatureFunc func(user *module.User, items []*module.Item, context *context.RecommendContext) []*module.Item type LoadFeatureFunc func(user *module.User, items []*module.Item, context *context.RecommendContext) func init() { featureService = &FeatureService{ featureSceneMap: make(map[string][]*feature.Feature), featureSceneAsyncMap: make(map[string]bool), featureFuncMap: make(map[string]FeatureFunc), loadFeatureFuncMap: make(map[string]LoadFeatureFunc), } } func DefaultFeatureService() *FeatureService { return featureService } func RegisterFeatureFunc(sceneName string, f FeatureFunc) { DefaultFeatureService().AddFeatureFunc(sceneName, f) } func RegisterLoadFeatureFunc(sceneName string, f LoadFeatureFunc) { DefaultFeatureService().AddLoadFeatureFunc(sceneName, f) } type FeatureService struct { featureSceneMap map[string][]*feature.Feature featureSceneAsyncMap map[string]bool featureFuncMap map[string]FeatureFunc loadFeatureFuncMap map[string]LoadFeatureFunc } func (s *FeatureService) AddFeatureFunc(sceneName string, f FeatureFunc) { s.featureFuncMap[sceneName] = f } func (s *FeatureService) AddLoadFeatureFunc(sceneName string, f LoadFeatureFunc) { s.loadFeatureFuncMap[sceneName] = f } // LoadFeatures load user or item feature use feature.Feature func (s *FeatureService) LoadFeatures(user *module.User, items []*module.Item, context *context.RecommendContext) []*module.Item { start := time.Now() var sceneName string if context.ExperimentResult != nil { sceneName = context.ExperimentResult.GetExperimentParams().GetString("features.scene.name", "") } if sceneName == "" { sceneName = context.GetParameter("scene").(string) } if features, ok := s.featureSceneMap[sceneName]; ok { async := s.featureSceneAsyncMap[sceneName] if async { var wg sync.WaitGroup for _, fea := range features { wg.Add(1) go func(fea *feature.Feature) { defer wg.Done() fea.LoadFeatures(user, items, context) }(fea) } if loadFeatureFunc, exist := s.loadFeatureFuncMap[sceneName]; exist { wg.Add(1) go func() { defer wg.Done() loadFeatureFunc(user, items, context) }() } wg.Wait() } else { for _, feature := range features { feature.LoadFeatures(user, items, context) } if loadFeatureFunc, exist := s.loadFeatureFuncMap[sceneName]; exist { loadFeatureFunc(user, items, context) } } featureFunc, ok := s.featureFuncMap[sceneName] if ok { items = featureFunc(user, items, context) } } log.Info(fmt.Sprintf("requestId=%s\tmodule=LoadFeatures\tcost=%d", context.RecommendId, utils.CostTime(start))) return items } func (s *FeatureService) LoadFeaturesForGeneralRank(user *module.User, items []*module.Item, context *context.RecommendContext) { start := time.Now() sceneName := context.GetParameter("scene").(string) if features, ok := s.featureSceneMap[sceneName]; ok { async := s.featureSceneAsyncMap[sceneName] if async { var wg sync.WaitGroup for _, fea := range features { wg.Add(1) go func(fea *feature.Feature) { defer wg.Done() fea.LoadFeatures(user, items, context) }(fea) } wg.Wait() } else { for _, feature := range features { feature.LoadFeatures(user, items, context) } } // featureFunc, ok := s.featureFuncMap[sceneName] // if ok { // featureFunc(user, items, context) // } } log.Info(fmt.Sprintf("requestId=%s\tmodule=LoadFeaturesForGeneralRank\tcost=%d", context.RecommendId, utils.CostTime(start))) } func LoadFeatureConfig(config *recconf.RecommendConfig) { for name, sceneConf := range config.FeatureConfs { var features []*feature.Feature for _, conf := range sceneConf.FeatureLoadConfs { f := feature.LoadWithConfig(conf) features = append(features, f) } featureService.featureSceneAsyncMap[name] = false if sceneConf.AsynLoadFeature { featureService.featureSceneAsyncMap[name] = true } featureService.featureSceneMap[name] = features } }