91 lines
2.4 KiB
Go
91 lines
2.4 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"math/rand"
|
||
|
"sync"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
searchEngineLock sync.Mutex
|
||
|
)
|
||
|
|
||
|
// SearchEngine struct now includes metrics for calculating reputation.
|
||
|
type SearchEngine struct {
|
||
|
Name string
|
||
|
Func func(string, string, string, int) ([]SearchResult, time.Duration, error)
|
||
|
Weight int
|
||
|
TotalRequests int
|
||
|
TotalTime time.Duration
|
||
|
SuccessfulSearches int
|
||
|
FailedSearches int
|
||
|
}
|
||
|
|
||
|
// init function seeds the random number generator.
|
||
|
func init() {
|
||
|
rand.Seed(time.Now().UnixNano())
|
||
|
}
|
||
|
|
||
|
// Selects a search engine based on weighted random selection with dynamic weighting.
|
||
|
func selectSearchEngine(engines []SearchEngine) SearchEngine {
|
||
|
searchEngineLock.Lock()
|
||
|
defer searchEngineLock.Unlock()
|
||
|
|
||
|
// Recalculate weights based on average response time and success rate.
|
||
|
for i := range engines {
|
||
|
engines[i].Weight = calculateReputation(engines[i])
|
||
|
}
|
||
|
|
||
|
totalWeight := 0
|
||
|
for _, engine := range engines {
|
||
|
totalWeight += engine.Weight
|
||
|
}
|
||
|
|
||
|
randValue := rand.Intn(totalWeight)
|
||
|
for _, engine := range engines {
|
||
|
if randValue < engine.Weight {
|
||
|
return engine
|
||
|
}
|
||
|
randValue -= engine.Weight
|
||
|
}
|
||
|
|
||
|
return engines[0] // fallback to the first engine
|
||
|
}
|
||
|
|
||
|
// Updates the engine's performance metrics.
|
||
|
func updateEngineMetrics(engine *SearchEngine, responseTime time.Duration, success bool) {
|
||
|
searchEngineLock.Lock()
|
||
|
defer searchEngineLock.Unlock()
|
||
|
|
||
|
engine.TotalRequests++
|
||
|
engine.TotalTime += responseTime
|
||
|
if success {
|
||
|
engine.SuccessfulSearches++
|
||
|
} else {
|
||
|
engine.FailedSearches++
|
||
|
}
|
||
|
engine.Weight = calculateReputation(*engine)
|
||
|
}
|
||
|
|
||
|
// Calculates the reputation of the search engine based on average response time and success rate.
|
||
|
func calculateReputation(engine SearchEngine) int {
|
||
|
const referenceTime = time.Second // 1 second reference time in nanoseconds (1000 ms)
|
||
|
|
||
|
if engine.TotalRequests == 0 {
|
||
|
return 10 // Default weight for new engines
|
||
|
}
|
||
|
|
||
|
// Calculate average response time in seconds.
|
||
|
avgResponseTime := engine.TotalTime.Seconds() / float64(engine.TotalRequests)
|
||
|
|
||
|
// Calculate success rate.
|
||
|
successRate := float64(engine.SuccessfulSearches) / float64(engine.TotalRequests)
|
||
|
|
||
|
// Combine response time and success rate into a single reputation score.
|
||
|
// The formula can be adjusted to weigh response time and success rate differently.
|
||
|
reputation := (referenceTime.Seconds() / avgResponseTime) * successRate
|
||
|
|
||
|
// Scale reputation for better interpretability (e.g., multiply by 10)
|
||
|
return int(reputation * 10)
|
||
|
}
|