feat: survey 包的 Analyzer 分析器增加大量辅助函数

This commit is contained in:
kercylan98 2023-11-06 20:26:12 +08:00
parent 589a424491
commit 85176f32f9
2 changed files with 203 additions and 13 deletions

View File

@ -1,13 +1,14 @@
package survey
import (
"github.com/tidwall/gjson"
"strings"
"sync"
)
// Analyzer 分析器
type Analyzer struct {
v map[string]float64 // 记录了每个 key 的当前值
v map[string]any // 记录了每个 key 的当前值
vc map[string]int64 // 记录了每个 key 生效的计数数量
repeat map[string]struct{} // 去重信息
subs map[string]*Analyzer
@ -29,7 +30,106 @@ func (slf *Analyzer) Sub(key string) *Analyzer {
return sub
}
// SetValueIfGreaterThan 设置指定 key 的值,当新值大于旧值时
// - 当已有值不为 float64 时,将会被忽略
func (slf *Analyzer) SetValueIfGreaterThan(key string, value float64) {
slf.m.Lock()
defer slf.m.Unlock()
if slf.v == nil {
slf.v = make(map[string]any)
slf.vc = make(map[string]int64)
}
v, exist := slf.v[key]
if !exist {
slf.v[key] = value
slf.vc[key]++
return
}
switch v := v.(type) {
case float64:
if v < value {
slf.v[key] = value
slf.vc[key]++
}
}
}
// SetValueIfLessThan 设置指定 key 的值,当新值小于旧值时
// - 当已有值不为 float64 时,将会被忽略
func (slf *Analyzer) SetValueIfLessThan(key string, value float64) {
slf.m.Lock()
defer slf.m.Unlock()
if slf.v == nil {
slf.v = make(map[string]any)
slf.vc = make(map[string]int64)
}
v, exist := slf.v[key]
if !exist {
slf.v[key] = value
slf.vc[key]++
return
}
switch v := v.(type) {
case float64:
if v > value {
slf.v[key] = value
slf.vc[key]++
}
}
}
// SetValueIf 当表达式满足的时候将设置指定 key 的值为 value
func (slf *Analyzer) SetValueIf(key string, expression bool, value float64) {
if !expression {
return
}
slf.m.Lock()
defer slf.m.Unlock()
slf.v[key] = value
slf.vc[key]++
}
// SetValueStringIf 当表达式满足的时候将设置指定 key 的值为 value
func (slf *Analyzer) SetValueStringIf(key string, expression bool, value string) {
if !expression {
return
}
slf.m.Lock()
defer slf.m.Unlock()
slf.v[key] = value
slf.vc[key]++
}
// SetValue 设置指定 key 的值
func (slf *Analyzer) SetValue(key string, value float64) {
slf.m.Lock()
defer slf.m.Unlock()
if slf.v == nil {
slf.v = make(map[string]any)
slf.vc = make(map[string]int64)
}
slf.v[key] = value
slf.vc[key]++
}
// SetValueString 设置指定 key 的值
func (slf *Analyzer) SetValueString(key string, value string) {
slf.m.Lock()
defer slf.m.Unlock()
if slf.v == nil {
slf.v = make(map[string]any)
slf.vc = make(map[string]int64)
}
slf.v[key] = value
slf.vc[key]++
}
// Increase 在指定 key 现有值的基础上增加 recordKey 的值
// - 当分析器已经记录过相同 key 的值时,会根据已有的值类型进行不同处理
//
// 处理方式:
// - 当已有值类型为 string 时,将会使用新的值的 string 类型进行覆盖
// - 当已有值类型为 float64 时,当新的值类型不为 float64 时,将会被忽略
func (slf *Analyzer) Increase(key string, record R, recordKey string) {
slf.m.Lock()
defer slf.m.Unlock()
@ -37,10 +137,31 @@ func (slf *Analyzer) Increase(key string, record R, recordKey string) {
return
}
if slf.v == nil {
slf.v = make(map[string]float64)
slf.v = make(map[string]any)
slf.vc = make(map[string]int64)
}
slf.v[key] += record.GetFloat64(recordKey)
value, exist := slf.v[key]
if !exist {
result := gjson.Get(string(record), recordKey)
switch result.Type {
case gjson.String:
slf.v[key] = result.String()
case gjson.Number:
slf.v[key] = result.Float()
default:
return
}
slf.vc[key]++
return
}
switch v := value.(type) {
case string:
slf.v[key] = record.GetString(recordKey)
case float64:
slf.v[key] = v + record.GetFloat64(recordKey)
default:
return
}
slf.vc[key]++
}
@ -49,11 +170,20 @@ func (slf *Analyzer) IncreaseValue(key string, value float64) {
slf.m.Lock()
defer slf.m.Unlock()
if slf.v == nil {
slf.v = make(map[string]float64)
slf.v = make(map[string]any)
slf.vc = make(map[string]int64)
}
slf.v[key] += value
slf.vc[key]++
v, exist := slf.v[key]
if !exist {
slf.v[key] = value
slf.vc[key]++
return
}
switch v := v.(type) {
case float64:
slf.v[key] = v + value
slf.vc[key]++
}
}
// IncreaseNonRepeat 在指定 key 现有值的基础上增加 recordKey 的值,但是当去重维度 dimension 相同时,不会增加
@ -99,3 +229,33 @@ func (slf *Analyzer) IncreaseValueNonRepeat(key string, record R, value float64,
slf.m.Unlock()
slf.IncreaseValue(key, value)
}
// GetValue 获取当前记录的值
func (slf *Analyzer) GetValue(key string) float64 {
slf.m.Lock()
defer slf.m.Unlock()
value, exist := slf.v[key]
if !exist {
return 0
}
switch v := value.(type) {
case float64:
return v
}
return 0
}
// GetValueString 获取当前记录的值
func (slf *Analyzer) GetValueString(key string) string {
slf.m.Lock()
defer slf.m.Unlock()
value, exist := slf.v[key]
if !exist {
return ""
}
switch v := value.(type) {
case string:
return v
}
return ""
}

View File

@ -2,6 +2,7 @@ package survey
import (
"github.com/kercylan98/minotaur/utils/super"
"strings"
)
func newReport(analyzer *Analyzer) *Report {
@ -23,15 +24,23 @@ func newReport(analyzer *Analyzer) *Report {
// Report 分析报告
type Report struct {
analyzer *Analyzer
Name string // 报告名称(默认为 ROOT
Values map[string]float64 `json:"Values,omitempty"`
Counter map[string]int64 `json:"Count,omitempty"`
Subs []*Report `json:"Reports,omitempty"`
Name string // 报告名称(默认为 ROOT
Values map[string]any `json:"Values,omitempty"`
Counter map[string]int64 `json:"Count,omitempty"`
Subs []*Report `json:"Reports,omitempty"`
}
// Avg 计算平均值
func (slf *Report) Avg(key string) float64 {
return slf.Values[key] / float64(slf.Counter[key])
value, exist := slf.Values[key]
if !exist {
return 0
}
valF, ok := value.(float64)
if !ok {
return 0
}
return valF / float64(slf.Counter[key])
}
// Count 获取特定 key 的计数次数
@ -43,7 +52,15 @@ func (slf *Report) Count(key string) int64 {
func (slf *Report) Sum(keys ...string) float64 {
var sum float64
for _, key := range keys {
sum += slf.Values[key]
value, exist := slf.Values[key]
if !exist {
continue
}
valF, ok := value.(float64)
if !ok {
continue
}
sum += valF
}
return sum
}
@ -58,6 +75,19 @@ func (slf *Report) Sub(name string) *Report {
return nil
}
// ReserveSubByPrefix 仅保留特定前缀的子报告
func (slf *Report) ReserveSubByPrefix(prefix string) *Report {
report := newReport(slf.analyzer)
var newSub []*Report
for _, sub := range slf.Subs {
if strings.HasPrefix(sub.Name, prefix) {
newSub = append(newSub, sub)
}
}
report.Subs = newSub
return report
}
// ReserveSub 仅保留特定名称子报告
func (slf *Report) ReserveSub(names ...string) *Report {
report := newReport(slf.analyzer)
@ -78,7 +108,7 @@ func (slf *Report) ReserveSub(names ...string) *Report {
return report
}
// FilterSub 过滤特定名称的子报告
// FilterSub 将特定名称的子报告过滤掉
func (slf *Report) FilterSub(names ...string) *Report {
report := newReport(slf.analyzer)
var newSub []*Report