golang使用redis对文章进行投票

键盘侠 · · 1111 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

最近在学redis,本人菜鸟.代码是过程式的,没考虑优化.就是发篇文章记录一下.感觉redis还是很强大的.

规则

  1. 评分 = 支持票数*(86400/200)+时间戳, 文章获得为200票就可以在首页展示一天,随着时间的流逝,当分数小于当前时间戳的时候,就从首页撤下.
  2. 使用hash记录文章的标题,链接,作者,文章发布时间,文章得到的投票数量.
  3. 使用两个有序集合来有序的存储文章:第一个有序集合的成员为文章ID,分值为文章的发布时间;第二个有序集合的成员同样为文章ID,分值为文章的评分.通过这两个有序集合,网站既可以根据文章发布的时间来展示文章,也可以根据文章评分的高低来展示文章.
  4. 为了防止用户对同一篇文章进行多次投票,网站需要为每篇文章记录一个已投票用户名单,为此,程序将为每篇文章创建一个集合,并使用这个集合来记录所有投票用户的ID.
  5. 为了节约内存,一篇文章发布满一周后将不能再对它进行投票,文章的评分将被固定下来,而记录文章已投票的用户名单的集合也会被删除.

发布文章

//创建文章
func CreateArticle(conn redis.Conn, title, content, link string, userId int) (err error) {
    articleId, err := redis.Int(conn.Do("incr", "articleid:")) //生成文章ID
    if nil != err {
        return
    }

    now := time.Now().Unix()
    _, err = conn.Do( //将文章详情存入redis中
        "hmset",
        "article:"+strconv.Itoa(articleId),
        "title", title,
        "content", content,
        "link", link,
        "votes", 1,
        "author", userId,
        "time", now,
    )

    if nil != err {
        return
    }

    _, err = conn.Do("sadd", "voted:"+strconv.Itoa(articleId), userId) //将已投票用户存入集合中
    if nil != err {
        return
    }

    exTime := time.Now().Unix() + 7*86400
    _, err = conn.Do("expireAt", "voted:"+strconv.Itoa(articleId), exTime) //记录过期时间为一周
    if nil != err {
        return
    }

    _, err = conn.Do("zadd", "score:", now+VOTE, articleId) //记录文章分值
    if nil != err {
        return
    }

    return nil
}

对文章进行投票

//对文章进行投票
func VoteArticle(conn redis.Conn, articleId, userId int) (err error) {
    cutoff := time.Now().Unix() - 7*86400
    reply, err := redis.Int64(conn.Do("hget", "article:"+strconv.Itoa(articleId), "time"))
    if nil != err {
        return
    }

    if reply < cutoff { //验证投票是否截止
        fmt.Println("投票已截止")
        return
    }

    bool, err := redis.Bool(conn.Do("sismember", "voted:"+strconv.Itoa(articleId), userId)) //检查是否已投过票
    if nil != err {
        return
    }

    if bool {
        fmt.Println("你已投过票")
        return
    }

    _, err = conn.Do("sadd", "voted:"+strconv.Itoa(articleId), userId) //将投票人ID加入集合中
    if nil != err {
        return
    }

    _, err = conn.Do("hincrby", "article:"+strconv.Itoa(articleId), "votes", 1) //文章得票 +1
    if nil != err {
        return
    }

    _, err = conn.Do("zincrby", "score:", VOTE, articleId)        //增加文章得分
    if nil != err {
        return
    }
    fmt.Println(11)
    return nil
}

按分数高低获取文章

//设置分页
const (
    ARTICLES_PER_PAGE = 2
)

//获取文章
func GetArticles(conn redis.Conn, page int) (ids []int, err error) {
    start := (page - 1) * ARTICLES_PER_PAGE
    end := start + ARTICLES_PER_PAGE - 1

    ids, err = redis.Ints(conn.Do("zrevrange", "score:", start, end)) //获取文章排名,分数由高到低
    if nil != err {
        return
    }

    return ids, nil
}

main

const (
    VOTE = 86400 / 200        //分值
)

func main() {
    conn, err := redis.Dial("tcp", ":6379")
    if nil != err {
        fmt.Println(err)
        os.Exit(1)
    }

    //创建文章
    err = CreateArticle(conn, "第一篇", "内容1", "www.baidu.com", 1) 
    if nil != err {
        fmt.Println(err)
    }
    
    //对文章进行投票
    err = VoteArticle(conn, 1, 2)
    if nil != err {
        fmt.Println(err)
    }

    //获取分数最高的文章,并进行分页
    ids, err := GetArticles(conn, 1)
    if nil !=err {
        fmt.Println(err)
    }

    fmt.Println(ids)

}

有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:键盘侠

查看原文:golang使用redis对文章进行投票

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1111 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传