Use an strcut for mapreduce stuff
This commit is contained in:
parent
d8e46419b1
commit
a4ccd41d05
3 changed files with 128 additions and 95 deletions
30
config.go
30
config.go
|
@ -3,21 +3,23 @@ package main
|
||||||
const (
|
const (
|
||||||
PORT = "8080"
|
PORT = "8080"
|
||||||
|
|
||||||
DB_IP = "127.0.0.1"
|
DB_IP = "127.0.0.1"
|
||||||
DB_NAME = "trantor"
|
DB_NAME = "trantor"
|
||||||
META_COLL = "meta"
|
META_COLL = "meta"
|
||||||
BOOKS_COLL = "books"
|
BOOKS_COLL = "books"
|
||||||
TAGS_COLL = "tags"
|
TAGS_COLL = "tags"
|
||||||
USERS_COLL = "users"
|
DAILY_VISITS_COLL = "visits.daily"
|
||||||
STATS_COLL = "statistics"
|
USERS_COLL = "users"
|
||||||
FS_BOOKS = "fs_books"
|
STATS_COLL = "statistics"
|
||||||
FS_IMGS = "fs_imgs"
|
FS_BOOKS = "fs_books"
|
||||||
|
FS_IMGS = "fs_imgs"
|
||||||
|
|
||||||
PASS_SALT = "ImperialLibSalt"
|
PASS_SALT = "ImperialLibSalt"
|
||||||
MINUTES_UPDATE_TAGS = 10
|
MINUTES_UPDATE_TAGS = 10
|
||||||
TAGS_DISPLAY = 50
|
MINUTES_UPDATE_DAILY = 60 * 12
|
||||||
SEARCH_ITEMS_PAGE = 20
|
TAGS_DISPLAY = 50
|
||||||
NEW_ITEMS_PAGE = 50
|
SEARCH_ITEMS_PAGE = 20
|
||||||
|
NEW_ITEMS_PAGE = 50
|
||||||
|
|
||||||
TEMPLATE_PATH = "templates/"
|
TEMPLATE_PATH = "templates/"
|
||||||
CSS_PATH = "css/"
|
CSS_PATH = "css/"
|
||||||
|
|
85
database.go
85
database.go
|
@ -7,10 +7,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
META_TYPE_TAGS = "tags updated"
|
|
||||||
)
|
|
||||||
|
|
||||||
var db *DB
|
var db *DB
|
||||||
|
|
||||||
type Book struct {
|
type Book struct {
|
||||||
|
@ -40,11 +36,10 @@ type Book struct {
|
||||||
|
|
||||||
type DB struct {
|
type DB struct {
|
||||||
session *mgo.Session
|
session *mgo.Session
|
||||||
meta *mgo.Collection
|
|
||||||
books *mgo.Collection
|
books *mgo.Collection
|
||||||
tags *mgo.Collection
|
|
||||||
user *mgo.Collection
|
user *mgo.Collection
|
||||||
stats *mgo.Collection
|
stats *mgo.Collection
|
||||||
|
mr *MR
|
||||||
}
|
}
|
||||||
|
|
||||||
func initDB() *DB {
|
func initDB() *DB {
|
||||||
|
@ -56,11 +51,10 @@ func initDB() *DB {
|
||||||
}
|
}
|
||||||
|
|
||||||
database := d.session.DB(DB_NAME)
|
database := d.session.DB(DB_NAME)
|
||||||
d.meta = database.C(META_COLL)
|
|
||||||
d.books = database.C(BOOKS_COLL)
|
d.books = database.C(BOOKS_COLL)
|
||||||
d.tags = database.C(TAGS_COLL)
|
|
||||||
d.user = database.C(USERS_COLL)
|
d.user = database.C(USERS_COLL)
|
||||||
d.stats = database.C(STATS_COLL)
|
d.stats = database.C(STATS_COLL)
|
||||||
|
d.mr = NewMR(database)
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,65 +182,8 @@ func (d *DB) GetFS(prefix string) *mgo.GridFS {
|
||||||
return d.session.DB(DB_NAME).GridFS(prefix)
|
return d.session.DB(DB_NAME).GridFS(prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) areTagsOutdated() bool {
|
|
||||||
var result struct {
|
|
||||||
Id bson.ObjectId `bson:"_id"`
|
|
||||||
}
|
|
||||||
err := d.meta.Find(bson.M{"type": META_TYPE_TAGS}).One(&result)
|
|
||||||
if err != nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
lastUpdate := result.Id.Time()
|
|
||||||
return time.Since(lastUpdate).Minutes() > MINUTES_UPDATE_TAGS
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DB) updateTags() error {
|
|
||||||
_, err := d.meta.RemoveAll(bson.M{"type": META_TYPE_TAGS})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var mr mgo.MapReduce
|
|
||||||
mr.Map = `function() {
|
|
||||||
if (this.active) {
|
|
||||||
this.subject.forEach(function(s) { emit(s, 1); });
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
mr.Reduce = `function(tag, vals) {
|
|
||||||
var count = 0;
|
|
||||||
vals.forEach(function() { count += 1; });
|
|
||||||
return count;
|
|
||||||
}`
|
|
||||||
mr.Out = bson.M{"replace": TAGS_COLL}
|
|
||||||
_, err = d.books.Find(bson.M{"active": true}).MapReduce(&mr, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return d.meta.Insert(bson.M{"type": META_TYPE_TAGS})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DB) GetTags(numTags int) ([]string, error) {
|
func (d *DB) GetTags(numTags int) ([]string, error) {
|
||||||
if d.areTagsOutdated() {
|
return d.mr.GetTags(numTags, d.books)
|
||||||
err := d.updateTags()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var result []struct {
|
|
||||||
Tag string "_id"
|
|
||||||
}
|
|
||||||
err := d.tags.Find(nil).Sort("-value").Limit(numTags).All(&result)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tags := make([]string, len(result))
|
|
||||||
for i, r := range result {
|
|
||||||
tags[i] = r.Tag
|
|
||||||
}
|
|
||||||
return tags, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Visits struct {
|
type Visits struct {
|
||||||
|
@ -255,19 +192,5 @@ type Visits struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) GetDayVisits(start time.Time) ([]Visits, error) {
|
func (d *DB) GetDayVisits(start time.Time) ([]Visits, error) {
|
||||||
var mr mgo.MapReduce
|
return d.mr.GetDayVisits(start, d.stats)
|
||||||
mr.Map = `function() {
|
|
||||||
var day = Date.UTC(this.date.getFullYear(),
|
|
||||||
this.date.getMonth(),
|
|
||||||
this.date.getDate());
|
|
||||||
emit(day, 1);
|
|
||||||
}`
|
|
||||||
mr.Reduce = `function(date, vals) {
|
|
||||||
var count = 0;
|
|
||||||
vals.forEach(function(v) { count += v; });
|
|
||||||
return count;
|
|
||||||
}`
|
|
||||||
var result []Visits
|
|
||||||
_, err := d.stats.Find(bson.M{"date": bson.M{"$gte": start}}).MapReduce(&mr, &result)
|
|
||||||
return result, err
|
|
||||||
}
|
}
|
||||||
|
|
108
mapreduce.go
Normal file
108
mapreduce.go
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"labix.org/v2/mgo"
|
||||||
|
"labix.org/v2/mgo/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MR struct {
|
||||||
|
meta *mgo.Collection
|
||||||
|
tags *mgo.Collection
|
||||||
|
daily *mgo.Collection
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMR(database *mgo.Database) *MR {
|
||||||
|
m := new(MR)
|
||||||
|
m.meta = database.C(META_COLL)
|
||||||
|
m.tags = database.C(TAGS_COLL)
|
||||||
|
m.daily = database.C(DAILY_VISITS_COLL)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MR) GetTags(numTags int, booksColl *mgo.Collection) ([]string, error) {
|
||||||
|
if m.isOutdated(TAGS_COLL, MINUTES_UPDATE_TAGS) {
|
||||||
|
var mr mgo.MapReduce
|
||||||
|
mr.Map = `function() {
|
||||||
|
if (this.subject) {
|
||||||
|
this.subject.forEach(function(s) { emit(s, 1); });
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
mr.Reduce = `function(tag, vals) {
|
||||||
|
var count = 0;
|
||||||
|
vals.forEach(function() { count += 1; });
|
||||||
|
return count;
|
||||||
|
}`
|
||||||
|
err := m.update(&mr, bson.M{"active": true}, booksColl, TAGS_COLL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []struct {
|
||||||
|
Tag string "_id"
|
||||||
|
}
|
||||||
|
err := m.tags.Find(nil).Sort("-value").Limit(numTags).All(&result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tags := make([]string, len(result))
|
||||||
|
for i, r := range result {
|
||||||
|
tags[i] = r.Tag
|
||||||
|
}
|
||||||
|
return tags, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MR) GetDayVisits(start time.Time, statsColl *mgo.Collection) ([]Visits, error) {
|
||||||
|
if m.isOutdated(DAILY_VISITS_COLL, MINUTES_UPDATE_DAILY) {
|
||||||
|
var mr mgo.MapReduce
|
||||||
|
mr.Map = `function() {
|
||||||
|
var day = Date.UTC(this.date.getFullYear(),
|
||||||
|
this.date.getMonth(),
|
||||||
|
this.date.getDate());
|
||||||
|
emit(day, 1);
|
||||||
|
}`
|
||||||
|
mr.Reduce = `function(date, vals) {
|
||||||
|
var count = 0;
|
||||||
|
vals.forEach(function(v) { count += v; });
|
||||||
|
return count;
|
||||||
|
}`
|
||||||
|
err := m.update(&mr, bson.M{"date": bson.M{"$gte": start}}, statsColl, DAILY_VISITS_COLL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []Visits
|
||||||
|
err := m.daily.Find(nil).All(&result)
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MR) update(mr *mgo.MapReduce, query bson.M, queryColl *mgo.Collection, storeColl string) error {
|
||||||
|
_, err := m.meta.RemoveAll(bson.M{"type": storeColl})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mr.Out = bson.M{"replace": storeColl}
|
||||||
|
_, err = queryColl.Find(query).MapReduce(mr, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.meta.Insert(bson.M{"type": storeColl})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MR) isOutdated(coll string, minutes float64) bool {
|
||||||
|
var result struct {
|
||||||
|
Id bson.ObjectId `bson:"_id"`
|
||||||
|
}
|
||||||
|
err := m.meta.Find(bson.M{"type": coll}).One(&result)
|
||||||
|
if err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
lastUpdate := result.Id.Time()
|
||||||
|
return time.Since(lastUpdate).Minutes() > minutes
|
||||||
|
}
|
Reference in a new issue