我们有个小系统,要load几十亿域名,支持字符串查询/正则模式匹配等等各种查找方式,以期找到满足模式的域名进行后续分析。
普通的正则过程会比较慢,尤其正则越复杂,性能下降会很严重。当前load数据有50亿到100亿之间,一个复杂正则可能需要耗费几十分钟才能跑完。
想到一个优化方法
- load数据的过程中,预先计算每个域名的组成,【0-9a-z._-】分别对应到一个bit,一个int64的整数足够
- 查询时,把正则中固定字符串提取出来,算固定字符串的组成,正则匹配之前,先看要检查的域名的对应的组成int64的位与是否能cover正则表达式的组成int64
域名的组成很少会把所有的字符都用到,对于特定的模式,能有overlap的域名只是一小部分,而上述的位与检查会非常迅速,所以可以大大提高匹配过程的效率。粗略估算,提升在5倍左右,对于正则表达式,如果能提供的固定字符串越多,匹配越快,如果完全不包含固定字符串,那就退化到和之前一样了。
问题来了,python里面 re.compile(pattern, 128)会把一个pattern对应的解析后结果展示出来,re2没有这个接口,我们得自己添加。
re2/re2.h 给 RE2 类添加
Dump方法在re2/regex.h是有的,不过没有给出实现。在re2/testing/下有类似的dump实现,不过dump出来的字符串是一坨不好看,我们修改为如下
re2/regexp.cc,添加到文件最后
这样做个小程序
main.cc
|
|
上述STR/CHR的部分就是我们关心的“一个正则中固定字符串”的部分,这里是“hello.”,将其映射到一个uint64 for pattern。
正则匹配之前,先通过一个位与运算判断上面的uint64 for pattern是否被包含与uint64 for string, 不被包含的就说明原始字符串肯定不会含有hello.对应的所有字符,也就肯定不可能被正则匹配过程命中,直接忽略掉匹配过程,加速整体匹配性能。