@@ -13,38 +13,28 @@ object App {
13
13
14
14
/** application state modeled as immutable maps in vars (not shared with other application parts) */
15
15
private var tweetMap : TreeMap [Long , TypedTweet ] = TreeMap .empty(reverseLongOrdering)
16
+
17
+ /** set for keeping track of number of tweets immediately (so that tweetMap still has previous tweet available
18
+ * when adding to other sorting maps) */
16
19
private val tweetIds : scala.collection.mutable.TreeSet [Long ] = scala.collection.mutable.TreeSet .empty(reverseLongOrdering)
17
- private var followersMap : TreeMap [Int , HashSet [TypedTweet ]] = TreeMap .empty(reverseIntOrdering)
18
- private var rtMap : TreeMap [Int , HashSet [TypedTweet ]] = TreeMap .empty(reverseIntOrdering)
19
- private var favoritesMap : TreeMap [Int , HashSet [TypedTweet ]] = TreeMap .empty(reverseIntOrdering)
20
20
21
- private def addToSortingMap [T ](id : Int , t : T , map : TreeMap [Int , HashSet [T ]]): TreeMap [Int , HashSet [T ]] = {
22
- map + (id -> (map.getOrElse(id, HashSet [T ]()) + t))
23
- }
21
+ /** maps for keeping followers / retweets / favorites count as key and Set with all matching Tweets as value
22
+ * on update tweet will be removed from old set and inserted into set at new position when updated tweet is received
23
+ * by means of retweets (e.g remove at 100 retweets, insert new tweet representation at 101 retweets) */
24
+ private var followersMap : TreeMap [Int , Set [TypedTweet ]] = TreeMap .empty(reverseIntOrdering)
25
+ private var rtMap : TreeMap [Int , Set [TypedTweet ]] = TreeMap .empty(reverseIntOrdering)
26
+ private var favoritesMap : TreeMap [Int , Set [TypedTweet ]] = TreeMap .empty(reverseIntOrdering)
24
27
25
- def removeFromSortingMap [T ](id : Int , t : T , map : TreeMap [Int , HashSet [T ]]): TreeMap [Int , HashSet [T ]] = {
26
- map + (id -> (map.getOrElse(id, HashSet [T ]()) - t))
28
+ /** adding and removing from data structures above -> should probably be refactored into its own class */
29
+ private def addToSortingMap [T ](id : Int , t : T , map : TreeMap [Int , Set [T ]]): TreeMap [Int , Set [T ]] = {
30
+ map + (id -> (map.getOrElse(id, Set [T ]()) + t))
27
31
}
28
-
29
- def addTweetImmediately (t : TypedTweet ): Unit = {
30
- tweetIds += t.id
31
- BirdWatch .setTweetCount(tweetCount)
32
-
33
- tweetMap.get(t.id).map {
34
- prev => {
35
- rtMap = removeFromSortingMap(prev.retweet_count, prev, rtMap)
36
- followersMap = removeFromSortingMap(prev.followers_count, prev, followersMap)
37
- favoritesMap = removeFromSortingMap(prev.favorite_count, prev, favoritesMap)
38
- }
39
- }
40
-
41
- if (t.retweet_count > 0 ) { rtMap = addToSortingMap(t.retweet_count, t, rtMap) }
42
- if (t.followers_count > 0 ) { followersMap = addToSortingMap(t.followers_count, t, followersMap) }
43
- if (t.favorite_count > 0 ) { favoritesMap = addToSortingMap(t.favorite_count, t, favoritesMap) }
44
-
45
- tweetMap = tweetMap + (t.id -> t)
32
+ def removeFromSortingMap [T ](id : Int , t : T , map : TreeMap [Int , Set [T ]]): TreeMap [Int , Set [T ]] = {
33
+ map + (id -> (map.getOrElse(id, Set [T ]()) - t))
46
34
}
47
35
36
+ /** function for adding tweets, only called for previous tweets. previous tweets are loaded backwards in time,
37
+ * therefore updating tweets existing tweets is not necessary (as the previous tweet going back in time will be older) */
48
38
def addTweet (t : TypedTweet )(): Unit = {
49
39
/** if previous version exists: remove from map and sets first */
50
40
if (! tweetMap.contains(t.id)) {
@@ -55,6 +45,7 @@ object App {
55
45
}
56
46
}
57
47
48
+ /** put curried addTweet function call on priority queue in order to be performed later */
58
49
def enqueueTweet (t : TypedTweet ): Unit = {
59
50
if (! tweetMap.contains(t.id)) {
60
51
tweetIds += t.id
@@ -64,12 +55,34 @@ object App {
64
55
}
65
56
}
66
57
58
+ /** add new tweet from SSE stream, needs to update existing tweets as whatever comes in here will be newer
59
+ * (retweeted tweets re-appear in their entirety in the retweet_status property of a tweets JSON representation) */
60
+ def addTweetImmediately (t : TypedTweet ): Unit = {
61
+ tweetIds += t.id
62
+ BirdWatch .setTweetCount(tweetCount) // update UI with new count
63
+ tweetMap.get(t.id).map {
64
+ prev => {
65
+ rtMap = removeFromSortingMap(prev.retweet_count, prev, rtMap)
66
+ followersMap = removeFromSortingMap(prev.followers_count, prev, followersMap)
67
+ favoritesMap = removeFromSortingMap(prev.favorite_count, prev, favoritesMap)
68
+ }
69
+ }
70
+
71
+ if (t.retweet_count > 0 ) { rtMap = addToSortingMap(t.retweet_count, t, rtMap) }
72
+ if (t.followers_count > 0 ) { followersMap = addToSortingMap(t.followers_count, t, followersMap) }
73
+ if (t.favorite_count > 0 ) { favoritesMap = addToSortingMap(t.favorite_count, t, favoritesMap) }
74
+
75
+ tweetMap = tweetMap + (t.id -> t)
76
+ }
77
+
78
+ /** lazily evaluate sorted tweets for each sort order */
67
79
def tweetsByIdDesc (n : Int , skip : Int ) = tweetMap.values.toIterator.drop(skip).take(n)
68
80
def tweetsByFollowersDesc (n : Int , skip : Int ) = followersMap.values.toIterator.flatten.drop(skip).take(n)
69
81
def tweetsByRetweetsDesc (n : Int , skip : Int ) = rtMap.values.flatten.toIterator.drop(skip).take(n)
70
82
def tweetsByFavoritesDesc (n : Int , skip : Int ) = favoritesMap.values.flatten.toIterator.drop(skip).take(n)
71
83
def tweetCount = tweetIds.size
72
84
85
+ /** reset application state when starting new query*/
73
86
def empty (): Unit = {
74
87
tweetMap = TreeMap .empty(reverseLongOrdering)
75
88
followersMap = TreeMap .empty(reverseIntOrdering)
0 commit comments