def create_connections(N, M, K1=None, K2=None): """Create connections from users 1 - N. Users with uid less equal than M will be considered as celebrities having many followers. Parameters ---------- N: int The number of users. M: int The number of celebrities. K1: int The average number of followers for celebrities. Default: 0.05 * N. K2: int The average number of followers for normal users. Default: 0.001 * N. """ assert N >= M if K1 is None: K1 = int(N * 0.05) if K2 is None: K2 = int(N * 0.001) for uid in range(1, M + 1): pipe = conn.pipeline(False) s = random.randint(1, N - K1) for follower_uid in range(s, s + K1): follow(follower_uid, uid, pipe) pipe.execute() for uid in range(M + 1, N + 1): pipe = conn.pipeline(False) s = random.randint(1, N - K2) for follower_uid in range(s, s + K2): follow(follower_uid, uid, pipe) pipe.execute()
def unfollow(follower, followee): """Remove a connection between follower and followee.""" follow_ts = conn.zscore(utils.get_followers_key(followee), follower) _tweets = tweets.get_tweets_since(followee, follow_ts, {'tid', 'uid'}) pipe = conn.pipeline() pipe.zrem(utils.get_followers_key(followee), follower) pipe.zrem(utils.get_followees_key(follower), followee) tweets.delete_tweets(_tweets, pipe) pipe.execute()
def get_tweets(tids, fields=None): """Return tweets with specified tids.""" pipe = conn.pipeline(False) for tid in tids: if fields is None: pipe.hgetall(utils.get_tweet_key(tid)) else: pipe.hmget(utils.get_tweet_key(tid), *fields) tweets = [Tweet.load_dict(d) for d in pipe.execute()] return tweets
def create_tweets(N, M, K1=200, K2=80): """Create tweets from users 1 - N. Users with uid less equal than M will be considered as celebrities having many followers. """ assert N >= M pipe = conn.pipeline(False) for uid in range(1, M + 1): pipe = conn.pipeline(False) for _ in range(K1): post_tweet(uid, pipe, body=fake_tweet_body(), location=fake_location()) pipe.execute() for uid in range(M + 1, N + 1): pipe = conn.pipeline(False) for _ in range(K2): post_tweet(uid, pipe, body=fake_tweet_body(), location=fake_location()) pipe.execute()
def delete_tweets(tweets, pipe=None): """Delete tweets with specified tids.""" execute = True if pipe is None: pipe = conn.pipeline(False) execute = True else: execute = False for tweet in tweets: delete_tweet(tweet, pipe) if execute: pipe.execute()
def follow(follower, followee, pipe=None): """Create a connection between follower and followee.""" if pipe is None: pipe = conn.pipeline() execute = True else: execute = False pipe.zadd(utils.get_followers_key(followee), follower, utils.get_timestamp()) pipe.zadd(utils.get_followees_key(follower), followee, utils.get_timestamp()) if execute: pipe.execute()
def delete_tweet(tweet, pipe=None): """Delete a tweet.""" followers = users.get_followers(tweet.uid) if pipe is None: pipe = conn.pipeline(False) execute = True else: execute = False pipe.zrem(utils.get_user_tweets_key(tweet.uid), tweet.tid) pipe.zrem(utils.get_timeline_key(tweet.uid), tweet.tid) for follower_uid in followers: pipe.zrem(utils.get_timeline_key(follower_uid), tweet.tid) pipe.delete(utils.get_tweet_key(tweet.tid)) if execute: pipe.execute()
def refresh_timeline(uid): """Refresh user's timeline. Fetch all delayed tweets from his/her followees. """ last_tid = conn.zrevrange(utils.get_timeline_key(uid), 0, 0) last_tweet = tweets.get_tweet(last_tid) if not last_tweet: return followees = get_followees(uid) pipe = conn.pipeline(False) for followee in followees: _tweets = tweets.get_tweets_since(followee, last_tweet.ts, {'tid', 'datetime'}) for tweet in _tweets: pipe.zadd(utils.get_timeline_key(uid), tweet.tid, tweet.ts) pipe.execute()
def post_tweet(uid, pipe=None, **tweet_info): """Create a new tweet with basic infomation. Parameters ---------- uid: str User ID. pipe: Pipeline object A Redis pipeline object, if given, need to execute manually outside this function. body: str The body of the tweet. location: str The location when posting this tweet. original: bool Whether this tweet is an original tweet or just a retweet. """ tweet_info['uid'] = uid tweet_info['tid'] = uuid4().hex tweet_info['datetime'] = datetime.now() tweet_info.setdefault('original', True) tweet = Tweet.load_dict(tweet_info) if pipe is None: pipe = conn.pipeline(False) execute = True else: execute = False pipe.hmset(utils.get_tweet_key(tweet.tid), tweet.dump_dict()) pipe.zadd(utils.get_user_tweets_key(uid), tweet.tid, tweet.ts) pipe.zadd(utils.get_timeline_key(uid), tweet.tid, tweet.ts) if users.get_followers_count(uid) < config.DIRECT_INSERT_THRES: # Perform direct insertion followers = users.get_followers(uid) for follower_uid in followers: pipe.zadd(utils.get_timeline_key(follower_uid), tweet.tid, tweet.ts) if execute: pipe.execute()