我有一堆短语列表。因为这是一个相当长的列表,我还有一个文本框,用户可以键入搜索栏。截至目前,过滤掉了与搜索栏中的字母不完全包含的术语。但是,我想让它列出一些关于这个词可能是什么的建议。
注意:我不是在找"你的意思是......"或拼写检查算法,如here或here或here(虽然来自第一个链接的this image似乎很好);我想要一种能够为不完整的单词或短语建议最佳匹配的算法;例如单词"bat"
应该是单词"battery"
的更好匹配,而不是单词"car"
。
使用Google的方法返回最常见的以(大约)相同字母开头的字符串也是不切实际的,因为据我所知,列表中的每个元素都是和其他任何一样普通。
另外,我想在Java(8)中这样做;但是,其他语言答案是可以接受的,只要它们不使用Java没有等效的内置函数。如果有用的话,我写了一个Levenshtein距离的修改版本(下面),它用星号填充搜索字符串,表示任何字符。"这适用于单个单词,例如"mud"
与"muddy"
完全匹配,但在考虑人们可能会使用"car"
搜索"race car"
时,/**
* <ul>
* <b><i>searchDistance</i></b><br>
* <br>
* <code> public static int searchDistance(String key, String match)</code><br>
* <br>
* Gets the Levenshtein distance between <code>key</code> and <code>match</code>. <br>
* If <code>useAsterisk</code> is true, then the follwing applies: If <code>key</code> is shorter than <code>match</code>, the asterisk <code>'*'</code> is appended to it until the lengths are equal. Asterisks can be used in <code>key</code> to signify 'any character.'
* @param key - The text to search for
* @param match - The text to compare <code>key</code> against
* @param useAsterisk - Whether or not to use asterisks for the purpose described above
* @return the Levenshtein distance between <code>key</code> and <code>match</code>.
* </ul>
*/
public static int searchDistance(String key, String match, boolean useAsterisk) {
while (key.length() < match.length()) {
key = key + "*";
}
int[][] matrix = new int[key.length() + 1][match.length() + 1];
for (int i = 0; i < matrix.length; i++) {
matrix[i][0] = i;
}
for (int i = 0; i < matrix[0].length; i++) {
matrix[0][i] = i;
}
for (int a = 1; a < matrix.length; a++) {
for (int b = 1; b < matrix[0].length; b++) {
matrix[a][b] = Math.min(Math.min(matrix[a - 1][b] + 1, matrix[a][b - 1] + 1), matrix[a - 1][b - 1] + (key.charAt(a - 1) == match.charAt(b - 1) || key.charAt(a - 1) == '*' ? 0 : 1));
}
}
return matrix[matrix.length - 1][matrix[0].length - 1];
}
是不够的。
<select>
TL; DR:有没有一种方法可以提供搜索条件的完成建议?
提前致谢!
答案 0 :(得分:1)
试着看看K Shingles方法在:http://infolab.stanford.edu/~ullman/mmds/book.pdf:第77页
它可能会给出一些阻碍这种模糊搜索系统的想法
答案 1 :(得分:1)
总有一种简单的蛮力方法。即使有相当多的短语,它也可以很好地运作。
想象一下,你有一百万个短语列表。用户输入字母'c'。您搜索包含字母“c”的所有短语的列表,并显示它们。你也保留了这个结果。
然后用户输入'a'。现在,您在上一次搜索返回的字符串列表中搜索字符串“ca”。所以你已经把你的搜索从所有短语切换到你知道包含字母'c'的那些短语。考虑到大约37%的英语单词包含字母'c'(参见http://phrontistery.info/ihlstats.html),你已经将你的名单减少了近三分之二。
无论如何,您现在有一个包含字母“ca”的短语列表。与所有短语列表相比,此列表将相当小。当用户键入字符时,您可以继续优化列表。
如果对整个列表的初始搜索花费的时间太长,您可以通过创建一个字母索引,并使用包含该字母的单词列表来轻松优化它。因此,例如,'c'的条目将包含“赛车”,“汽车”,“猫”,“主雕刻师”等。因此,不需要搜索来获取初始列表。
使用字典方法的另一个好处是,您可以预处理每个字母的列表,以便以字母开头的单词位于列表的前面。这很好,因为大多数时候,当有人在搜索时,他正在寻找一个以他输入的第一个字母开头的单词或短语。但您可以根据受欢迎程度或任何其他标准轻松安排。
我多次使用过这种方法,而且效果很好。它实现起来很简单,并且通常执行速度足够快而无需任何优化。我上面提到的字典优化对于除了一些简单的暴力方法不起作用的情况就足够了,有一次我需要两个字典:一个用于第一个字符,一个用于字母对。
即使这不是最终解决方案,但它很有用,因为它很容易证明是正确的,并且可以测试其他更复杂的算法。