From 3da8cae762ddd4e281f360ff2be51503a57cfea2 Mon Sep 17 00:00:00 2001 From: Las Zenow Date: Sat, 1 Jun 2013 05:48:15 +0200 Subject: [PATCH] Get the visited and downloaded books from the stadistics --- config.go | 20 +++++++++------- database.go | 36 ++++++++++++++-------------- mapreduce.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ trantor.go | 2 -- 4 files changed, 98 insertions(+), 28 deletions(-) diff --git a/config.go b/config.go index 7e6475e..b8f5f71 100644 --- a/config.go +++ b/config.go @@ -8,6 +8,8 @@ const ( META_COLL = "meta" BOOKS_COLL = "books" TAGS_COLL = "tags" + VISITED_COLL = "visited" + DOWNLOADED_COLL = "downloaded" HOURLY_VISITS_COLL = "visits.hourly" DAILY_VISITS_COLL = "visits.daily" MONTHLY_VISITS_COLL = "visits.monthly" @@ -16,14 +18,16 @@ const ( FS_BOOKS = "fs_books" FS_IMGS = "fs_imgs" - PASS_SALT = "ImperialLibSalt" - MINUTES_UPDATE_TAGS = 11 - MINUTES_UPDATE_HOURLY = 31 - MINUTES_UPDATE_DAILY = 60*12 + 7 - MINUTES_UPDATE_MONTHLY = 60*24 + 11 - TAGS_DISPLAY = 50 - SEARCH_ITEMS_PAGE = 20 - NEW_ITEMS_PAGE = 50 + PASS_SALT = "ImperialLibSalt" + MINUTES_UPDATE_TAGS = 11 + MINUTES_UPDATE_VISITED = 41 + MINUTES_UPDATE_DOWNLOADED = 47 + MINUTES_UPDATE_HOURLY = 31 + MINUTES_UPDATE_DAILY = 60*12 + 7 + MINUTES_UPDATE_MONTHLY = 60*24 + 11 + TAGS_DISPLAY = 50 + SEARCH_ITEMS_PAGE = 20 + NEW_ITEMS_PAGE = 50 TEMPLATE_PATH = "templates/" CSS_PATH = "css/" diff --git a/database.go b/database.go index 9789a32..ebf6fb0 100644 --- a/database.go +++ b/database.go @@ -98,14 +98,6 @@ func (d *DB) UpdateBook(id bson.ObjectId, data interface{}) error { return d.books.Update(bson.M{"_id": id}, bson.M{"$set": data}) } -func (d *DB) IncVisit(id bson.ObjectId) error { - return d.books.Update(bson.M{"_id": id}, bson.M{"$inc": bson.M{"VisitsCount": 1}}) -} - -func (d *DB) IncDownload(id bson.ObjectId) error { - return d.books.Update(bson.M{"_id": id}, bson.M{"$inc": bson.M{"DownloadCount": 1}}) -} - /* optional parameters: length and start index * * Returns: list of books, number found and err @@ -140,11 +132,15 @@ func (d *DB) GetBooks(query bson.M, r ...int) (books []Book, num int, err error) /* Get the most visited books */ func (d *DB) GetVisitedBooks(num int) (books []Book, err error) { - var q *mgo.Query - q = d.books.Find(bson.M{"active": true}).Sort("-VisitsCount").Limit(num) - err = q.All(&books) - for i, b := range books { - books[i].Id = bson.ObjectId(b.Id).Hex() + bookId, err := d.mr.GetMostVisited(num, d.stats) + if err != nil { + return nil, err + } + + books = make([]Book, num) + for i, id := range bookId { + d.books.Find(bson.M{"_id": id}).One(&books[i]) + books[i].Id = bson.ObjectId(books[i].Id).Hex() } return } @@ -152,11 +148,15 @@ func (d *DB) GetVisitedBooks(num int) (books []Book, err error) { /* Get the most downloaded books */ func (d *DB) GetDownloadedBooks(num int) (books []Book, err error) { - var q *mgo.Query - q = d.books.Find(bson.M{"active": true}).Sort("-DownloadCount").Limit(num) - err = q.All(&books) - for i, b := range books { - books[i].Id = bson.ObjectId(b.Id).Hex() + bookId, err := d.mr.GetMostDownloaded(num, d.stats) + if err != nil { + return nil, err + } + + books = make([]Book, num) + for i, id := range bookId { + d.books.Find(bson.M{"_id": id}).One(&books[i]) + books[i].Id = bson.ObjectId(books[i].Id).Hex() } return } diff --git a/mapreduce.go b/mapreduce.go index e899ee7..dbadd19 100644 --- a/mapreduce.go +++ b/mapreduce.go @@ -9,6 +9,8 @@ import ( type MR struct { meta *mgo.Collection tags *mgo.Collection + visited *mgo.Collection + downloaded *mgo.Collection hourly_raw *mgo.Collection daily_raw *mgo.Collection monthly_raw *mgo.Collection @@ -21,6 +23,8 @@ func NewMR(database *mgo.Database) *MR { m := new(MR) m.meta = database.C(META_COLL) m.tags = database.C(TAGS_COLL) + m.visited = database.C(VISITED_COLL) + m.downloaded = database.C(DOWNLOADED_COLL) m.hourly_raw = database.C(HOURLY_VISITS_COLL + "_raw") m.daily_raw = database.C(DAILY_VISITS_COLL + "_raw") m.monthly_raw = database.C(MONTHLY_VISITS_COLL + "_raw") @@ -64,6 +68,70 @@ func (m *MR) GetTags(numTags int, booksColl *mgo.Collection) ([]string, error) { return tags, nil } +func (m *MR) GetMostVisited(num int, statsColl *mgo.Collection) ([]bson.ObjectId, error) { + if m.isOutdated(VISITED_COLL, MINUTES_UPDATE_VISITED) { + var mr mgo.MapReduce + mr.Map = `function() { + emit(this.id, 1); + }` + mr.Reduce = `function(tag, vals) { + var count = 0; + vals.forEach(function() { count += 1; }); + return count; + }` + err := m.update(&mr, bson.M{"section": "book"}, statsColl, VISITED_COLL) + if err != nil { + return nil, err + } + } + + var result []struct { + Book bson.ObjectId "_id" + } + err := m.visited.Find(nil).Sort("-value").Limit(num).All(&result) + if err != nil { + return nil, err + } + + books := make([]bson.ObjectId, len(result)) + for i, r := range result { + books[i] = r.Book + } + return books, nil +} + +func (m *MR) GetMostDownloaded(num int, statsColl *mgo.Collection) ([]bson.ObjectId, error) { + if m.isOutdated(DOWNLOADED_COLL, MINUTES_UPDATE_DOWNLOADED) { + var mr mgo.MapReduce + mr.Map = `function() { + emit(this.id, 1); + }` + mr.Reduce = `function(tag, vals) { + var count = 0; + vals.forEach(function() { count += 1; }); + return count; + }` + err := m.update(&mr, bson.M{"section": "download"}, statsColl, DOWNLOADED_COLL) + if err != nil { + return nil, err + } + } + + var result []struct { + Book bson.ObjectId "_id" + } + err := m.downloaded.Find(nil).Sort("-value").Limit(num).All(&result) + if err != nil { + return nil, err + } + + books := make([]bson.ObjectId, len(result)) + for i, r := range result { + books[i] = r.Book + } + return books, nil +} + func (m *MR) GetHourVisits(start time.Time, statsColl *mgo.Collection) ([]Visits, error) { if m.isOutdated(HOURLY_VISITS_COLL, MINUTES_UPDATE_HOURLY) { const reduce = `function(date, vals) { diff --git a/trantor.go b/trantor.go index 04c2d5b..569720c 100644 --- a/trantor.go +++ b/trantor.go @@ -71,7 +71,6 @@ func bookHandler(w http.ResponseWriter, r *http.Request, sess *Session) { notFound(w) return } - db.IncVisit(id) data.Book = books[0] data.Description = strings.Split(data.Book.Description, "\n") loadTemplate(w, "book", data) @@ -113,7 +112,6 @@ func downloadHandler(w http.ResponseWriter, r *http.Request, sess *Session) { headers["Content-Disposition"] = []string{"attachment; filename=\"" + f.Name() + "\""} io.Copy(w, f) - db.IncDownload(id) } type indexData struct {