开发者学堂课程【Lucene知识精讲与实战(下):相关度排序】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/701/detail/12356
相关度排序
内容介绍:
一、什么是相关度排序
二、如何打分
三、什么是词的权重
四、怎么影响相关度排序
五、人为影响相关度排序
一、什么是相关度排序
1、Lucene 对查询关键字和索引文档的相关度进行打分,得分高的就排在前边。
2、在查询时查询出的数据,根据关键词查询,谁在前谁在后,应该有顺序,Lucene根据默认的相关度排序算法进行计算,跟关键词越相关的内容应该排在前面,跟关键词不相关的内容排在后面,一般看都是看前几页,看完之后往后翻,就会发现跟搜索的关键词不相关,就不再看了。
二、如何打分
Lucene 是在用户进行检索时实时根据搜索的关键字计算出来的,分两步:
1.计算出词 (Term) 的权重。
2.根据词的权重值,计算文档相关度得分。
根据tf和df算相关度的分数,分数越高越往前,分数越低越往后。
三、什么是词的权重
明确索引的最小单位是一个 Term (索引词典中的一 个词),搜索也是要从Term中搜索,再根据 Term 找到文档, Term 对文档的重要性称为权重,影响 Term 权重有两个因素:
1、Term Frequency (tf):
指此Term在此文档中出现了多少次。tf 越大说明越重要。词 (Term) 在 文档中出现的次数越多,说明此词 (Term) 对该文档越重要,如"Lucene"这个词, 在文档中出现的次数很多,说明该文档主要就是讲Lucene技术的。影响分值。
2、Document Frequency (df):
一个词在一个文档中出现,词在所有的文档中都出现。指有多少文档包含次Term。df 越大说明越不重要。比如,在一篇英语文档中,this出现的次数更多, 就说明越重要吗?不是的,有越多的文档包含此词 (Term) ,说明此词 (Term) 太普通,不足以区分这些文档,因而重要性越低。
3、比如在中文词典中“的”,基本在每篇文章中都会出现,“是”也会在每个文档中出现,这两个词没有放到中文词典中,在分词器分词时没有去掉,没有作用,不会影响排序。比如“权重”在文档中出现,而且出现好多次,说明这个文档跟这个词比较相关,所以分数会越高。不需要影响,Lucene底层会自动的进行相关度算法计算,在搜索时哪篇文档相关哪篇文档不相关,都会进行默认的排序。像一些搜索引擎,百度等,搜索引擎需要做广告,在做广告时给钱了,就会把做广告的排在前面,所以需要人工进行影响。
四、怎么影响相关度排序
boost 是一个加权值(默认加权值为1.0f),它可以影响权重的计算。
1、在索引时对某个文档中的field设置加权值高,在搜索时匹配到这个文档就可能排在前边。
2、在搜索时对某个域进行加权,在进行组合域查询时,匹配到加权值高的域最后计算的相关度得分就高。
设置boost是给域(field) 或者 Document 设置的。
五、人为影响相关度排序
1、查询的时候,通过设置查询域的权重,可以人为影响查询结果。
2、在 Lucene 早期版本中可以影响文档,也可以影响域,通过域或某一个文档设置权重,设置的越高越往前排,设置越低越往后排,在目前比较新的7.7.2中可以影响哪一个域比较重要,给它的值设置的域大一些,设置的大一些对于域比较关键,会影响它排序的顺序。搜索时顺序如何影响它?
3、找到测试案例 test-testsearch,
/**
*测试相关度排序
*@throws Exception
*/
4、fsdirectory直接从文件系统中查询,更改查询语法,只是通过queryparser默认搜索域进行查询,在查询时会出现查询一个关键字通过多个域进行查询,比如名称域,分类域,品牌域三个域中有包含手机关键字都要查出来。
//需求:不管是名称域还是品牌域或者是分类域有关于手机关键字的查询出来
new MultiFieldQueryParser();
在查询中多个域查询有multfiedqueryparser查询接口,有两个参数,有三个参数。有两个参数的第一个查询的是域名,第二个存放的是使用的分词器,域名是字符串数组,原因是从多个域中进行查询。
//查询的多个域名
String[] fields= {"name" ," categoryName" ," brandName"} ;
//从多个查询的关键字
MultiFieldQueryParser multiFiel dQueryParser = new MultiF
ieldQueryParser(fields, analyzer);
//设置查询的关键词
Query query . multiFieldQueryParser .parse("
手机
");
从多个域查询,默认 Lucene 的排序为诺基亚(NbKIA) 105手机 老人机 学生机 老人手机 经典 新款黑色,根据诺基亚手机查询。人为改变顺序,设置 boost,在文档中可以设置 map 里面设置权重,权重值,categorname 权重的域名,把 map 作为 multfiedqueryparser 第三个参数传进去,会直接影响排序顺序,相当于人工影响打分的分数,由于影响打分的分数,排序是按照算出分值进行排序,也影响正常的排序的顺序,把分类名的权重设置的非常大,是 float 类型,值没有最大只有更大,设置的大一些会影响它排序的顺序。
//设置影响排序的权重,这里设置域的权重,f代表float类型
Mapboots=new HashMap<>( ) ;
boots . put( " categoryName"
,
10000000f) ;
把它作为第三个参数传进来
//从多个域查询对象
MultiFieldQueryParser multiFieldQueryParser = new MultiFieldQueryParser(fields, analyzer, boots);
搜索出23786个结果,排第一个的尾号是402,诺基亚手机。
再查询还是402手机,顺序并没有进行影响,原因可能是切割词时切割成手和机两个词,在创建索引时索引库通过分类的域名,使用的是stringfield不分词,影响不了它,查询时也不要给它分词,手机在中文中就是一个词,不能分成手和机,在创建索引时换成中文分词器,ik有语法分析功能。
Analyzer analyzer = new IKAnaiyzer();
搜索时也选择ik进行搜索。
Analyzer analyzer . new IKAnalyzer);
先把boots去掉。
MultiFieldQueryParser multiFieldQueryParser = new MultiFieldQueryParser(fields, analyzer);
重新创建索引重新查询,看原来查询出的结果是什么。
///boots. put( "categoryName " , 10000000000f);
优化完是什么样,清空索引库,在创建索引时分词器用ik,中文分词器进行分词,搜索时对于分词,查询手机,相关度都已经被的去掉,去掉人为的影响相关度排序,去掉之后查询出的结果不一样,尾号变为99300苹果手机,分类是手机,假如影响相关度排序,把参数boots加上。
//设置影响排序的权重,这里设置域的权重
Map
,
Float> boots = new HashMap<>();
boots . put("categoryName"
,
10000000000f);
//从多个域查询对象
MultiFieldQueryParser multiFieldQueryParser = new MultiFieldQueryParser(fields, analyzer, boots);
查询尾号为300,再查询把分类名的权重加大,主要根据分类查询结果,会很大程度上影响排序的顺序,现在查询尾号为145,结果不一样,排序跟分词器有影响,跟设置域的权重也有影响,这是对于 Lucene7.7.2 版本中相关度排序的理解。