Redisを使用した記事投票サイトの構築


関連するkey:
1. article_time,記事の公開時間を記録するzset構造
2. article_score,文章の得点を記録し,zset構造
スコア=公開時間+投票ユーザ数X 432
3. voted_article_id,文章の投票ユーザ集合を記録し,文章の発行者は文章の投票ユーザとしてデフォルトである,set構造
4. article_article_id,文章を記述するためのhash構造
5. group_groupname,グループgroupnameの下の文章集合,set構造
6. score_groupname,グループgroupnameの下の文章スコアセット,zset構造
# python3
# -*- coding: utf-8 -*-

import redis
import time

ONE_WEEK_IN_SECONDS = 7 * 86400
#         200  ,           
VOTE_SCORE = 86400 / 200
ARTICLES_PER_PAGE = 25

def redis_init(redis):
    # article_time        
    redis.zadd('article_time', article_100408=1496762197, article_100635=1496769721, article_100716=1496760089)
    # article_score      
    redis.zadd('article_score', article_100408=1496766517, article_100635=1496770153, article_100716=1496765705)
    # voted_article_id     article_id          
    redis.sadd('voted_100408', 'user_234487', 'user_253378', 'user_364680',
               'user_132097', 'user_350917')
    #  hash      
    article_desc = {'title':'kunlun', 'link':'www.kunlun.com', 'poster':'user_234487',
                    'time':1441728000, 'votes':523}
    redis.hmset('article_100408', article_desc)
    article_desc = {'title': 'zhuxian', 'link': 'www.zhuxian.com', 'poster': 'user_234488',
                    'time': 1081440000, 'votes': 677}
    redis.hmset('article_100635', article_desc)
    article_desc = {'title': 'soushenji', 'link': 'www.soushenji.com', 'poster': 'user_234489',
                    'time': 1187280000, 'votes': 421}
    redis.hmset('article_100635', article_desc)
    #       
    redis.set('article_index', 200000)

#        
def article_vote(conn, user, article):
    cutoff = time.time() - ONE_WEEK_IN_SECONDS
    if conn.zscore('article_time', article) < cutoff:
        return

    article_id = article.partition('_')[-1]
    if conn.sadd('voted_' + article_id, user):
        conn.zincrby('article_score', article, VOTE_SCORE)
        conn.hincrby(article, 'votes', 1)

#      
def post_article(conn, user, title, link):
    article_id = str(conn.incr('article_index'))

    voted = 'voted_' + article_id
    # poster          
    conn.sadd(voted, user)
    #   key    
    conn.expire(voted, ONE_WEEK_IN_SECONDS)

    now = time.time()
    article = 'article_' + article_id
    conn.hmset(article, {
        'title': title,
        'link': link,
        'poster': user,
        'time': now,
        'votes': 1,
    })

    conn.zadd('article_score', article, now + VOTE_SCORE)
    conn.zadd('article_time', article, now)

    return article_id

#          
#         ,order='article_time'
# page,    
def get_articles(conn, page, order='article_score'):
    start = (page-1) * ARTICLES_PER_PAGE
    end = start + ARTICLES_PER_PAGE - 1

    ids = conn.zrevrange(order, start, end)
    articles = []
    for id in ids:
        article_data = conn.hgetall(id)
        article_data['id'] = id
        articles.append(article_data)

    return articles

#
def add_remove_groups(conn, article_id, to_add=[], to_remove=[]):
    article = 'article_' + article_id
    for group in to_add:
        conn.sadd('group_' + group, article)
    for group in to_remove:
        conn.srem('group_' + group, article)

#         
def get_group_articles(conn, group, page, order='article_score'):
    key = order + group
    if not conn.exists(key):
        conn.zinterstore(key,
                         ['group_' + group, order],
                         aggregate='max'
                         )
        #   60s
        conn.expire(key, 60)
    return get_articles(conn, page, key)

r = redis.Redis(host='redis_serverip', port=6379, password='redis_passwd', db=0)

# redis_init(r)

# article_vote(r,'use_115423', 'article_100408')
#
# new_article_id =  post_article(r, 'user_5424', 'yingxiongzhi', 'www.yingxiongzhi.com')
# print('new_article_id:', new_article_id)
#
# add_remove_groups(r, 'article_100408')
#
# get_group_articles(r, 'programming', 1)

PS:
redis-pyモジュールには、RedisとStrictRedisの2つのクラスがあり、両者の部分的なAPIはやや異なり、本稿ではRedisというクラスを使用する.
 
 
反対票の実現:
def article_against(conn, user, article):
    cutoff = time.time() - ONE_WEEK_IN_SECONDS
    if conn.zscore('article_time', article) < cutoff:
        return

    article_id = article.partition('_')[-1]
    if conn.sadd('against_' + article_id, user):
        conn.incrby('article_score', article, -VOTE_SCORE)
        conn.hincrby(article, 'votes', -1)

投票の競合条件を削除するには、次の手順に従います.
def article_against(conn, user, article):
    cutoff = time.time() - ONE_WEEK_IN_SECONDS
    if conn.zscore('article_time', article) < cutoff:
        return

    article_id = article.partition('_')[-1]
    if conn.sadd('against_' + article_id, user):
        pipeline = conn.pipeline()
        
        conn.incrby('article_score', article, -VOTE_SCORE)
        conn.hincrby(article, 'votes', -1)

        pipeline.execute()

 
参考資料:
『Redis実戦』
https://pypi.python.org/pypi/redis
https://redis-py.readthedocs.io/en/latest/
転載先:https://www.cnblogs.com/gattaca/p/6958789.html