Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions module/realtime_user2item_featurestore_dao.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,12 @@ func (d *RealtimeUser2ItemFeatureStoreDao) ListItemsByUser(user *User, context *
d.cache.Put(triggerId, d.convertItemsToString(items))
}
}
//negative cache set, if itemId(triggerId) not have data in feature store, set empty string
for _, itemId := range itemIds {
if _, exist := d.cache.GetIfPresent(itemId); !exist {
d.cache.Put(itemId, "")
}
}
}
}
// sort items
Expand Down
5 changes: 5 additions & 0 deletions recconf/recconf.go
Original file line number Diff line number Diff line change
Expand Up @@ -765,8 +765,13 @@ type SortConfig struct {
ExclusionRules []ExclusionRuleConfig
TimeInterval int
BoostScoreByWeightDao BoostScoreByWeightDaoConfig
MultiValueDimensionConf []MultiValueDimensionConfig
}

type MultiValueDimensionConfig struct {
DimensionName string
Delimiter string
}
type BoostScoreByWeightDaoConfig struct {
DaoConfig
ItemFieldName string
Expand Down
122 changes: 122 additions & 0 deletions sort/diversity_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,18 @@ import (

"github.com/alibaba/pairec/v2/module"
"github.com/alibaba/pairec/v2/recconf"
"github.com/alibaba/pairec/v2/utils"
)

type DiversityMatchFunc func(item *module.Item) bool

type DiversityRuleInterface interface {
Match(item *module.Item, itemList []*module.Item) bool
GetWeight() int
}

var _ DiversityRuleInterface = (*DiversityRule)(nil)

type DiversityRule struct {
DiversityRuleConfig recconf.DiversityRuleConfig
DimensionItemMap map[module.ItemId]string
Expand Down Expand Up @@ -86,3 +95,116 @@ func (r *DiversityRule) GetWeight() int {
return r.DiversityRuleConfig.Weight

}

var _ DiversityRuleInterface = (*DiversityRuleMultiDimension)(nil)

type DiversityRuleMultiDimension struct {
DiversityRuleConfig recconf.DiversityRuleConfig
DimensionItemMap map[module.ItemId][]any
multiDimensionMap map[int]recconf.MultiValueDimensionConfig
}

func NewDiversityRuleMultiDimension(config recconf.DiversityRuleConfig, size int, multiDimensionMap map[int]recconf.MultiValueDimensionConfig) *DiversityRuleMultiDimension {
rule := DiversityRuleMultiDimension{
DiversityRuleConfig: config,
DimensionItemMap: make(map[module.ItemId][]any, size),
multiDimensionMap: multiDimensionMap,
}

return &rule
}

func (r *DiversityRuleMultiDimension) GetDimensionValue(item *module.Item) []any {
if value, ok := r.DimensionItemMap[item.Id]; ok {
return value
}

var dimensionValues []any
for i, dimension := range r.DiversityRuleConfig.Dimensions {
multiDimensionConf, ok := r.multiDimensionMap[i]
if ok {
value := item.StringProperty(dimension)
strs := strings.Split(value, multiDimensionConf.Delimiter)
dimensionValues = append(dimensionValues, strs)
} else {
value := item.StringProperty(dimension)
dimensionValues = append(dimensionValues, value)
}
}

r.DimensionItemMap[item.Id] = dimensionValues

return r.DimensionItemMap[item.Id]
}

func (r *DiversityRuleMultiDimension) Match(item *module.Item, itemList []*module.Item) bool {
size := len(itemList)

itemDimensionValues := r.GetDimensionValue(item)
if r.DiversityRuleConfig.IntervalSize > 0 && size >= r.DiversityRuleConfig.IntervalSize {
end := size
begin := size - r.DiversityRuleConfig.IntervalSize
sameValue := 1
for i := end - 1; i >= begin; i-- {
if r.isDimensionValuesEqual(itemDimensionValues, r.GetDimensionValue(itemList[i])) {
sameValue++
} else {
break
}
}

if sameValue > r.DiversityRuleConfig.IntervalSize {
return false
}

}
if r.DiversityRuleConfig.WindowSize > 0 &&
r.DiversityRuleConfig.FrequencySize > 0 &&
r.DiversityRuleConfig.WindowSize > r.DiversityRuleConfig.FrequencySize {
end := size
begin := size - r.DiversityRuleConfig.WindowSize + 1
if begin < 0 {
begin = 0
}

sameValue := 1
for i := begin; i < end; i++ {
if r.isDimensionValuesEqual(itemDimensionValues, r.GetDimensionValue(itemList[i])) {
sameValue++
}

if sameValue > r.DiversityRuleConfig.FrequencySize {
return false
}
}
}
return true
}

func (r *DiversityRuleMultiDimension) GetWeight() int {
return r.DiversityRuleConfig.Weight
}
func (r *DiversityRuleMultiDimension) isDimensionValuesEqual(left, right []any) bool {
if len(left) != len(right) {
return false
}
for i := 0; i < len(left); i++ {
switch left[i].(type) {
case string:
if left[i] != right[i] {
return false
}
case []string:
leftValues := left[i].([]string)
if rightValues, ok := right[i].([]string); ok {
if !utils.StringContains(leftValues, rightValues) {
return false
}

} else {
return false
}
}
}
return true
}
62 changes: 43 additions & 19 deletions sort/diversity_rule_sort.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,29 @@ import (
)

type DiversityRuleSort struct {
diversitySize int
diversityRules []recconf.DiversityRuleConfig
exclusionRules []recconf.ExclusionRuleConfig
excludeRecallMap map[string]bool
filterParam *module.FilterParam
cloneInstances map[string]*DiversityRuleSort
name string
exploreItemSize int
diversitySize int
diversityRules []recconf.DiversityRuleConfig
exclusionRules []recconf.ExclusionRuleConfig
excludeRecallMap map[string]bool
filterParam *module.FilterParam
cloneInstances map[string]*DiversityRuleSort
name string
exploreItemSize int
multiValueDimensionConf []recconf.MultiValueDimensionConfig
multiDimensionMaps []map[int]recconf.MultiValueDimensionConfig // size is equal config.DiversityRules, per entry is map of multi dimension config for each diversity rule of dimensions
}

func NewDiversityRuleSort(config recconf.SortConfig) *DiversityRuleSort {
sort := DiversityRuleSort{
diversitySize: config.DiversitySize,
diversityRules: config.DiversityRules,
exclusionRules: config.ExclusionRules,
excludeRecallMap: make(map[string]bool, len(config.ExcludeRecalls)),
filterParam: nil,
name: config.Name,
cloneInstances: make(map[string]*DiversityRuleSort),
exploreItemSize: -1,
diversitySize: config.DiversitySize,
diversityRules: config.DiversityRules,
exclusionRules: config.ExclusionRules,
excludeRecallMap: make(map[string]bool, len(config.ExcludeRecalls)),
filterParam: nil,
name: config.Name,
cloneInstances: make(map[string]*DiversityRuleSort),
exploreItemSize: -1,
multiValueDimensionConf: config.MultiValueDimensionConf,
}

for _, recallName := range config.ExcludeRecalls {
Expand All @@ -43,6 +46,22 @@ func NewDiversityRuleSort(config recconf.SortConfig) *DiversityRuleSort {
if config.ExploreItemSize > 0 {
sort.exploreItemSize = config.ExploreItemSize
}
if len(config.MultiValueDimensionConf) > 0 {
for _, diversityRuleConfig := range sort.diversityRules {
multiDimensionMap := make(map[int]recconf.MultiValueDimensionConfig)
for i, dimension := range diversityRuleConfig.Dimensions {
for _, multiDimension := range config.MultiValueDimensionConf {
if multiDimension.DimensionName == dimension {
multiDimensionMap[i] = multiDimension
break
}
}
}
sort.multiDimensionMaps = append(sort.multiDimensionMaps, multiDimensionMap)

}

}

return &sort
}
Expand All @@ -68,9 +87,14 @@ func (s *DiversityRuleSort) Sort(sortData *SortData) error {
return nil
}

func (s *DiversityRuleSort) createDiversityRules(size int) (ret []*DiversityRule) {
for _, config := range s.diversityRules {
rule := NewDiversityRule(config, size)
func (s *DiversityRuleSort) createDiversityRules(size int) (ret []DiversityRuleInterface) {
for i, config := range s.diversityRules {
var rule DiversityRuleInterface
if len(s.multiValueDimensionConf) > 0 {
rule = NewDiversityRuleMultiDimension(config, size, s.multiDimensionMaps[i])
} else {
rule = NewDiversityRule(config, size)
}

ret = append(ret, rule)
}
Expand Down
Loading
Loading