Skip to content

Commit

Permalink
Add heavykeeper to detect top followees
Browse files Browse the repository at this point in the history
  • Loading branch information
dcadenas committed Jan 28, 2025
1 parent 9c7e62a commit aa18f38
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 0 deletions.
82 changes: 82 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ config_rs = { version = "0.14", package = "config", features = ["yaml"] }
env_logger = "0.11.5"
futures = "0.3.30"
gcloud-sdk = { version = "0.25.6", features = ["google-pubsub-v1"] }
heavykeeper = "0.2.4"
hyper = "1.4.1"
hyper-util = { version = "0.1.10", features = ["client", "http1", "client-legacy"] }
log = "0.4.22"
Expand Down
25 changes: 25 additions & 0 deletions src/domain/notification_factory.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::NotificationMessage;
use crate::domain::{FollowChange, FolloweeNotificationFactory};
use crate::metrics;
use heavykeeper::TopK;
use nostr_sdk::PublicKey;
use ordermap::OrderMap;
use std::collections::HashSet;
Expand All @@ -17,6 +18,7 @@ pub struct NotificationFactory {
followee_maps: OrderMap<Followee, FolloweeNotificationFactory>,
burst: u16,
min_seconds_between_messages: NonZeroUsize,
top_followees: TopK<Vec<u8>>,
}

impl NotificationFactory {
Expand All @@ -28,10 +30,18 @@ impl NotificationFactory {

let min_seconds_between_messages = NonZeroUsize::new(min_seconds_between_messages).unwrap();

// Initialize TopK with parameters:
// k=20 (top 20 followees)
// width=1000 (internal width for accuracy)
// depth=5 (internal depth for accuracy)
// decay=0.925 (decay factor for aging out less frequent items)
let top_followees = TopK::new(20, 1000, 5, 0.925);

Self {
followee_maps: OrderMap::with_capacity(1_000),
burst,
min_seconds_between_messages,
top_followees,
}
}

Expand All @@ -43,6 +53,13 @@ impl NotificationFactory {
FolloweeNotificationFactory::new(self.burst, self.min_seconds_between_messages)
});

// Add to TopK tracking when it's a follow (not unfollow)
if follow_change.is_follower() {
// Convert friendly_followee to bytes for TopK tracking
let friendly_id = follow_change.friendly_followee().to_string();
self.top_followees.add(friendly_id.as_bytes().to_vec());
}

followee_info.insert(follow_change);
}

Expand Down Expand Up @@ -114,6 +131,14 @@ impl NotificationFactory {
messages.iter().filter(|m| m.is_single()).count(),
messages.iter().filter(|m| !m.is_single()).count()
);

// Log top 20 most followed accounts
info!("Top 20 most followed accounts:");
for node in self.top_followees.list() {
if let Ok(friendly_id) = String::from_utf8(node.item.to_vec()) {
info!(" {}: {} follows", friendly_id, node.count);
}
}
}

pub fn is_empty(&self) -> bool {
Expand Down

0 comments on commit aa18f38

Please sign in to comment.