Python URL的最长前缀匹配
我需要关于任何标准python包的信息,这些包可以用于URL上的“最长前缀匹配”。我已经看了两个标准包&'http://pypi.python.org/pypi/trie/0.1.1但它们对于URL上最长前缀匹配任务似乎没有用处 例如,如果我的集合有这些URL 1->http://www.google.com/mail , 2->http://www.google.com/document, 3->http://www.facebook.com等等 现在如果我搜索'http://www.google.com/doc'然后它应该返回2并搜索'http://www.face'应该返回3 我想确认是否有任何标准python包可以帮助我完成这项工作,或者我应该实现一个用于前缀匹配的Trie 我不是在寻找一种正则表达式类型的解决方案,因为它不能随着URL数量的增加而伸缩Python URL的最长前缀匹配,python,url,trie,longest-prefix,Python,Url,Trie,Longest Prefix,我需要关于任何标准python包的信息,这些包可以用于URL上的“最长前缀匹配”。我已经看了两个标准包&'http://pypi.python.org/pypi/trie/0.1.1但它们对于URL上最长前缀匹配任务似乎没有用处 例如,如果我的集合有这些URL 1->http://www.google.com/mail , 2->http://www.google.com/document, 3->http://www.facebook.com等等 现在如果我搜索'http://www.goog
非常感谢。下面的函数将返回最长匹配的索引。其他有用的信息也可以很容易地提取出来
from os.path import commonprefix as oscp
def longest_prefix(s, slist):
pfx_idx = ((oscp([s, url]), i) for i, url in enumerate(slist))
len_pfx_idx = map(lambda t: (len(t[0]), t[0], t[1]), pfx_idx)
length, pfx, idx = max(len_pfx_idx)
return idx
slist = [
'http://www.google.com/mail',
'http://www.google.com/document',
'http://www.facebook.com',
]
print(longest_prefix('http://www.google.com/doc', slist))
print(longest_prefix('http://www.face', slist))
此示例适用于小url列表,但不能很好地扩展
def longest_prefix_match(search, urllist):
matches = [url for url in urllist if url.startswith(search)]
if matches:
return max(matches, key=len)
else:
raise Exception("Not found")
使用该模块的实现
结果:
'http' -> ['http://www.facebook.com', 'http://www.google.com/document', 'http://www.google.com/mail']
'http://www.go' -> ['http://www.google.com/document', 'http://www.google.com/mail']
'http://www.fa' -> ['http://www.facebook.com']
'http://fail' -> []
或者使用相同的结果,但列表的顺序不同
from pytrie import StringTrie
url_list = [
'http://www.google.com/mail',
'http://www.google.com/document',
'http://www.facebook.com',
]
url_trie = StringTrie()
for url in url_list:
url_trie[url] = url
searches = ("http", "http://www.go", "http://www.fa", "http://fail")
for search in searches:
print "'%s' ->" % search, url_trie.values(prefix=search)
我开始认为从内存使用的角度来看,a会更好。这就是基数树的外观:
而trie看起来更像:
如果您愿意用RAM换取时间性能,那么可能会很有用。它具有很好的算法特性,例如它允许在线性时间内解决最长的公共子串问题 如果总是搜索前缀而不是任意子字符串,则可以在填充
SubstringDict()
时添加唯一的前缀:
这种使用subfixtree
的方式似乎不太理想,但在我尝试过的数据上,它比[基于.startswith()
]的构建时间快20-150倍(没有SubstringDict()
)
要安装,请运行:
性能比较
subfixtree
vs.pytrie
vs.trie
vs.datrie
vs.startswith
-函数
安装程序
记录的时间是1000次搜索的3次重复中的最短时间。trie构建时间包含在所有搜索中,并分布在所有搜索中。搜索是在主机名集合(从1到1000000个项目)上执行的
搜索字符串的三种类型:
-字符串不匹配不存在\u键
-百万分之二十左右稀有钥匙
-出现次数与集合大小相当frequency_key
| function | memory, | ratio |
| | GiB | |
|-------------+---------+-------|
| suffix_tree | 0.853 | 1.0 |
| pytrie | 3.383 | 4.0 |
| trie | 3.803 | 4.5 |
| datrie | 0.194 | 0.2 |
| startswith | 0.069 | 0.1 |
#+TBLFM: $3=$2/@3$2;%.1f
要复制结果
- 罕见的密钥/不存在的密钥案例
如果URL的数量少于10000,那么datrie是最快的,例如
N> 10000-
速度更快,suffextree
平均速度明显较慢startwith
- 轴线:
- 垂直(时间)刻度为~1秒(2**20微秒)
- 横轴显示每种情况下的URL总数:N=1、10、100、1000、10000、100000和1000000(一百万)
- 频密键
最多N=100000
是最快的(对于一百万个URL,时间是 主要由trie施工时间决定) 在找到的匹配项中查找最长的匹配项所花费的时间最多。因此,所有函数的行为都与预期类似datrie
startswith
-时间性能与密钥类型无关
trie
和pytrie
的行为相似
无trie构建时间的性能
-最快、最合理的内存消耗datrie
在这里更为不利,因为其他方法不会因构建trie所需的时间而受到惩罚startswith
,datrie
,pytrie
-对于稀有/不存在的密钥,几乎是O(1)(恒定时间)trie
这将返回一个搜索索引,该索引不应匹配任何内容。很好,它没有检查零长度匹配。我没有时间润色它。非常感谢你的回复,但我不是在寻找正则表达式类的解决方案,因为它不能随着不同URL数量的增加而扩展。我正在寻找的是基于Trie的最长前缀匹配解决方案,其中字符串是URL。非常感谢您的回复,但我不寻找正则表达式类型的解决方案,因为它不能随着不同URL数量的增加而扩展。我正在寻找的是基于Trie的最长前缀匹配解决方案,其中字符串是URL。可能
return'
在这里更合适,而不是raiseexception
@Amit fair。您如何存储URL列表?如果您在数据库中对它们进行索引,那么URL可能会提供一个简单而高效的解决方案@J.F.Sebastian好的,谢谢。@Stephen我没有将它们存储在数据库中,我有一个URL的列表,其中有一个唯一的随机数与之关联,现在我想将其存储在trie中,然后匹配一个新的URL并找出最接近的前缀匹配。这对您有帮助吗?帮助(str.startswith)如果搜索http://www.google
?是否支持像“ww.google.com/d”这样的搜索?您希望它匹配整个搜索字符串,还是匹配搜索字符串中可能最长的前缀?换句话说,搜索“”会有效(返回1或2)还是失败?到目前为止,这是一个比我更好的解决方案。遗憾的是,标准python库中没有树实现。后缀树可以序列化吗?或者生成它们的速度太快,以至于无法
from SuffixTree import SubstringDict
substr_dict = SubstringDict()
for url in URLS: # urls must be ascii (valid urls are)
assert '\n' not in url
substr_dict['\n'+url] = url #NOTE: assume that '\n' can't be in a url
def longest_match(url_prefix, _substr_dict=substr_dict):
matches = _substr_dict['\n'+url_prefix]
return max(matches, key=len) if matches else ''
pip install SuffixTree -f https://hkn.eecs.berkeley.edu/~dyoo/python/suffix_trees
| function | memory, | ratio |
| | GiB | |
|-------------+---------+-------|
| suffix_tree | 0.853 | 1.0 |
| pytrie | 3.383 | 4.0 |
| trie | 3.803 | 4.5 |
| datrie | 0.194 | 0.2 |
| startswith | 0.069 | 0.1 |
#+TBLFM: $3=$2/@3$2;%.1f
| Fitting polynom | Function |
|------------------------------+-------------------|
| 0.15 log2(N) + 1.583 | log2(N) |
| 0.30 log2(N) + 3.167 | log2(N)*log2(N) |
| 0.50 log2(N) + 1.111e-15 | sqrt(N) |
| 0.80 log2(N) + 7.943e-16 | N**0.8 |
| 1.00 log2(N) + 2.223e-15 | N |
| 2.00 log2(N) + 4.446e-15 | N*N |