From c1b0efd4551418bd4fe53c3cf18dc38fafcae7fd Mon Sep 17 00:00:00 2001 From: DanB Date: Thu, 17 Oct 2024 14:37:54 +0200 Subject: [PATCH] Adding reversed logic for sortingParams in RankingS --- engine/librankings.go | 53 ++++++++++++++++++++++++++++---------- engine/librankings_test.go | 28 ++++++++++++++++++-- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/engine/librankings.go b/engine/librankings.go index 765426c8d..a9d7f841e 100644 --- a/engine/librankings.go +++ b/engine/librankings.go @@ -20,6 +20,7 @@ package engine import ( "sort" + "strings" "sync" "github.com/cgrates/cgrates/utils" @@ -131,8 +132,18 @@ func newRankingSorter(sortingType string, sortingParams []string, // newRankingDescSorter is a constructor for rankingDescSorter func newRankingDescSorter(sortingParams []string, statMetrics map[string]map[string]float64) (rkDsrtr *rankingDescSorter) { + clnSp := make([]string, len(sortingParams)) + sPReversed := make(utils.StringSet) + for i, sP := range sortingParams { // clean the sortingParams, out of param:false or param:true definitions + sPSlc := strings.Split(sP, utils.InInFieldSep) + clnSp[i] = sPSlc[0] + if len(sPSlc) > 1 && sPSlc[1] == utils.FalseStr { + sPReversed.Add(sPSlc[0]) // param defined as param:false which should be added to reversing comparison + } + } rkDsrtr = &rankingDescSorter{ - sortingParams, + clnSp, + sPReversed, statMetrics, make([]string, 0, len(statMetrics))} for statID := range rkDsrtr.statMetrics { @@ -143,8 +154,9 @@ func newRankingDescSorter(sortingParams []string, // rankingDescSorter will sort data descendent for metrics in sortingParams or random if all equal type rankingDescSorter struct { - sortingParams []string - statMetrics map[string]map[string]float64 + sMetricIDs []string + sMetricRev utils.StringSet // list of exceptios for sortingParams, reverting the sorting logic + statMetrics map[string]map[string]float64 statIDs []string // list of keys of the statMetrics } @@ -155,7 +167,7 @@ func (rkDsrtr *rankingDescSorter) sortStatIDs() []string { return rkDsrtr.statIDs } sort.Slice(rkDsrtr.statIDs, func(i, j int) bool { - for _, metricID := range rkDsrtr.sortingParams { + for _, metricID := range rkDsrtr.sMetricIDs { val1, hasMetric1 := rkDsrtr.statMetrics[rkDsrtr.statIDs[i]][metricID] if !hasMetric1 { return false @@ -168,10 +180,11 @@ func (rkDsrtr *rankingDescSorter) sortStatIDs() []string { if val1 == val2 { continue } - if val1 > val2 { - return true + ret := val1 > val2 + if rkDsrtr.sMetricRev.Has(metricID) { + ret = !ret } - return false + return ret } //in case that we have the same value for all params we return randomly return utils.BoolGenerator().RandomBool() @@ -182,8 +195,18 @@ func (rkDsrtr *rankingDescSorter) sortStatIDs() []string { // newRankingAscSorter is a constructor for rankingAscSorter func newRankingAscSorter(sortingParams []string, statMetrics map[string]map[string]float64) (rkASrtr *rankingAscSorter) { + clnSp := make([]string, len(sortingParams)) + sPReversed := make(utils.StringSet) + for i, sP := range sortingParams { // clean the sortingParams, out of param:false or param:true definitions + sPSlc := strings.Split(sP, utils.InInFieldSep) + clnSp[i] = sPSlc[0] + if len(sPSlc) > 1 && sPSlc[1] == utils.FalseStr { + sPReversed.Add(sPSlc[0]) // param defined as param:false which should be added to reversing comparison + } + } rkASrtr = &rankingAscSorter{ - sortingParams, + clnSp, + sPReversed, statMetrics, make([]string, 0, len(statMetrics))} for statID := range rkASrtr.statMetrics { @@ -194,8 +217,9 @@ func newRankingAscSorter(sortingParams []string, // rankingAscSorter will sort data ascendent for metrics in sortingParams or randomly if all equal type rankingAscSorter struct { - sortingParams []string - statMetrics map[string]map[string]float64 + sMetricIDs []string + sMetricRev utils.StringSet // list of exceptios for sortingParams, reverting the sorting logic + statMetrics map[string]map[string]float64 statIDs []string // list of keys of the statMetrics } @@ -206,7 +230,7 @@ func (rkASrtr *rankingAscSorter) sortStatIDs() []string { return rkASrtr.statIDs } sort.Slice(rkASrtr.statIDs, func(i, j int) bool { - for _, metricID := range rkASrtr.sortingParams { + for _, metricID := range rkASrtr.sMetricIDs { val1, hasMetric1 := rkASrtr.statMetrics[rkASrtr.statIDs[i]][metricID] if !hasMetric1 { return false @@ -219,10 +243,11 @@ func (rkASrtr *rankingAscSorter) sortStatIDs() []string { if val1 == val2 { continue } - if val2 > val1 { - return true + ret := val2 > val1 + if rkASrtr.sMetricRev.Has(metricID) { + ret = !ret // reversed logic in case of metric:false in params } - return false + return ret } //in case that we have the same value for all params we return randomly return utils.BoolGenerator().RandomBool() diff --git a/engine/librankings_test.go b/engine/librankings_test.go index 46234eb89..3187db7fe 100644 --- a/engine/librankings_test.go +++ b/engine/librankings_test.go @@ -36,12 +36,24 @@ func TestRankingDescSorterSortStatIDs(t *testing.T) { if statIDs := rdscSrtr.sortStatIDs(); !reflect.DeepEqual(eStatIDs, statIDs) { t.Errorf("Expecting: %v, received %v", eStatIDs, statIDs) } - sortMetrics = []string{"*tcc", "*acc"} // changed the order of checks, stats4 should come first + sortMetrics = []string{"*acc:false", "*tcc"} // changed the order of checks, stats4 should come first + rdscSrtr = newRankingDescSorter(sortMetrics, statMetrics) + eStatIDs = []string{"STATS3", "STATS2", "STATS1", "STATS4"} + if statIDs := rdscSrtr.sortStatIDs(); !reflect.DeepEqual(eStatIDs, statIDs) { + t.Errorf("Expecting: %v, received %v", eStatIDs, statIDs) + } + sortMetrics = []string{"*tcc", "*acc:true"} // changed the order of checks, stats4 should come first rdscSrtr = newRankingDescSorter(sortMetrics, statMetrics) eStatIDs = []string{"STATS4", "STATS3", "STATS2", "STATS1"} if statIDs := rdscSrtr.sortStatIDs(); !reflect.DeepEqual(eStatIDs, statIDs) { t.Errorf("Expecting: %v, received %v", eStatIDs, statIDs) } + sortMetrics = []string{"*tcc:false", "*acc"} // reversed *tcc which should consider ascendent instead of descendent + rdscSrtr = newRankingDescSorter(sortMetrics, statMetrics) + eStatIDs = []string{"STATS1", "STATS2", "STATS3", "STATS4"} + if statIDs := rdscSrtr.sortStatIDs(); !reflect.DeepEqual(eStatIDs, statIDs) { + t.Errorf("Expecting: %v, received %v", eStatIDs, statIDs) + } } func TestRankingAscSorterSortStatIDs(t *testing.T) { @@ -57,10 +69,22 @@ func TestRankingAscSorterSortStatIDs(t *testing.T) { if statIDs := rtAscSrtr.sortStatIDs(); !reflect.DeepEqual(eStatIDs, statIDs) { t.Errorf("Expecting: %v, received %v", eStatIDs, statIDs) } - sortMetrics = []string{"*tcc", "*acc"} + sortMetrics = []string{"*acc:false", "*tcc"} rtAscSrtr = newRankingAscSorter(sortMetrics, statMetrics) eStatIDs = []string{"STATS1", "STATS2", "STATS3", "STATS4"} if statIDs := rtAscSrtr.sortStatIDs(); !reflect.DeepEqual(eStatIDs, statIDs) { t.Errorf("Expecting: %v, received %v", eStatIDs, statIDs) } + sortMetrics = []string{"*tcc", "*acc:true"} + rtAscSrtr = newRankingAscSorter(sortMetrics, statMetrics) + eStatIDs = []string{"STATS1", "STATS2", "STATS3", "STATS4"} + if statIDs := rtAscSrtr.sortStatIDs(); !reflect.DeepEqual(eStatIDs, statIDs) { + t.Errorf("Expecting: %v, received %v", eStatIDs, statIDs) + } + sortMetrics = []string{"*tcc:false", "*acc"} + rtAscSrtr = newRankingAscSorter(sortMetrics, statMetrics) + eStatIDs = []string{"STATS4", "STATS3", "STATS2", "STATS1"} + if statIDs := rtAscSrtr.sortStatIDs(); !reflect.DeepEqual(eStatIDs, statIDs) { + t.Errorf("Expecting: %v, received %v", eStatIDs, statIDs) + } }