语境
在解析 Web 访问日志时,需要将机器人与人类用户代理分开。
我手动构建了它们的列表,提取了类似 bot 的模式(例如包含bot)。然后我有一个模式列表(大约 300 项大),我实时验证传入的访问日志。随着时间的推移,这已经成为一个相当大的瓶颈,因为我的(低效的)算法会寻找任何模式;即使我们忽略了意味着 DoS 漏洞的性能下降。
代码(Java)
String userAgent;
List<Pattern> botPatterns;
for (Pattern botPattern : botPatterns)
{
if (botPattern.matcher(userAgent).find())
{
return true;
}
}
return false;
已经探索的答案
使用 WURFL
这可能是一个简单的解决方案,但结果有时不准确。现在想避免使用内置解决方案。
使用用户代理缓存
通过将用户代理字符串存储在哈希图中,可以缓存结果。然而,即使这提高了性能,这也增加了使用随机生成的用户代理字符串进行简单 DoS 攻击的脆弱性。
问题
是否有一种有效的算法可以将大量 (N) 字符串与固定数量的正则表达式模式 (m) 进行匹配?
编辑:基准答案
我使用真实数据以及随机生成的用户代理字符串对@stemm 的答案进行了基准测试。我在 10 秒内运行了测试,并对计算时间进行了平均。缓存是一个大小为 5000 的简单 LFU ehcache
这是我的结果:
模式循环
没有缓存
真实数据:101us
随机数据:193us
带缓存
真实数据:4us
随机数据:203us
单一模式
没有缓存
真实数据:100us
随机数据:160us
带缓存
真实数据:3us
随机数据:154us
结论
- 对于现实生活中的情况,缓存是最有效的解决方案。
- 与循环模式相比,具有单一模式可提供 25% 的增益。
- 缓存不像我想象的那样容易受到 DoS 攻击。
谢谢大家的回答和评论。