我有一个接受包含网址的邮件的系统,如果邮件中包含某些关键字,则使用网址作为参数进行API调用。
为了节省处理并保持我的最终演示效率。
我不希望在特定时间范围内提交重复的网址。
所以,如果这个网址---> http://instagram.com/p/gHVMxltq_8/进来并将其提交给api
url = incoming.msg['urls']
url = urlparse(url)
if url.netloc == "instagram.com":
r = requests.get("http://api.some.url/show?url=%s"% url)
然后3秒后相同的网址进来,我不希望它提交给api。
我可以部署哪种编程方法来消除/限制根据时间提交给api的重复邮件?
使用TIM PETERS方法更新
limit = DecayingSet(86400)
l = limit.add(longUrl)
if l == False:
pass
else:
r = requests.get("http://api.some.url/show?url=%s"% url)
此代码段位于长时间运行的进程中,即通过tcp接受流式消息。
每次我传入相同的url时,l每次都返回True。
但是当我在解释器中尝试它时一切都很好,当设置的时间没有到期时它会返回False。
是否与脚本正在运行这一事实有关,而该集正在添加到?
实例问题?
答案 0 :(得分:4)
也许是矫枉过正,但我喜欢为这种事创造一个新类。你永远不知道什么时候需求会变得更加漂亮;-)例如,
from time import time
class DecayingSet:
def __init__(self, timeout): # timeout in seconds
from collections import deque
self.timeout = timeout
self.d = deque()
self.present = set()
def add(self, thing):
# Return True if `thing` not already in set,
# else return False.
result = thing not in self.present
if result:
self.present.add(thing)
self.d.append((time(), thing))
self.clean()
return result
def clean(self):
# forget stuff added >= `timeout` seconds ago
now = time()
d = self.d
while d and now - d[0][0] >= self.timeout:
_, thing = d.popleft()
self.present.remove(thing)
如上所述,只要尝试添加新内容,它就会检查到期时间。也许这不是你想要的,但它应该是一个便宜的检查,因为deque
按照添加顺序保存项目,所以如果没有项目到期则立即退出。很多可能性。
为何选择deque
?因为当项目数量变得非常重要时,deque.popleft()
比<{1}}更快批次。
答案 1 :(得分:1)
假设您所需的间隔是1小时,保持2个计数器每小时递增但它们相互偏移30分钟。一世。即计数器A在1, 2, 3, 4
点11:17, 12:17, 13:17, 14:17
,计数器B在1, 2, 3, 4
点击11:47, 12:47, 13:47, 14:47
。
现在如果链接进来并且两个计数器的 与之前的链接相同,则认为它是重复的。
此方案优于显式时间戳的好处是您可以散列网址+ counterA和url + counterB以快速检查网址是否存在
更新:您需要两个数据存储:一个是常规数据库表(慢),列为:(url, counterA, counterB)
,两个,一块n
位内存(快速)。给出了一个网址so.com
,counterA 17
和counterB 18
,首先将哈希“17,so.com”加入范围0
到n - 1
,看看是否该地址的位已打开。类似地,哈希“18,so.com”并查看该位是否已打开。
如果在任何一种情况下都没有开启该位,您确定它是一小时内的新URL,所以我们(快速)完成了。
如果在任何一种情况下都打开该位,那么在数据库表中查找url以检查它是否确实是那个url还是其他一些散列到同一位的URL。
进一步更新:布隆过滤器是此方案的扩展。
答案 2 :(得分:0)
我建议保留最近使用的URL的内存缓存。像字典一样:
urls = {}
然后为每个网址:
if url in urls and (time.time() - urls[url]) < SOME_TIMEOUT:
# Don't submit the data
else:
urls[url] = time.time()
# Submit the data