首先推测 checkExistRule(List<String[]> keywordRule, String text) 的实现有问题,OP 的实现只会用到第一条规则。
其次 String 的 contains 匹配是数组下标查找,也是一层循环,效率不高。
建议是先分词,得到 哈希数组,然后再比较,示例代码如下:
public static boolean checkExistRuleV2(List<Set<String>> keywordRule, Set<String> textSet) {
return
keywordRule.stream().anyMatch(textSet::containsAll);
}
Benchmark 压测结果如下:循环 10000 次的时间,从 13 ms 降低到 0.5 ms
Benchmark Mode Cnt Score Error Units
Print1024Test.checkExistRule avgt 6 13.877 ± 0.148 ms/op
Print1024Test.checkExistRuleV2 avgt 6 0.528 ± 0.035 ms/op
单元测试代码
package org.corning.v2ex.year2024;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.junit.jupiter.api.Test;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class Print1024Test {
public static List<String[]> keywordRule = Lists.newArrayList(
new String[]{"鼎赛龙", "男士春夏", "D-FINING", "深灰色", "锥形牛仔裤"},
new String[]{"DIESEL", "男士春夏", "DFINING", "深灰色", "锥形牛仔裤"}
);
public static String text = "#DIESEL 大牌好友# @宋雨琦_G-I-DLE 演绎#DIESEL2023 秋冬系列# 牛仔坠饰 D-VINA 包袋。渐变丹宁渲染不羁格调,另类包型注解无畏想象";
public static List<Set<String>> keywordRuleSet =
keywordRule.stream()
.map(Sets::newHashSet)
.collect(Collectors.toList());
// 这里可能需要更好的分词手法,trim / 去掉逗号等
public static Set<String> textSet =
Arrays.stream(text.split(" ")).collect(Collectors.toSet());
@
Test public void runBenchmarks() throws Exception {
Options options = new OptionsBuilder()
.include(this.getClass().getName() + ".*")
.mode(Mode.AverageTime)
.warmupTime(TimeValue.seconds(1))
.warmupIterations(6)
.threads(1)
.measurementIterations(6)
.forks(1)
.shouldFailOnError(true)
.shouldDoGC(true)
.build();
new Runner(options).run();
}
@
Benchmark @
Test @
OutputTimeUnit(TimeUnit.MILLISECONDS)
public void checkExistRule() {
for (int i = 0; i < 10000; i++) {
Print1024.checkExistRule(keywordRule, text);
}
}
@
Benchmark @
Test @
OutputTimeUnit(TimeUnit.MILLISECONDS)
public void checkExistRuleV2() {
for (int i = 0; i < 10000; i++) {
Print1024.checkExistRuleV2(keywordRuleSet, textSet);
}
}
}