Skip to content

Instantly share code, notes, and snippets.

@elhardoum
Created February 12, 2023 17:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elhardoum/b94107d336e19c1907560e99211f9369 to your computer and use it in GitHub Desktop.
Save elhardoum/b94107d336e19c1907560e99211f9369 to your computer and use it in GitHub Desktop.
Twitter-like Trending Topics App Backend - PHP Example
<?php
// @see https://medium.com/@elhardoum/2a442e04bb2f
function get_redis() : \Redis {
static $redis;
if ( null === $redis ) {
$redis = new \Redis();
$redis->connect('0.0.0.0', 6379);
register_shutdown_function([$redis, 'close']);
}
return $redis;
}
function boost_topic(string $setId, string $member, int $increment_by=1) : void
{
// create a set for 5 minutes, with a TTL of 1 hour
// reason: cannot expire set members without expiring the whole set
$setId .= ':' . date('H.') . round(date('i')/5);
// increment set member score
get_redis()->zincrby($setId, $increment_by, $member);
if ( get_redis()->ttl($setId) == -1 ) // is this a new set? if so, set TTL to 60min to we don't keep stale data
get_redis()->expire($setId, 3600);
}
function get_top_topics(string $setId, int $limit=10) : array
{
$items = [];
// query all sets created in the past 30min
if ( $sets = get_redis()->keys("{$setId}:*") ) {
$meta = [ 'withscores' => true, 'limit' => [0, $limit] ];
// begin transaction
get_redis()->multi();
foreach ( $sets as $set ) {
// get top N (=$limit) winners of each set and merge them together
get_redis()->zrevrangebyscore($set, '+inf', '-inf', $meta);
}
// commit transaction
$result = get_redis()->exec();
foreach ( $sets as $i => $set ) {
if ( $list = array_map('intval', $result[$i] ?? []) ) {
foreach ( $list as $k=>$v ) {
$items[$k] = ($items[$k] ?? 0) + $v;
}
}
}
arsort($items);
// return top winners
$items = array_slice($items, 0, $limit);
}
return $items;
}
// boost a topic's score
boost_topic('hot-topics', 'Caturday');
boost_topic('hot-topics', 'Feline');
boost_topic('hot-topics', 'Thursday');
// boost a topic's score by 2 points
boost_topic('hot-topics', 'Feline', 2);
// get a list of top 2 trends
get_top_topics('hot-topics', 2); // [ 'Feline' => 3, 'Caturday' => 1 ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment