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

Python 数千个网络的两个列表之间的交点,python,networking,apache-pig,Python,Networking,Apache Pig,我有一个巨大的网络列表(称为a),我需要检查这些网络的地址是否存在于另一个网络列表(称为B)中: 两份清单的格式如下: 列出 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:等等 1.2.3.4 3.4.1.0/24 我的第一次测试很天真: 列出带有模块的所有IP 将每个列表的IP分成两部分 按两组的顺序做 此方法适用于小列表

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

两份清单的格式如下:

列出

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:等等

1.2.3.4
3.4.1.0/24
我的第一次测试很天真:

  • 列出带有模块的所有IP
  • 将每个列表的IP分成两部分
  • 按两组的顺序做
此方法适用于小列表。但是,此解决方案不适用于数千个网络(即数百万个IP地址),因为我不支持。此外,此解决方案不适用于IPv6网络

两个列表相交最有效的方法是什么?

另外:我还要在列表A和其他列表B:A之间重复这一点∩ C、 A∩ D、 等等

我愿意接受所有建议,即使是:-)

解决方案:

def块(l,n):
对于x范围内的i(0,len(l),n):
收益率l[i:i+n]
res=[]
对于块(a,1000)中的块(a):
对于块中的块(b,1000):
C=IPSet(块a)和IPSet(块b)
如果C>IPSet([]):
决议草案(C)

基于实现IP地址/网络集的
NetAddress
包,这里有一种可能性

首先考虑,如果a= a1∪ A2和B=B1∪ B2,然后是A∩ B=(A1)∩ B1)∪ (A1)∩ B2)∪ (A2)∩ B1)∪ (A2)∩ B2)

因此,您可以将列表拆分为几个小集合,并使用上面的方法以增量方式计算交点。例如:

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的笔记本电脑上,两个5000个随机定义的网络列表(长度为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"

好吧,如果你对猪开放,那么没有什么比这更容易的了。它不会出现内存不足的问题,并且通过
连接
,交叉点非常简单:

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';

完成。

3.4.0.0/16
在两个列表中,所以不应该在交叉点而不是
3.4.1.0/24
?谢谢@larsmans,已修复。您可以用6字节表示IP4地址,4字节表示地址,2字节表示端口。因此,如果使用numpy数组保存地址,500万个地址将使用大约29MB的内存。此解决方案适用于IP地址。但是这个解决方案不能处理cidr符号,不是吗?之前,我必须列举网络的所有IP(至少在IPv6中为2^64 IP…),为什么会有任何不同?这只是比较字符串。如果您的IP地址为
asegaegas11351.13511 35;###
它不会抱怨。这里没有枚举,只是两个任意对象列表的交叉点。谢谢你的解释,但我还是不明白。仅包含一项的两个列表示例:“10.1.2.3”和“10.0.0.0/16”。交叉口的预期结果为10.1.2.3。对我来说,由于CIDR表示法,两个字符串的“简单”比较不会返回真正的交集。你能详细说明一下吗?我真的很想了解你的解决方案。我误解了你所说的“交叉点”的意思。(事实上,我仍然不太确定。)我怀疑在Pig中使用UDF有一种方法可以做到这一点,但我需要更好地理解您的需求。我不太精通IP地址语义。因为注释不是一个解释的好地方,请参阅