3

我有一个接受包含 url 的消息的系统,如果消息中包含某些关键字,则使用 url 作为参数进行 api 调用。

为了节省处理并保持我的最终演示效率。

我不希望在某个时间范围内提交重复的网址。

所以如果这个 url ---> 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 秒后相同的 url 进来,我不希望它提交给 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。

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

实例问题?

4

3 回答 3

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()快得多list.pop(0)

于 2013-10-31T02:45:48.353 回答
1

假设您想要的时间间隔是 1 小时,请保留 2 个每小时递增的计数器,但它们彼此偏移 30 分钟。即计数器 A1, 2, 3, 411:17, 12:17, 13:17, 14:17,计数器 B1, 2, 3, 411:47, 12:47, 13:47, 14:47

现在,如果一个链接进入并且两个计数器中的任何一个与之前的链接相同,则认为它是重复的。

该方案相对于显式时间戳的好处是您可以散列 url+counterA 和 url+counterB 以快速检查 url 是否存在

更新:您需要两个数据存储:一个,带有列的常规数据库表(慢):(url, counterA, counterB)以及两个,一大块n内存(快)。给定一个 url so.com, counterA17和 counterB 18,首先将“17,so.com”散列到一个范围内0n - 1然后查看该地址的位是否打开。同样,散列“18,so.com”并查看该位是否打开。

如果在任何一种情况下都没有打开该位,您确定它在一小时内是一个新的 URL,所以我们完成了(很快)。

如果在任何一种情况下都打开了该位,则在数据库表中查找 url 以检查它是否确实是该 url 或其他一些哈希到同一位的 URL。

进一步更新:布隆过滤器是该方案的扩展。

于 2013-10-31T02:24:59.897 回答
0

我建议保留最近使用的 URL 的内存缓存。像字典一样的东西:

urls = {}

然后对于每个 URL:

if url in urls and (time.time() - urls[url]) < SOME_TIMEOUT:
    # Don't submit the data
else:
    urls[url] = time.time()
    # Submit the data
于 2013-10-31T02:25:29.840 回答