如何計算評分的html
Lucene 使用布爾模型(Boolean model) 查找匹配文檔 並主要的借鑑了 詞頻/逆向文檔頻率(term frequency/inverse document frequency) 和 向量空間模型(vector space model),同時加入 協調因子 字段長度歸一化 以及詞或查詢語句權重提高node
詞頻web
詞在文檔中出現的頻度是多少? 頻度越高,權重 越高
tf(t in d) = √frequency 詞 t 在文檔 d 的詞頻( tf )是該詞在文檔中出現次數的平方根算法
逆向文檔頻率spring
詞在集合全部文檔裏出現的頻率是多少?頻次越高,權重 越低
vidf(t) = 1 + log ( numDocs / (docFreq + 1)) 詞 t 的逆向文檔頻率( idf )是:索引中文檔數量除以全部包含該詞的文檔數,而後求其對數api
字段長度歸一值數組
字段的長度是多少? 字段越短,字段的權重 越高 。
norm(d) = 1 / √numTerms 字段長度歸一值( norm )是字段中詞數平方根的倒數 session
對於 not_analyzed 字符串字段的歸一值默認是禁用的
** 經過實例查詢,來看評分是如何計算的**app
GET product/base/_search { "size": 1, "explain": true, "query": { "match": { "name": "上海" } } }
展現出的explanation 內容dom
{ "took": 17, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 19, "max_score": 4.266216, "hits": [ { "_shard": "[product_v3][3]", "_node": "N_gFl4xjTNmIxr9SY9FAQw", "_index": "product_v3", "_type": "base", "_id": "1-134473", "_score": 4.266216, "_source": { "productSource": 1, "departureCitys": [ "上海" ], "keywords": [ "上海", "哈哈" ], "pattern": "101", "buyQuantity": 34, "managerRecommend": "111。", "averageScore": 0, "themes": [ { "category": "遊玩景點", "items": [ { "code": 4724, "name": "太原+五臺山+大同+平遙" } ] } ], "installmentFlag": 0, "madeType": 0, "bussinessProductId": "1-134473", "attribute": 91, "supplierName": "春秋旅遊", "passbyCities": [ "上海" ], "pictureLabels": [], "productId": 134473, "weight": 22, "picture": "http://webresourcetest.springtour.com/Images/gallery/201702/43362c75-91ae-43af-8cfd-85b43ec9199e_201702211501_500_350.jpg", "productThemes": [ "太原+五臺山+大同+平遙" ], "brandId": 2, "name": "上海3日2晚上海名牌", "dayNum": 3, "online": 1 }, "_explanation": { "value": 4.266216, "description": "sum of:", "details": [ { "value": 4.266216, "description": "weight(name:上海 in 54) [PerFieldSimilarity], result of:", "details": [ { "value": 4.266216, "description": "score(doc=54,freq=2.0 = termFreq=2.0\n), product of:", "details": [ { "value": 2.730029, "description": "idf, computed as log(1 + (docCount - docFreq + 0.5) / (docFreq + 0.5)) from:", "details": [ { "value": 4, "description": "docFreq", "details": [] }, { "value": 68, "description": "docCount", "details": [] } ] }, { "value": 1.5626998, "description": "tfNorm, computed as (freq * (k1 + 1)) / (freq + k1 * (1 - b + b * fieldLength / avgFieldLength)) from:", "details": [ { "value": 2, "description": "termFreq=2.0", "details": [] }, { "value": 1.2, "description": "parameter k1", "details": [] }, { "value": 0.75, "description": "parameter b", "details": [] }, { "value": 12.411765, "description": "avgFieldLength", "details": [] }, { "value": 7.111111, "description": "fieldLength", "details": [] } ] } ] } ] }, { "value": 0, "description": "match on required clause, product of:", "details": [ { "value": 0, "description": "# clause", "details": [] }, { "value": 1, "description": "_type:base, product of:", "details": [ { "value": 1, "description": "boost", "details": [] }, { "value": 1, "description": "queryNorm", "details": [] } ] } ] } ] } } ] } }
因爲展現的內容過多,咱們將其簡化 就會簡化到下面這樣的主幹
weight(text:上海 in 0) [PerFieldSimilarity]: 0.15342641 // 詞 fox 在文檔的內部 Lucene doc ID 爲 0 ,字段是 text 裏的最終評分 result of: fieldWeight in 0 0.15342641 product of: tf(freq=1.0), with freq of 1: 1.0 //詞 上海 在該文檔 text 字段中只出現了一次。 idf(docFreq=1, maxDocs=1): 0.30685282 //上海 在全部文檔 text 字段索引的逆向文檔頻率。 fieldNorm(doc=0): 0.5 // 該字段的字段長度歸一值。
假設咱們有三個文檔
咱們爲每一個文檔建立包含每一個查詢此 的權重向量
happy hippopotamus」 查詢及文檔向量
向量之間是能夠比較的,只要測量查詢向量和文檔向量之間的角度就能夠獲得每一個文檔的相關度
咱們只是利用二維的演示這個原理,其實在現實中 確定有多於兩個的。這樣的咱們可使用線性代數 ——做爲數學中處理向量的一個分支——爲咱們提供了計算兩個多維向量間角度工具
爲何向量之間的角度能夠表示他們的相關度 使用了 餘弦近似度(cosine similarity)。
在一個多詞查詢中,ES是如何對這些多詞進行處理的呢?
Lucene 使用 布爾模型(Boolean model) 、 TF/IDF 以及 向量空間模型(vector space model) ,而後將它們組合到單個高效的包裏以收集匹配文檔並進行評分計算
咱們使用例子來看多詞查詢 是怎麼轉化爲基本查詢的
GET /my_index/doc/_search { "query": { "match": { "text": "quick fox" } } } 會在內部被重寫爲 GET /my_index/doc/_search { "query": { "bool": { "should": [ {"term": { "text": "quick" }}, {"term": { "text": "fox" }} ] } } }
bool 查詢實現了布爾模型
實用評分函數 計算公式
score(q,d) = //文檔 d 與查詢 q 的相關度評分。 queryNorm(q) //查詢歸一化 因子 · coord(q,d) //協調 因子 · ∑ ( //查詢 q 中每一個詞 t 對於文檔 d 的權重和 tf(t in d) //詞 t 在文檔 d 中的 詞頻 。 · idf(t)² //詞 t 的 逆向文檔頻率 · t.getBoost() //查詢中使用的 boost( · norm(t,d) //是 字段長度歸一值 ,與 索引時字段層 boost (若是存在)的和 ) (t in q)
查詢歸一因子 queryNorm
查詢歸一因子 ( queryNorm )試圖將查詢 歸一化 , 這樣就能將兩個不一樣的查詢結果相比較。
查詢協調
協調因子 ( coord ) 能夠爲那些查詢詞包含度高的文檔提供獎勵,文檔裏出現的查詢詞越多,它越有機會成爲好的匹配結果。
索引時字段層權重提高
在索引時對這個字段上的數據進行權重的提高
不推薦這樣使用
查詢腳本
GET /_search { "query": { "bool": { "should": [ { "match": { "title": { "query": "quick brown fox", "boost": 2 } } }, { "match": { "content": "quick brown fox" } } ] } } }
** 將 boost 設置爲 2 ,並不表明最終的評分 _score 是原值的兩倍;實際的權重值會通過歸一化和一些其餘內部優化過程**
提高索引權重
當在多個索引中搜索時, 可使用參數 indices_boost 來提高整個索引的權重
GET /docs_2014_*/_search
{
"indices_boost": {
"docs_2014_10": 3,
"docs_2014_09": 2
},
"query": {
"match": {
"text": "quick brown fox"
}
}
}
t.getBoost()
權重提高不會被應用於它在查詢表達式中出現的層,而是會被合併下轉至每一個詞中。 t.getBoost() 始終返回當前詞的權重或當前分析鏈上查詢的權重
假如一個業務場景,咱們想搜索Apple,可是咱們可能會返回水果 食譜和公司,咱們可使用must_not語句來排除咱們不想要的,而將結果範圍縮小在Apple公司的相關的結果
GET /_search { "query": { "bool": { "must": { "match": { "text": "apple" } }, "must_not": { "match": { "text": "pie tart fruit crumble tree" } } } } }
可是咱們會不會發現,使用這種方法是否是過於嚴格了?會不會使咱們遺漏一些咱們所須要的數據呢?
咱們樂意使用 權重提高查詢 方法
GET /_search { "query": { "boosting": { "positive": { "match": { "text": "apple" } }, "negative": { "match": { "text": "pie tart fruit crumble tree" } }, "negative_boost": 0.5 } } }
操做的過程就是那些匹配 positive 查詢的文檔羅列出來,對於那些同時還匹配 negative 查詢的文檔將經過文檔的原始 _score 與 negative_boost 相乘的方式降級
下面咱們使用下面的這個查詢來演示咱們提高權重的過程
使用function_score
GET product/_search { "query": { "function_score": {//function_score 查詢將主查詢和函數包括在內 "query": {//先查詢主查詢 "multi_match": { "query": "上海", "fields": ["name", "keywords"] } }, "field_value_factor": {field_value_factor 函數會被應用到每一個與主 query 匹配的文檔 "field": "averageScore"//使用這個字段對score值進行計算 } } } } //每一個文檔的最終評分score作了下面的修改 new_score = old_score * number_of_votes
這樣的話,咱們的score值會根據成這樣的比例增加
帶modifyer 參數的請求
GET /blogposts/post/_search { "query": { "function_score": { "query": { "multi_match": { "query": "popularity", "fields": [ "title", "content" ] } }, "field_value_factor": { "field": "votes", "modifier": "log1p" } } } }
修飾詞 modifyer 值能夠爲多種
factor
使用指定字段與factor 的積來調節score的值
咱們經過在factor屬性添加值來改變score
GET product/_search
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "上海",
"fields": ["name","keywords" ]
}
},
"field_value_factor": {
"field": "buyQuantity",
"modifier": "ln2p",
"factor": 2
}
}
}
}
在函數圖表上顯示的話,就是這樣的
boost_mode
max_boost
經過整合多個函數,來提高權重信息
整合多個函數的查詢
GET /_search { "query": { "function_score": { "filter": { //function_score 查詢有個 filter 過濾器而不是 query 查詢 "term": { "name": "上海" } }, "functions": [ //functions 關鍵字存儲着一個將被應用的函數列表 { "filter": { "term": { "name": "杭州" }}, "weight": 1 }, { "filter": { "term": { "name": "北京" }}, "weight": 1 }, { "filter": { "term": { "name": "三亞" }}, "weight": 2 //三亞 比其餘特性更重要,因此它有更高 weight } ], "score_mode": "sum" score_mode 指定各個函數的值進行組合運算的方式。 } } }
random_score 函數的做用
andom_score 函數會輸出一個 0 到 1 之間的數, 當種子 seed 值相同時,生成的隨機結果是一致的
GET /_search { "query": { "function_score": { "filter": { "term": { "city": "Barcelona" } }, "functions": [ { "filter": { "term": { "features": "wifi" }}, "weight": 1 }, { "filter": { "term": { "features": "garden" }}, "weight": 1 }, { "filter": { "term": { "features": "pool" }}, "weight": 2 }, { "random_score": { "seed": "the users session id" } } ], "score_mode": "sum" } } } // 1 **random_score** 語句沒有任何過濾器 filter ,因此會被應用到全部文檔 // 2 將用戶的會話 ID 做爲種子 seed ,讓該用戶的隨機始終保持一致,相同的種子 seed 會產生相同的隨機結果。
function_score 查詢會提供一組 衰減函數(decay functions) , 讓咱們有能力在兩個滑動標準,如地點和價格,之間權衡
三種衰減函數
以原點 origin 爲中心點,爲其設置一個非零的偏移量 offset 覆蓋一個範圍,而不僅是單個原點。在範圍 -offset <= origin <= +offset 內的全部評分 _score 都是 1.0
下面的是衰減函數曲線
gauss 高斯函數 先慢後快最後慢
腳本實例
GET product/base/_search { "query": { "function_score": { "query": {}, "functions": [ { "gauss": { "averageScore": { "origin": "100", "scale": "20", "offset": "50" } } }, { "exp": { "productId": { "origin": "1500", "scale": "100", "offset": "50" } }, "weight": 2 } ] } } }
在作字段映射的時候進行更改類似度
PUT /my_index { "mappings": { "doc": { "properties": { "title": { "type": "string", "similarity": "BM25" // title 字段使用 BM25 類似度算法 }, "body": { "type": "string", "similarity": "default" // body 字段用默認類似度算法 } } } }
Elasticsearch 不支持更改已有字段的類似度算法 similarity 映射
配置BM25類似度
PUT /my_index { "settings": { "similarity": { "my_bm25": { //建立一個基於內置 BM25 ,名爲 my_bm25 的自定義類似度算法 "type": "BM25", "b": 0 //禁用字段長度規範化(field-length normalization) } } }, "mappings": { "doc": { "properties": { "title": { "type": "string", "similarity": "my_bm25" //title 字段使用自定義類似度算法 my_bm25 }, "body": { "type": "string", "similarity": "BM25" //字段 body 使用內置類似度算法 BM25 } } } } }