限制传入邮件以避免重复的最佳方法

时间:2013-10-31 02:19:34

标签: python algorithm parsing message-queue messaging

我有一个接受包含网址的邮件的系统,如果邮件中包含某些关键字,则使用网址作为参数进行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。

是否与脚本正在运行这一事实有关,而该集正在添加到?

实例问题?

3 个答案:

答案 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, 411: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”加入范围0n - 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