全文搜索与机器学习领域的大多数其他问题不同,是网络程序员在日常工作中经常遇到的问题。客户端可能会要求你在某处提供一个搜索框,然后你会写一个类似WHEREtitleLIKE%:query%的SQL语句来实现搜索功能。起初,这很好,直到有一天,一位客户来找你说:“搜索有误!”当然,搜索实际上并没有“出错”,只是搜索的结果并不是客户想要的。普通用户不知道如何进行精确匹配,因此得到的搜索结果质量很差。为了解决这个问题,您决定使用全文搜索。经过一段时间的繁琐学习,你开启了MySQL的FULLTEXT索引,使用了更高级的查询语法,比如“MATCH...AGAINST”。好了,问题解决了,撒花就完事了!当数据库较小时没有问题。但是当你的数据越来越多的时候,你会发现你的数据库越来越慢。MySQL不是一个非常有用的全文搜索工具。因此,您决定使用ElasticSearch,重构您的代码,并部署一个由Lucene提供支持的全文搜索集群。你会发现它工作得很好,又快又准。此时你不禁会想:Lucene为什么这么牛逼?这篇文章(主要介绍TF-IDF、OkapiBM-25和generalrelevancescore)和下一篇文章(主要介绍索引)将介绍全文搜索背后的基本概念。相关性对于每个搜索查询,我们可以轻松地为每个文档定义一个“相关性分数”。当用户搜索时,我们可以按相关性分数而不是文档时间排序。这样,最相关的文档就会排在第一位,不管它是在多久之前创建的(当然,有时候也和文档的创建时间有关)。有很多很多方法可以计算单词之间的相关性,但我们将从最简单的、基于统计的方法开始。这种方法不需要了解语言本身,而是根据文档中唯一词的流行程度,通过计算词的使用、匹配和加权来确定“相关性分数”。算法不关心这个词是名词还是动词,也不关心这个词的意思。它唯一关心的是哪些是常见词,哪些是罕见词。如果一个搜索查询同时包含常用词和稀有词,你最好给包含稀有词的文档更高的分数,并降低常用词的权重。该算法称为OkapiBM25。它包含两个基本概念词频(termfrequency)简称词频(“TF”)和逆文档频率(inversedocumentfrequency)简称(“IDF”)。将它们放在一起称为“TF-IDF”,这是一个术语在文档中的重要性的统计度量。TF-IDF词频(TermFrequency),简称“TF”,是一个非常简单的指标:特定词条在文档中出现的次数。您可以将该值除以文档中的单词总数以获得分数。比如文档中有100个词,'the'这个词出现了8次,那么'the'的TF就是8或者8/100或者8%(取决于你想怎么表示)。逆文档频率(InverseDocumentFrequency),简称“IDF”,稍微复杂一点:一个词越稀有,其值就越高。它是通过将文档总数除以包含该术语的文档数,然后取所得商的对数得到的。这个词越稀有,“IDF”就越高。如果将这两个数字相乘(TF*IDF),就会得到文档中某个术语的权重。“权重”的定义是:这个词有多罕见,它在文档中出现的频率是多少?您可以将此概念用于文档的搜索查询。对于查询中的每个关键字,计算它们的TF-IDF分数并将它们相加。得分最高的文档是与查询语句匹配的文档。OkapiBM25上面的算法是一个可用的算法,但不是很准确。它提供了一个基于统计的相关评分算法,我们可以进一步改进该算法。OkapiBM25被认为是迄今为止最先进的排名算法之一(因此被称为ElasticSearch)。OkapiBM25在TF-IDF的基础上增加了两个可调参数,k1和b,分别代表“词频饱和度”和“字段长度规范”。这到底是什么?为了直观地理解“词频饱和度”,想象一下两篇讨论棒球的文章,长度差不多。另外,我们假设所有文档(除了这两个)都没有太多与棒球相关的内容,所以“棒球”这个词会有很高的IDF——这是极其重要和重要的。这两篇文章都是关于棒球的,并且都用了相当大的篇幅,但其中一篇使用“棒球”这个词的次数比另一篇多。那么在这种情况下,一篇文章与另一篇文章的分数相差很大是真的吗?由于两份文件都详细讨论了棒球,因此“棒球”一词出现40次还是80次都会产生同样的区别。其实30应该是上限!这就是“termfrequencysaturation”。原来的TF-IDF算法没有饱和的概念,所以一个“baseball”出现80次的文档是出现40次的文档的两倍。有时候,这就是我们想要的,但是Sometimes我们不要这个。另外,OkapiBM25还有一个k1参数,用来调节饱和度变化的速率,k1参数的取值一般在1.2到2.0之间,值越低速度越快saturationprocess.(意思是上面两个文档有相同的分数,因为它们都包含很多单词“baseball”)Field-lengthnormalization将文档的长度减少到所有文档的平均长度上。这个很有用对于单字段的集合(比如我们的),可以统一不同长度的文档在同一个比较标准上。对于双字段的集合(比如“title”和“body”)更是有用的意思,它也可以将title和body字段统一为相同的比较健康)状况。字段长度缩减用b表示,它的值在0到1之间,1表示全部缩减,0表示不缩减Reduction。在OkapiBM25维基百科中,可以了解Okapi算法的公式。既然你知道了公式中的每一项是什么,它一定很容易理解。那么公式就不说了,直接上代码:BM25.Tokenize=function(text){text=text.toLowerCase.replace(/\W/g,'').replace(/\s+/g,'').trim.split('').map(function(a){returnstemmer(a);});//FilteroutstopStemsvarout=;for(vari=0,len=text.length;i
