-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
940cd24
commit 61732a8
Showing
6 changed files
with
204 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package main | ||
|
||
type Ad interface { | ||
Features() []Feature | ||
Weight(Feature) float32 | ||
Bid() float32 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package main | ||
|
||
var endOfPosting PagePostingItem = PagePostingItem{ | ||
PID: lastPID, | ||
} | ||
|
||
type PagePostingItem struct { | ||
PID int64 | ||
Weight float32 | ||
} | ||
|
||
type PagePostingList struct { | ||
// the end of posting items must be endOfPostingItem | ||
Items []PagePostingItem | ||
// meta info | ||
MaxWeight float32 | ||
} | ||
|
||
type Feature string // 特征名称,包含特征值? | ||
|
||
type FeatureCursor struct { | ||
feature Feature | ||
posting *PagePostingList | ||
current int | ||
} | ||
|
||
func (c *FeatureCursor) CurrentPage() PagePostingItem { | ||
return c.posting.Items[c.current] | ||
} | ||
|
||
func (c *FeatureCursor) Beyond(PID int64) { | ||
// page IDs are sorted in non-decreasing order | ||
for c.CurrentPage().PID < PID { | ||
c.current++ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package main | ||
|
||
import "sort" | ||
|
||
type ImpressionForecastor struct { | ||
pages map[int64]PageMeta | ||
featureToPages map[Feature]*PagePostingList | ||
} | ||
|
||
func (i *ImpressionForecastor) forecast(ad Ad) int { | ||
impressions := 0 | ||
|
||
searcher := &Searcher{ | ||
pages: i.pages, | ||
feature2Pages: i.featureToPages, | ||
currentPage: 0, | ||
ad: ad, | ||
} | ||
|
||
searcher.initCursors() | ||
pageID := searcher.nextCandidate() | ||
for pageID < lastPID { | ||
p := i.pages[pageID] | ||
score := i.score(ad, p) | ||
if score > p.minScore { | ||
impressions += p.impressions | ||
} | ||
pageID = searcher.nextCandidate() | ||
} | ||
|
||
return impressions | ||
} | ||
|
||
func (i *ImpressionForecastor) score(ad Ad, page PageMeta) float32 { | ||
pageWeight := make(map[Feature]float32, len(page.features)) | ||
for i, f := range page.features { | ||
pageWeight[f] = page.weights[i] | ||
} | ||
|
||
sim := float32(0) | ||
for _, f := range ad.Features() { | ||
sim += pageWeight[f] * ad.Weight(f) | ||
} | ||
|
||
return sim * ad.Bid() | ||
} | ||
|
||
type Searcher struct { | ||
pages map[int64]PageMeta | ||
feature2Pages map[Feature]*PagePostingList | ||
|
||
currentPage int64 | ||
ad Ad | ||
features []*FeatureCursor | ||
} | ||
|
||
func (s *Searcher) initCursors() { | ||
s.currentPage = 0 | ||
|
||
ad := s.ad | ||
features := ad.Features() | ||
cursors := make([]*FeatureCursor, len(features)) | ||
for i, f := range features { | ||
|
||
cursors[i] = &FeatureCursor{ | ||
feature: f, | ||
posting: s.feature2Pages[f], | ||
current: 0, | ||
} | ||
} | ||
|
||
s.features = cursors | ||
} | ||
|
||
func (s *Searcher) nextCandidate() int64 { | ||
for { | ||
|
||
s.sortFeatures(s.features) | ||
pivot := s.findPivotFeature(s.features) | ||
|
||
if pivot == -1 { | ||
return lastPID | ||
} | ||
pivotPID := s.features[pivot].CurrentPage().PID | ||
if pivotPID == lastPID { | ||
return lastPID | ||
} | ||
|
||
if pivotPID == s.currentPage { | ||
f := s.pickFeature(s.features[0 : pivot+1]) | ||
s.features[f].Beyond(pivotPID + 1) | ||
} else { | ||
if s.features[0].CurrentPage().PID == pivotPID { | ||
s.currentPage = pivotPID | ||
return s.currentPage | ||
} else { | ||
f := s.pickFeature(s.features[0 : pivot+1]) | ||
s.features[f].Beyond(pivotPID) | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (s *Searcher) sortFeatures(features []*FeatureCursor) { | ||
sort.Slice(features, func(i, j int) bool { | ||
return features[i].CurrentPage().PID < features[j].CurrentPage().PID | ||
}) | ||
} | ||
|
||
func (s *Searcher) findPivotFeature(cursors []*FeatureCursor) int { | ||
n := len(cursors) | ||
ub := float32(0) | ||
ad := s.ad | ||
|
||
minScoreP := s.pages[s.currentPage].minScore | ||
threshold := minScoreP / ad.Bid() | ||
|
||
for i := 0; i < n; i++ { | ||
|
||
f := cursors[i].feature | ||
maxWeight := s.feature2Pages[f].MaxWeight | ||
ub += ad.Weight(f) * maxWeight | ||
if ub >= threshold { | ||
return i | ||
} | ||
} | ||
|
||
return -1 | ||
} | ||
|
||
func (s *Searcher) pickFeature(cursors []*FeatureCursor) int { | ||
return 0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module github.com/csimplestring/ca-imp-forecast | ||
|
||
go 1.17 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
github.com/allegro/bigcache/v3 v3.0.0/go.mod h1:t5TAJn1B9qvf/VlJrSM1r6NlFAYoFDubYUsCuIO9nUQ= | ||
github.com/csimplestring/go-left-right v0.0.3/go.mod h1:ASS5AW8dwk3v6VxpOPQ6wI/N68ibyAMAPW1VTAWQpx8= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/linxGnu/go-adder v0.2.0/go.mod h1:t9zC6P+vQpG5iEtw4sinwsVqe52AuFvL4P1dVXHD46c= | ||
github.com/philpearl/stringbank v1.1.0/go.mod h1:0V0f9Ba79DpIl4FTfotL+7IJ+etELdRQIcHJY2nX/+w= | ||
github.com/philpearl/symboltab v1.1.4/go.mod h1:vOdgHoGZAUqGg1apOcrqjuAxFERPUJ03PLfL6pvxNBg= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||
github.com/valyala/fastrand v1.0.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package main | ||
|
||
import ( | ||
"math" | ||
) | ||
|
||
// PageID is generated by increasing order of minScore: smaller ID, smaller score | ||
const lastPID = math.MaxInt64 | ||
|
||
type PageMeta struct { | ||
impressions int | ||
minScore float32 | ||
features []Feature | ||
weights []float32 | ||
} |