- 什么是相关度排名
直观理解搜索结果精准由高到低
如:要查询 苍老师、tony、火锅有关的新闻:
含有三个关键字(相关度最高)的新闻排前面,含两个关键字(相关度次之)排次之,含一个关键字 的排次次之。
当然,这是由一个算法完成的。
- 如何设计相关性模型
利用出现次数来建立模型
规则1: 统计出现次数,根据次数从高到低排
{{1,5},{5,3},{12,1},{8,1}}:文章1出现5次,文章5出现3次,文章12出现1次,文章8出现1次。问题:标题中出现苍老师,与新闻的内容中出现苍老师,哪个是专门写苍老师的相关度高些?
规则2:加入权重,标题权重10,内容权重1,计算权重得分,按高-低排序
{{1,23},{12,10},{5,3},{8,1}},总结:利用出现次数来建立模型这个相关性模型很简单。有时排序会不是很准确。
复杂的相关性计算模型有:
TF/IDF和字段长度准则(长度越长,相关性越低),即检索词频率【检索词在该字段出现的频率】/反向文档频率【检索词在索引中出现的频率】,具体参参阅es-search
向量空间模型
贝叶斯概率模型,如:BM25
3. lucene相关度排序
官方介绍,在Lucene 7.4中,我们打分的对象是文档。文档是字段的集合。每个字段都有关于如何创建和存储 (tokenized, stored)的语义。重要的是要注意,Lucene评分在Fields上工作,然后组合结果返回文档。这是很重要的,因为两个文档具有相同的内容,但是由于长度规范化,一个文档在两个字段中具有内容,而另一个文档在一个字段中具有内容,所以对于相同的查询,可能返回不同的分数。lucene 为查询出来的结果(document)都打一个分,得分越高,排列的顺序越靠前,当然,我们也可以自己去干预。
相关度得分
相关度得分是在查询时根据查询条件实进计算出来的;
如果索引库数据不变,查询条件不变,查出的文档得分也不变;
注意事项
排序我们可以通过设置这个权重值来影响他的得分;
得分跟命中的次数有关系;
这个得分跟文档出现的搜索关键字的次数或者位置有关系…
提高分数
Lucene允许通过包装 BoostQuery来影响查询的各个部分的得分贡献,也就是通过设置boost值。
改变得分-相似性
- Boost
上面提到过Boost,它影响着索引阶段和搜索阶段。在索引阶段设定文档的Document.setBoost和域的Field.setBoost值,这些值是在索引阶段就写入索引文件的,存储在标准化因子(.nrm)文件中,一旦设定,除非删除此文档,否则无法改变。如果不进行设定,则Document Boost和Field Boost默认为1。在6.4版本中已经不再支持了。
@Test
public void go_explain() throws IOException {
Directory directory = new RAMDirectory();
IndexWriterConfig config = new IndexWriterConfig();
config.setUseCompoundFile(true);
IndexWriter writer = new IndexWriter(directory, config);
String feildName="title";
Field f1 = new TextField(feildName, "bc bc", Field.Store.YES);
Field f2 = new TextField(feildName, "ab bc", Field.Store.YES);
Field f3 = new TextField(feildName, "ab bc cd", Field.Store.YES);
Field f4 = new TextField(feildName, "abc", Field.Store.YES);
Document doc1 = new Document();
Document doc2 = new Document();
Document doc3 = new Document();
Document doc4 = new Document();
doc1.add(f1);
doc2.add(f2);
doc3.add(f3);
doc4.add(f4);
writer.addDocument(doc1);
writer.addDocument(doc2);
writer.addDocument(doc3);
writer.addDocument(doc4);
writer.close();
IndexReader reader = DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
searcher.setSimilarity(new ClassicSimilarity());//切换算法
TermQuery q = new TermQuery(new Term(feildName, "bc"));
//Weight weight = q.createWeight(searcher, true, 3); //不要再这样使用,否则导致TFIDFSimilarity不生效
BoostQuery bq=new BoostQuery(q,2f);
TopDocs topDocs = searcher.search(bq, 10);
System.out.println("totalHits:" + topDocs.totalHits + ",MaxScore" + topDocs.getMaxScore());
for (int i = 0; i < topDocs.scoreDocs.length; i++) {
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
Document doc = searcher.doc(scoreDoc.doc);
System.out.print(doc.get(feildName));
System.out.print(" ");
System.out.print(scoreDoc.score);
System.out.print(" ");
System.out.println(searcher.explain(bq, i));
}
reader.close();
directory.close();
}