由於 Open-Match 在架構上,允許使用同一張 ticket,對不同的配對池進行搜尋與配對,這便是先前提到的 overlapping MatchProfiles,但如何使這些具有重疊性的匹配,最後只產生出一個最適合的匹配結果,則需要 Evaluator 介入參與。
基於配對方式的設計,可以決定我們的 Evaluator 如何參與我們的配對流程,可以簡單地分成三種使用方式:
無重疊
:將 MatchProfiles 使用的條件完全不重疊,使你的配對永遠不會發生重疊衝突,如此一來可以僅靠 default evaluator 處理配對有重疊(單一指標)
:MatchProfiles 使用含有重疊的條件範圍,但有計算出分數指標,並且放入 Extensions["evaluation_input"]
中,default evaluator 可以依據此指標進行匹配判斷,避免配對衝突有重疊(多指標)
:MatchProfiles 使用含有重疊的條件範圍,且計算出多個評分指標,在這樣的情況下,需要重新建立客製化的 Evaluator,針對計算出來的多個指標做評分與指派這邊看了一下 source code,粗淺的解析一下預設的 Evaluator 是怎麼運作的。
func evaluate(ctx context.Context, in <-chan *pb.Match, out chan<- string) error {
matches := make([]*matchInp, 0)
nilEvaluationInputs := 0
for m := range in {
//如同範例使用的 DefaultEvaluationCriteria 將計算分數放 Score
inp := &pb.DefaultEvaluationCriteria{
Score: math.Inf(-1),
}
//指定 Extensions key "evaluation_input"
if a, ok := m.Extensions["evaluation_input"]; ok {
err := ptypes.UnmarshalAny(a, inp)
if err != nil {
logger.WithFields(logrus.Fields{
"match_id": m.MatchId,
"error": err,
}).Error("Failed to unmarshal match's DefaultEvaluationCriteria. Rejecting match.")
continue
}
} else {
nilEvaluationInputs++
}
matches = append(matches, &matchInp{
match: m,
inp: inp,
})
}
if nilEvaluationInputs > 0 {
logger.WithFields(logrus.Fields{
"count": nilEvaluationInputs,
}).Info("Some matches don't have the optional field evaluation_input set.")
}
//分數排序
sort.Sort(byScore(matches))
//避免衝突
d := decollider{
ticketsUsed: make(map[string]*collidingMatch),
backfillsUsed: make(map[string]*collidingMatch),
}
for _, m := range matches {
d.maybeAdd(m)
}
stats.Record(context.Background(), collidedMatchesPerEvaluate.M(int64(len(matches)-len(d.resultIDs))))
//結果
for _, id := range d.resultIDs {
out <- id
}
return nil
}