Elasticsearch學習筆記(十四)relevance score相關性評分的計算(1)
一、多shard場景下relevance
score不準確問題
1、問題描述:
多個shard下,如果每個shard包含指定搜索條件的document數量不均勻的情況下,會導致在某個shard上document數量少的時候,計算該指定搜索條件的document的相關性評分要虛高。導致該document比實際真正想要返回的document的評分要高。![Image[4] Image[4]](https://images2018.cnblogs.com/blog/294879/201803/294879-20180327113447266-922407310.png)
![Image[4] Image[4]](https://images2018.cnblogs.com/blog/294879/201803/294879-20180327113447266-922407310.png)
2、解決
(1)生產環境下,數據量大,盡可能實現均勻分配
數據量很大的話,其實一般情況下,在概率學的背景下,es都是在多個shard中均勻路由數據的,路由的時候根據_id,負載均衡比如說有10個document,title都包含java,一共有5個shard,那么在概率學的背景下,如果負載均衡的話,其實每個shard都應該有2個doc,title包含java如果說數據分布均勻的話,其實就沒有剛才說的那個問題了(2)測試環境下,將索引的primary shard設置為1個,number_of_shards=1,index settings如果說只有一個shard,那么當然,所有的document都在這個shard里面,就沒有這個問題了(3)測試環境下,搜索附帶search_type=dfs_query_then_fetch參數,會將local IDF取出來計算global IDF計算一個doc的相關度分數的時候,就會將所有shard對的local IDF計算一下,獲取出來,在本地進行global IDF分數的計算,會將所有shard的doc作為上下文來進行計算,也能確保準確性。但是production生產環境下,不推薦這個參數,因為性能很差。
二、多字段搜索相關性評分計算(best
fields策略,most_field策略)
1、為帖子數據增加content字段
POST /forum/article/_bulk{ "update": { "_id": "1"} }{ "doc" : {"content" : "i like to write best elasticsearch article"} }{ "update": { "_id": "2"} }{ "doc" : {"content" : "i think java is the best programming language"} }{ "update": { "_id": "3"} }{ "doc" : {"content" : "i am only an elasticsearch beginner"} }{ "update": { "_id": "4"} }{ "doc" : {"content" : "elasticsearch and hadoop are all very good solution, i am a beginner"} }{ "update": { "_id": "5"} }{ "doc" : {"content" : "spark is best big data solution based on scala ,an programming language similar to java"} }
2、搜索title或content中包含java或solution的帖子下面這個就是multi-field搜索,多字段搜索
GET /forum/article/_search{"query": {"bool": {"should": [{ "match": { "title": "java solution" }},{ "match": { "content": "java solution" }}]}}}
3、結果分析
期望的是doc5,結果是doc2,doc4排在了前面計算每個document的relevance score:每個query的分數,乘以matched query數量,除以總query數量算一下doc4的分數{ "match": { "title": "java solution" }},針對doc4,是有一個分數的{ "match": { "content": "java solution" }},針對doc4,也是有一個分數的所以是兩個分數加起來,比如說,1.1 + 1.2 = 2.3matched query數量 = 2總query數量 = 22.3 * 2 / 2 = 2.3算一下doc5的分數{ "match": { "title": "java solution" }},針對doc5,是沒有分數的{ "match": { "content": "java solution" }},針對doc5,是有一個分數的所以說,只有一個query是有分數的,比如2.3matched query數量 = 1總query數量 = 22.3 * 1 / 2 = 1.15doc5的分數 = 1.15 < doc4的分數 = 2.3
4、best fields策略,dis_max
best fields策略,就是說,搜索到的結果,應該是某一個field中匹配到了盡可能多的關鍵詞,被排在前面;而不是盡可能多的field匹配到了少數的關鍵詞,排在了前面dis_max語法,直接取多個query中,分數最高的那一個query的分數即可{ "match": { "title": "java solution" }},針對doc4,是有一個分數的,1.1{ "match": { "content": "java solution" }},針對doc4,也是有一個分數的,1.2取最大分數,1.2{ "match": { "title": "java solution" }},針對doc5,是沒有分數的{ "match": { "content": "java solution" }},針對doc5,是有一個分數的,2.3取最大分數,2.3然后doc4的分數 = 1.2 < doc5的分數 = 2.3,所以doc5就可以排在更前面的地方,符合我們的需要GET /forum/article/_search{"query": {"dis_max": {"queries": [{ "match": { "title": "java solution" }},{ "match": { "content": "java solution" }}]}}}
5、dis_max的優化、改進
dis_max只取某一個query最大的分數,完全不考慮其他query的分數。這樣存在返回的document不是預期的情況
tie_breaker參數的意義,在于說,將其他query的分數,乘以tie_breaker,然后綜合與最高分數的那個query的分數,綜合在一起進行計算除了取最高分以外,還會考慮其他的query的分數tie_breaker的值,在0~1之間,是個小數,就okGET /forum/article/_search{"query": {"dis_max": {"queries": [{ "match": { "title": "java beginner" }},{ "match": { "body": "java beginner" }}],"tie_breaker": 0.3}}}6.基于multi_match語法實現dis_max+tie_breakerGET /forum/article/_search{"query": {"multi_match": {"query": "java solution","type": "best_fields","fields": [ "title^2", "content" ], //title^2表示 boost設置為2"tie_breaker": 0.3,"minimum_should_match": "50%"}}}(1)minimum_should_match,主要是用來干嘛的?
去長尾,long tail長尾,比如你搜索5個關鍵詞,但是很多結果是只匹配1個關鍵詞的,其實跟你想要的結果相差甚遠,這些結果就是長尾minimum_should_match,控制搜索結果的精準度,只有匹配一定數量的關鍵詞的數據,才能返回
(2)title^2表示 boost設置為2GET /forum/article/_search{"query": {"dis_max": {"queries": [{"match": {"title": {"query": "java beginner","minimum_should_match": "50%","boost": 2}}},{"match": {"content": {"query": "java beginner","minimum_should_match": "50%"}}}],"tie_breaker": 0.3}}}7、most_fields策略best-fields策略,主要是說將某一個field匹配盡可能多的關鍵詞的doc優先返回回來most-fields策略,主要是說盡可能返回更多field匹配到某個關鍵詞的doc,優先返回回來不同字段使用不同的分詞器,對應不同的查詢行為。
POST /forum/_mapping/article{"properties": {"sub_title": {"type": "string","analyzer": "english", // sub_title 使用english分詞器"fields": {"std": {"type": "string","analyzer": "standard" //sub_title字段的子字段std使用standard分詞器}}}}}sub_title字段english分詞器:
會將單詞還原為其最基本的形態,stemmer
learning --> learnlearned --> learncourses --> course
subtitle.std子字段standard分詞器: 保留當前字段值得原始值得時態信息等
POST
/forum/article/_bulk
{ "update": { "_id": "1"} }{ "doc" : {"sub_title" : "learning more courses"} }{ "update": { "_id": "2"} }{ "doc" : {"sub_title" : "learned a lot of course"} }{ "update": { "_id": "3"} }{ "doc" : {"sub_title" : "we have a lot of fun"} }{ "update": { "_id": "4"} }{ "doc" : {"sub_title" : "both of them are good"} }{ "update": { "_id": "5"} }{ "doc" : {"sub_title" : "haha, hello world"} }GET /forum/article/_search{"query": {"match": {"sub_title": "learning courses"}}}
基于multi_match的most_fields
GET /forum/article/_search{"query": {"multi_match": {"query": "learning courses","type": "most_fields","fields": [ "sub_title", "sub_title.std" ]}}}
8、best_fields與most_fields:
(1)best_fields,是對多個field進行搜索,挑選某個field匹配度最高的那個分數,同時在多個query最高分相同的情況下,在一定程度上考慮其他query的分數。簡單來說,你對多個field進行搜索,就想搜索到某一個field盡可能包含更多關鍵字的數據優點:通過best_fields策略,以及綜合考慮其他field,還有minimum_should_match支持,可以盡可能精準地將匹配的結果推送到最前面缺點:除了那些精準匹配的結果,其他差不多大的結果,排序結果不是太均勻,沒有什么區分度了實際的例子:百度之類的搜索引擎,最匹配的到最前面,但是其他的就沒什么區分度了(2)most_fields,綜合多個field一起進行搜索,盡可能多地讓所有field的query參與到總分數的計算中來,此時就會是個大雜燴,出現類似best_fields案例最開始的那個結果,結果不一定精準,某一個document的一個field包含更多的關鍵字,但是因為其他document有更多field匹配到了,所以排在了前面;所以需要建立類似sub_title.std這樣的field,盡可能讓某一個field精準匹配query string,貢獻更高的分數,將更精準匹配的數據排到前面優點:將盡可能匹配更多field的結果推送到最前面,整個排序結果是比較均勻的缺點:可能那些精準匹配的結果,無法推送到最前面實際的例子:wiki,明顯的most_fields策略,搜索結果比較均勻,但是的確要翻好幾頁才能找到最匹配的結果
道在我心,一以貫之 HanWang

浙公網安備 33010602011771號