数千个网络的两个列表之间的交叉点

时间:2013-03-23 13:56:44

标签: python networking apache-pig

我有一个庞大的网络列表(称为A),我需要检查这些网络的地址是否存在于另一个网络列表中(称为B):

两个列表的格式如下:

听A

1.2.3.4
145.2.3.0/24
6.5.0.0/16
3.4.1.0/24

听B

1.5.6.7
10.0.3.0/24
1.2.3.0/24
3.4.0.0/16

两个列表A∩B:etc

的交集的预期结果
1.2.3.4
3.4.1.0/24

我的第一次测试很天真:

此方法适用于小型列表。但是,此解决方案不适用于数千个网络(即数百万个IP地址),因为我don't have enough memory。此外,此解决方案不适用于 IPv6 网络。

执行两个列表交集的最有效方法是什么?

另外:我还要在列表A和其他列表之间重复这个:B:A∩C,A∩D等。

我对所有建议持开放态度,即使使用pig: - )

解决方案:

def chunks(l, n):
  for i in xrange(0, len(l), n):
    yield l[i:i+n]

res = []
for chunk_a in chunks(A, 1000):
  for chunk_b in chunks(B, 1000):
      C = IPSet(chunk_a) & IPSet(chunk_b)
      if C > IPSet([]):
          res.append(C)

2 个答案:

答案 0 :(得分:1)

这是基于实现IP地址/网络集的netaddr包的一种可能性。

首先,考虑如果A =A1∪A2和B =B1∪B2,那么A∩B=(A1∩B1)∪(A1∩B2)∪(A2∩B1)∪(A2∩B2)。 / p>

因此,您将列表分成小集并使用上面的内容逐步计算交集。例如:

from netaddr import IPSet

A1 = IPSet(['1.2.3.4','145.2.3.0/24'])
A2 = IPSet(['6.5.0.0/16','3.4.1.0/24'])
B1 = IPSet(['1.5.6.7','10.0.3.0/24'])
B2 = IPSet(['1.2.3.0/24','3.4.0.0/16'])

A1B1 = A1 & B1
A1B2 = A1 & B2
A2B1 = A2 & B1
A2B2 = A2 & B2

A1B1 | A1B2 | A2B1 | A2B2
-> IPSet(['1.2.3.4/32', '3.4.1.0/24'])

但考虑到这一点,在使用IPSet时,您不需要列出所有地址,您可以执行交叉点而无需将列表拆分为小集。


更新:在具有4GB内存的笔记本电脑上,两个5,000个随机定义的网络列表(长度为8到24位)的交集仅需几秒钟:

制作两个IP地址列表:

import random

f = open('iplist1.txt','w')
for i in range(5000):
    ip = '.'.join([str(random.randint(1,254)) for i in range(4)])
    ip += '/'+str(random.randint(8,24))
    f.write(ip+'\n')
f.close()

f = open('iplist2.txt','w')
for i in range(5000):
    ip = '.'.join([str(random.randint(1,254)) for i in range(4)])
    ip += '/'+str(random.randint(8,24))
    f.write(ip+'\n')
f.close()

将它们相交:

import time
import netaddr

ipset1 = netaddr.IPSet(open('iplist1.txt','r').readlines())
ipset2 = netaddr.IPSet(open('iplist2.txt','r').readlines())

print "Set 1:", len(ipset1), "IP addresses"
print "Set 2:", len(ipset2), "IP addresses"

start = time.time()
ipset = ipset1 & ipset2
print "Elapsed:", time.time() - start
print "Intersection:",len(ipset),"IP addresses"

答案 1 :(得分:0)

如果你对猪开放,那么没有什么比这更容易了。内存耗尽不会有麻烦,JOIN

交叉点很简单
A = LOAD '/path/to/A' AS (ip:chararray);
B = LOAD '/path/to/B' AS (ip:chararray);

intersection = FOREACH (JOIN A BY ip, B BY ip) GENERATE A::ip;
STORE intersection INTO '/path/to/output';

完成。