1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# coding=utf-8
from __future__ import unicode_literals, absolute_import, print_function
import datetime
from django.conf import settings
from gm_types.gaia import DIARY_OPERATION
from talos.cache.diaryheatscorecache import diary_heat_cache
from talos.models.diary.diaryrank import DiaryRank
class DiaryRankTool(object):
LOSE_RATE = settings.DIARY_HEAT_RANK['lose_rate']
MAX_SCORE = settings.DIARY_HEAT_RANK['max_score']
REPLY_NUM_PER_DEVICE = settings.DIARY_HEAT_RANK['reply_num_per_device']
def __init__(self, diary_id):
self.diary_id = diary_id
self.heat_score_map = {
DIARY_OPERATION.CREATE_TOPIC: settings.DIARY_HEAT_RANK['score_create_topic'],
DIARY_OPERATION.MODIFY_DIARY: settings.DIARY_HEAT_RANK['score_modify_diary'],
DIARY_OPERATION.SELF_REPLY: settings.DIARY_HEAT_RANK['score_self_reply'],
DIARY_OPERATION.OTHER_REPLY: settings.DIARY_HEAT_RANK['score_other_reply'],
DIARY_OPERATION.OTHER_VOTE: settings.DIARY_HEAT_RANK['score_other_vote'],
}
self.heat_restriction_map = {
DIARY_OPERATION.CREATE_TOPIC: settings.DIARY_HEAT_RANK['restrict_create_topic'],
DIARY_OPERATION.MODIFY_DIARY: settings.DIARY_HEAT_RANK['restrict_modify_diary'],
DIARY_OPERATION.SELF_REPLY: settings.DIARY_HEAT_RANK['restrict_self_reply'],
DIARY_OPERATION.OTHER_REPLY: settings.DIARY_HEAT_RANK['restrict_other_reply'],
DIARY_OPERATION.OTHER_VOTE: settings.DIARY_HEAT_RANK['restrict_other_vote'],
}
def reset_action_map(self):
diary_heat_cache.reset_action_num_map(self.diary_id)
def get_diary_heat(self):
dr = DiaryRank.objects.get(diary_id=self.diary_id)
return dr.heat_score
def update_action_num_map(self, action, extra_id=None):
action_num_map = diary_heat_cache.get_action_num_map(self.diary_id)
action_num_map[action] += 1
if extra_id is not None:
if action == DIARY_OPERATION.SELF_REPLY:
ids = action_num_map['replied_user_ids']
if extra_id not in ids:
ids.append(extra_id)
elif action == DIARY_OPERATION.OTHER_REPLY:
device_map = action_num_map['devices_reply_num_map']
key = str(extra_id)
if key in device_map.keys():
device_map[key] += 1
else:
device_map[key] = 1
diary_heat_cache.set_action_num_map(self.diary_id, action_num_map)
def add_score(self, score):
dr, _ = DiaryRank.objects.get_or_create(diary_id=self.diary_id)
original_score = self.get_diary_heat()
new_score = original_score + score
if new_score > self.MAX_SCORE:
new_score = self.MAX_SCORE
elif new_score < 0:
new_score = 0
dr.heat_score = new_score
dr.save()
def lose_score(self, current_time):
score = self.get_diary_heat()
last_calculated_time = diary_heat_cache.get_last_calculated_time(self.diary_id)
time_delta = current_time - last_calculated_time
seconds = time_delta.total_seconds()
hour = seconds / 3600
lose_score = self.LOSE_RATE * hour * score
diary_heat_cache.set_last_calculated_time(self.diary_id, current_time)
self.add_score(-lose_score) # 加负数即为减
def in_restriction(self, action, extra_id):
current_action_num_map = diary_heat_cache.get_action_num_map(self.diary_id)
c = current_action_num_map[action]
max_action_num = self.heat_restriction_map[action]
if c >= max_action_num:
return True
if action == DIARY_OPERATION.SELF_REPLY:
replied_user_ids = current_action_num_map['replied_user_ids']
if extra_id in replied_user_ids:
return True
else:
# self.update_action_num_map(action, extra_id=extra_id)
return False
elif action == DIARY_OPERATION.OTHER_REPLY:
devices_reply_num_map = current_action_num_map['devices_reply_num_map']
extra_id = str(extra_id)
if extra_id in devices_reply_num_map.keys():
if devices_reply_num_map[extra_id] >= self.REPLY_NUM_PER_DEVICE:
return True
else:
# self.update_action_num_map(action, extra_id=extra_id)
return False
else:
# self.update_action_num_map(action, extra_id=extra_id)
return False
else:
return False
def add_heat(self, action, time, extra_id=None):
previous_day_time = diary_heat_cache.get_previous_day_time(self.diary_id)
previous_day = previous_day_time.date()
day_delta = (time.date() - previous_day).days
if day_delta >= 1:
diary_heat_cache.set_previous_day_time(self.diary_id, time)
self.reset_action_map()
if self.in_restriction(action, extra_id):
return
else:
added_score = self.heat_score_map[action]
self.update_action_num_map(action, extra_id)
self.add_score(added_score)
self.lose_score(time)
@classmethod
def get_loss_score_by_time(cls, diary_id, current_score, current_time=None):
# only read, do not write.es data async will trigger this
current_time = current_time or datetime.datetime.now()
last_calculated_time = diary_heat_cache.get_last_calculated_time(diary_id)
time_delta = current_time - last_calculated_time
seconds = time_delta.total_seconds()
hour = seconds / 3600
lose_score = cls.LOSE_RATE * hour * current_score
return lose_score