java - 使用部分单词匹配而不是余弦相似度在java中搜索2个字符串的相似度
问题描述
嗨,我想通过其他字符串中出现的部分单词来比较 2 个字符串。例如:我有 4 个字符串:
A) "white snow ball"
B) "super exciting"
C) "white image superdupercold"
D) "cold"
并且用户通过此字符串“ super cold white snow
”搜索结果应按以下顺序返回:
C, A, D, B
因为 B 只有一个匹配“super”,总共 2 个单词(相似度 = 50%),而 D 匹配一个“cold”,总共 1 个单词(相似度 = 100%)。A 有 2 个匹配“white”和“snow”,C 有 3 个匹配但是,如果我使用余弦相似度,它的排名会有所不同:
另一个例子:如果用户通过这个字符串“super”搜索,那么结果应该按这个顺序返回:B,C
我认为它可以通过正则表达式和字符串拆分来解决。有没有什么好的和干净的方式来用 java 写它?
解决方案
haystack.split("\\s+")
对于每个搜索字符串,使用( \\s+
is regexp-ese for '字符串由空格分隔')将其拆分为单词。
然后,要获得“分数”,您需要 2 个数字:匹配的单词数,以及总共有多少单词。您首先按降序排序,最后按升序排序,这会得到您想要的行为。
String[] needle = "super cold white snow".split("\\s+");
String[] haystack = "white image superdupercold".split("\\s+");
int matchedWords = 0, totalWords = haystack.length;
for (String n : needle) {
boolean found = false;
for (String hay : haystack) {
if (hay.contains(n)) {
found = true;
break;
}
}
if (found) matchedWords++;
}
对于每根针,您现在最终得到 2 个分数:matchedWords 和 totalWords。
对于给定的任何 2 个这样的得分对,获胜者是匹配词数较高的那个;totalWords 用作决胜局,它反向工作(较低的 totalWords 获胜)。
有多种方法可以尝试表示这一点。一个简单的技巧是将所有这些“编码”为一个长值:
private static final long MULTIPLIER = 0x100000000L;
long score = MULTIPLIER * matchedWords + (Integer.MAX_VALUE - totalWords);
现在得分较高的针是最好的答案。
另一种选择是创建一个代表针的类以及两个分数,将所有结果放在一个列表中,然后对列表进行排序:
@Value
class Result { String needle; int words, total; }
list.sort(
Comparator.comparing(Result::getWords).reversed().
thenComparing(Comparator.comparing(Result::getTotal));
list.stream().map(Result::getNeedle).forEach(System.out::println);
注意:如果目标是非常有效地做到这一点,那么您可以快速处理几十万个大海捞针,答案在于诸如 postgres tsvectors 之类的 wordsearch 解决方案或Lucene之类的库。
这些片段中使用的类型:
- 龙目岛的
@Value
java.util.Comparator
推荐阅读
- powershell - PowerShell - 复制文件 X 次并更改其名称
- python - Python 转 C# 多维数组
- python - 根据数据帧中的子字符串提取字符串的一部分 - python
- animation - 如何在 Elm-UI 中鼠标悬停动画?
- typescript - 打字稿根据字符串区分对象中的联合
- c# - 我无法到达面板上的标签
- ruby-on-rails - 使用 ActiveStorage 变体会提高性能吗?
- javascript - 我们如何动态地(通过用户)在 mongoDB 中添加集合?
- python - 如何在 python 中将我的变量与另一个变量附加(+=)之前添加新行?
- intellij-idea - IntelliJIDEA 向我显示“从 waitForDisplayed 返回的承诺被忽略”,即使我使用了 TestRunner 模式的 @wdio/sync 包