我正在编写一个预测性搜索,为了服务器性能要求(全部被缓存),必须在客户端浏览器上运行。这些项目是电视节目和电影,并由标题,演员和导演名称匹配。执行搜索后,它会返回一个匹配项列表,其中包含每个结果的两个值:
匹配单词的数量(n):用户可以输入4个单词,但只有2个单词与一个项目匹配。越多越好。
Levenshtein Edit Distance加法(ld)。用户可以键入3个单词,但其中2个单词与索引的单词有差错或其他小差异。我使用编辑距离来查找最近的索引字。所有Levenshtein距离的添加都作为接近指示符返回。越少越好。
要求
客户端。没有Sphinx,Lucene或任何其他服务器端解决方案。
速度超过准确性。该算法在每次击键时运行,我们不想让用户厌烦。保持大O 不是那么大。
非递归的。每个项目相关性的计算不应该依赖于其他项目计算。我不想击败谷歌,只提供一小部分的最佳结果。
有界形式0到1,0到100或类似的东西。不是必需品,但能够显示“相关百分比”是一个加号。
关于实施的想法。我正在寻找一种比特定实现更好的算法/公式。
我的aproach
基于指数衰减(如放射性半衰期分解),我制定了这个公式。
其中:
T
是用户提供的字数。n
是匹配单词的数量。ld
是此匹配词的Levenshtein距离加法。在伪代码中。
function lambda(n, ld) {
lambda = (n/T) * e^(-ld * 1/n);
return lambda;
}
一点解释:
-ld * 1/n
是相关性度量核心。如果ld
较低且n
较大,则接近于零(-0侧)并表示此结果更具相关性。
n/T
是准确率。匹配单词与所有单词。通过考虑总用户输入来优化先前的相关性。
指数函数,对于负数幂,将结果绑定在0和1之间。
最后,问题
我想要的不是基于具有额外编辑距离计算的this response来优化搜索算法,而是通过将相关值设置为每个来提高返回元素的相关性排序。如果需要n
和ld
以外的任何参数并且可以轻松计算,则可以使用。在我的解决方案中,我添加了T
,即用户提供的字数。
答案 0 :(得分:7)
一般情况下,我认为您必须简化您的公式。事实上,像tf-idf这样的大多数基本相关公式非常简单,只使用生产或参数的一部分,可能还有“强化”或“弱化”功能。例如,tf-idf
只是术语频率的乘法和对数逆文档频率的“弱化”。首先,我会快速分析您的公式,然后提出一些建议。
让我们改写你的公式:
首先,请注意,n/T
未规范化:可能会有更多结果(n
),然后搜索字词(T
)。考虑这样的例子:用户输入查询“John Malkovich”,并且数据库中有电影Being John Malkovich。用户输入了2个单词,即T = 2
,但电影在电影片名和演员表中都有这些术语,所以n = 2 * 2 = 4
。鉴于此,最终的相关性将更加严重。缺乏正常化本身并不是问题,但在实践中,它可能会在未来导致许多错误。
现在让我们看一下公式的第二部分 - 1 / e^(ld/n)
。我们将ld/n
表示为x
。在这种情况下,公式的第二部分将如下所示:
因此,对于x
的高值,它会削弱最终的相关性。虽然我不明白为什么它必须是指数级的,但它仍然有意义。但是x
不是自变量,它本身就是2个变量的函数:x = x(ld, n)
。此外,ld
也是一个函数:ld = ld(MAX_LD, T)
,因此x
取决于3个不同的自变量/参数:x = x(MAX_LD, T, n)
。在这种情况下,很难预测所有可能情况下x
的行为(以及最终相关性)。
<强> 1。简化x()。如果您希望公式的第二部分仅跟踪Levenshtein距离,则仅依赖于此距离,而不是所有3个独立变量。例如,您的公式可能如下所示:
甚至:
其中distance
是实际的Levenshtein编辑距离,而不是T
和MAX_LD
的函数。
<强> 2。使用词干。我知道,我知道,你说过,你不能使用服务器端编程。但是你确定它无法在客户端执行吗? Steming似乎比它容易得多。大多数词干只是截断后缀和结尾,如“-s”,“-ing”,“-ment”等。这不是理想的,但我相信它会给出更好的结果,然后是Levenshtein距离。这里唯一强大的限制是:词干必须同时用于 - 索引和搜索。
有关更精确的词干算法,请参阅Lucene sources中的PorterStemmer类。
第3。使用逆记录频率。使用查询“John Malkovich”调用示例。可能有很多电影用“约翰”这个词,但只有几部用“马尔科维奇”。很自然地假设,第二项必须在搜索结果中具有更大的权重,然后是第一项。 tf-idf
在其idf
(逆文档频率)部分中涉及此事实。你可以通过计算逆记录频率来做同样的事情:
irf = number-of-all-found-records / number-of-records-with-current-term
并添加相关公式第三部分:
当然,请记住:在真实数据上测试之前,没有公式是好的。