背景
策略上需要通过自定义expression动态调整文本相似度算法, 而文本相似度算法对每个匹配(match query)都调用一次, 假设一个request中有10个match query, 每个match query平均匹配10w个文档(我们假设的极端些), 那么一个request会调用打分公式100w次.
可见, 我们需要一款super fast的expression evaluator.
实验
给定bm25公式: expression=idf_boost_(k 1)_tf/(tf k_((1-b) b*dl/avgdl))
. 和一组固定的参数数值.
重复执行100w次, 对比各开源库的耗时.
构建(编译)和执行前都有预热.
实验结果
名称 | 构建(编译)时间(ms) | 执行时间(ms) | github链接 |
---|---|---|---|
java原生代码 | 3 | ||
exp4j | 0.04ms | 298 | https://github.com/fasseg/exp4j |
paralithic | 0.22ms | 3 | https://github.com/PolyhedralDev/Paralithic |
parsii | 0.06 | 79 | https://github.com/scireum/parsii |
结论
经过测试, 决定选用paralithic.
为什么paralithic和其他开源库会有如此大的性能差异呢? 因为这几个库中, 只有paralithic采用了动态字节码生成技术(通过ASM). 类似的技术也被用在ES的painless表达式执行.
对于上面的bm25公式, paralithic会动态编译生成下面的java class, 因此拥有接近原生java的执行速度.
当然也因此导致了paralithic构建时间最慢, 不过好在我们的文本相关性公式虽然可以动态调整, 但从算法角度, 肯定是可枚举的, 因此可以把构建(编译)结果缓存起来.