sort/mix_sort_strategy.go (178 lines of code) (raw):

package sort import ( "math/rand" "github.com/alibaba/pairec/v2/module" "github.com/alibaba/pairec/v2/recconf" "github.com/alibaba/pairec/v2/utils" ) type MixSortStrategyType int const ( FixPositionStrategyType MixSortStrategyType = 1 RandomPositionStrategyType MixSortStrategyType = 2 DefaultStrategyType MixSortStrategyType = 3 ) type MixSortStrategy interface { ContainsRecallName(name string) bool AppendItem(item *module.Item) IsFull() bool GetStrategyType() MixSortStrategyType BuildItems(items []*module.Item) []*module.Item Evaluate(properties map[string]interface{}) (bool, error) EvaluateByDomain(userProperties, itemProperties map[string]interface{}) (bool, error) IsUseCondition() bool } type mixSortStrategy struct { number int totalSize int index int strategyType MixSortStrategyType recallNameMap map[string]bool items []*module.Item filterParam *module.FilterParam } func (s *mixSortStrategy) ContainsRecallName(name string) bool { if s.strategyType == DefaultStrategyType { return true } if _, ok := s.recallNameMap[name]; ok { return true } return false } func (s *mixSortStrategy) Evaluate(properties map[string]interface{}) (bool, error) { ok, err := s.filterParam.Evaluate(properties) if err != nil { return false, err } return ok, nil } func (s *mixSortStrategy) EvaluateByDomain(userProperties, itemProperties map[string]interface{}) (bool, error) { ok, err := s.filterParam.EvaluateByDomain(userProperties, itemProperties) if err != nil { return false, err } return ok, nil } func (s *mixSortStrategy) AppendItem(item *module.Item) { if len(s.items) == s.number { return } s.items = append(s.items, item) } func (s *mixSortStrategy) IsFull() bool { return len(s.items) >= s.number } func (s *mixSortStrategy) IsUseCondition() bool { /** if s.filterParam != nil { return true } return false **/ return s.filterParam != nil } func (s *mixSortStrategy) GetStrategyType() MixSortStrategyType { return s.strategyType } func newMixSortStrategy(config *recconf.MixSortConfig) *mixSortStrategy { strategy := mixSortStrategy{ number: 0, index: 0, recallNameMap: make(map[string]bool), } if config != nil { for _, name := range config.RecallNames { strategy.recallNameMap[name] = true } } if config != nil { if len(config.Conditions) > 0 { filterParam := module.NewFilterParamWithConfig(config.Conditions) strategy.filterParam = filterParam } } return &strategy } type fixPositionStrategy struct { *mixSortStrategy positions []int positionField string } func newFixPositionStrategy(config *recconf.MixSortConfig) *fixPositionStrategy { strategy := fixPositionStrategy{ positions: config.Positions, positionField: config.PositionField, mixSortStrategy: newMixSortStrategy(config), } strategy.number = len(strategy.positions) if strategy.number == 0 && config.Number > 0 { strategy.number = config.Number } strategy.strategyType = FixPositionStrategyType return &strategy } func (s *fixPositionStrategy) BuildItems(items []*module.Item) []*module.Item { if len(s.positions) == 0 && s.positionField != "" { for i := 0; i < s.number; i++ { if i < len(s.items) { if p := utils.ToInt(s.items[i].GetProperty(s.positionField), -1); p > 0 { s.positions = append(s.positions, p) } } } } for _, pos := range s.positions { if pos <= s.totalSize && s.index < len(s.items) { items[pos-1] = s.items[s.index] s.index++ } } return items } type randomPositionStrategy struct { *mixSortStrategy } func newRandomPositionStrategy(config *recconf.MixSortConfig, size int) *randomPositionStrategy { strategy := randomPositionStrategy{ mixSortStrategy: newMixSortStrategy(config), } if config.NumberRate > float64(0) { strategy.number = int(float64(size) * config.NumberRate) } else if config.Number > 0 { strategy.number = config.Number } strategy.strategyType = RandomPositionStrategyType return &strategy } func (s *randomPositionStrategy) BuildItems(items []*module.Item) []*module.Item { start := 0 end := 0 for _, item := range s.items { end = start + rand.Intn(s.totalSize/s.number) if end >= s.totalSize { end = s.totalSize - 1 } for items[end] != nil { end++ end = end % s.totalSize } items[end] = item start += s.totalSize / s.number } return items } type defaultStrategy struct { *mixSortStrategy } func newDefaultStrategy(config *recconf.MixSortConfig, size int) *defaultStrategy { strategy := defaultStrategy{ mixSortStrategy: newMixSortStrategy(config), } strategy.totalSize = size strategy.number = size strategy.strategyType = DefaultStrategyType return &strategy } func (s *defaultStrategy) BuildItems(items []*module.Item) []*module.Item { for i, item := range items { if item == nil && s.index < len(s.items) { items[i] = s.items[s.index] s.index++ } } return items }