一、預熱
TFIDFSimilarity曾經是Lucene/Solr默認評分公式,但是從lucene-6.0
開始已經改成BM25Similary
了(詳見Lucene-6789 )。但我們今天看的依然是TFIDFSimilarity ,因為它相對簡單一些,對我們理解評分過程有好處。
首先假定你知道怎么把一篇文檔轉化成一個空間向量,並且知道空間向量模型。
接下來先來統一一下術語和記號 q : query,表示一個查詢 d : document,表示一篇文檔
V(q) :
q ⃗
q
⃗
\vec{q}
q
表示Query的向量 V(d) :
d ⃗
d
⃗
\vec{d}
d
表示Document的向量 |V(q)| :
∣ q ⃗ ∣
∣
q
⃗
∣
|\vec{q}|
∣ q
∣ 表示Query向量的歸一化 |V(d)| :
∣ d ⃗ ∣
∣
d
⃗
∣
|\vec{d}|
∣ d
∣ 表示Document向量的歸一化
在看TFIDFSimilarity之前,我們先看簡單復習幾個簡單的公式。
余弦定理
c o s i n e _ s i m i l a r i t y ( q , d ) = V ( q ) ⋅ V ( q ) ∣ V ( q ) ∣ × ∣ V ( d ) ∣
c
o
s
i
n
e
_
s
i
m
i
l
a
r
i
t
y
(
q
,
d
)
=
V
(
q
)
⋅
V
(
q
)
∣
V
(
q
)
∣
×
∣
V
(
d
)
∣
cosine\_similarity(q,d) = \frac{V(q) · V(q)}{|V(q)| \times |V(d)|}
c o s i n e _ s i m i l a r i t y ( q , d ) = ∣ V ( q ) ∣ × ∣ V ( d ) ∣ V ( q ) ⋅ V ( q ) ,用余弦定理通過計算兩向量的夾角來表示兩文本的相似,這是一切的基礎。
這里沿*Lucene Docs 的寫法,
c o s i n e _ s i m i l a r i t y ( q , d )
c
o
s
i
n
e
_
s
i
m
i
l
a
r
i
t
y
(
q
,
d
)
cosine\_similarity(q,d)
c o s i n e _ s i m i l a r i t y ( q , d ) 而不是用
s c o r e ( q , d )
s
c
o
r
e
(
q
,
d
)
score(q,d)
s c o r e ( q , d ) 的原因是相似度不是每個最終得分,相似度只是評分過程比較重要的一個因素而已。*建議你還是先看看 TFIDFSimilarty的官方文檔 ,它講得相當完整也很細**。
tf-idf公式 tf-idf算法是一種非常常見算法,用來計算文本每個權重的。 tf-idf算法的原理如果詞條在文檔出頻率越高,則詞條權重越高;如詞條在越多篇文檔出現,而詞條的權重越低。具體計算如下:
t f i d f ( t ) = t f ( t ) ∗ i d f ( t )
t
f
i
d
f
(
t
)
=
t
f
(
t
)
∗
i
d
f
(
t
)
tfidf(t) = tf(t) * idf(t)
t f i d f ( t ) = t f ( t ) ∗ i d f ( t )
t f ( t ) = f r e q u e n c y − − − − − − − − √
t
f
(
t
)
=
f
r
e
q
u
e
n
c
y
tf(t) = \sqrt{frequency}
t f ( t ) = f r e q u e n c y
i d f ( t ) = 1 + log d o c _ c o u n t + 1 d o c _ f r e q + 1
i
d
f
(
t
)
=
1
+
log
d
o
c
_
c
o
u
n
t
+
1
d
o
c
_
f
r
e
q
+
1
idf(t) = 1 + \log{\frac{doc\_count+1}{doc\_freq+1}}
i d f ( t ) = 1 + log d o c _ f r e q + 1 d o c _ c o u n t + 1
t f i d f ( t ) = f r e q u e n c y − − − − − − − − √ × ( 1 + log d o c _ c o u n t + 1 d o c _ f r e q + 1 )
t
f
i
d
f
(
t
)
=
f
r
e
q
u
e
n
c
y
×
(
1
+
log
d
o
c
_
c
o
u
n
t
+
1
d
o
c
_
f
r
e
q
+
1
)
tfidf(t) = \sqrt{frequency} \times (1 + \log{\frac{doc\_count+1}{doc\_freq+1}})
t f i d f ( t ) = f r e q u e n c y
× ( 1 + log d o c _ f r e q + 1 d o c _ c o u n t + 1 )
對於VSM而言,tf-idf算法並不是必須,甚至權重的引入也不是必須。也就是只需要把每個詞轉化為一個數值即可,可以用詞條的HashCode、詞包的下標等等。 當然tf-idf算法也不是計算權重的唯一算法,比tf-idf效果更的還有BM25(BM25Similarity )。 故名思義,TFIDFSimilarity即是用TFIDF作為VSM向量的權重來計算相似度的打分器。
二、開始
原想從兩個字符串的相似計算開始來推導我們Lucene的評分公式的,但這樣的話篇幅太長太啰嗦太復雜。因此選擇從Lucene的公式出發來看全公式每個細節的含義,一步步變化和計算最終推導出實踐公式。
2.1 理論公式
我們先看一下,Lucene TFIDFSimilarity給出的理論評分公式:
s c o r e ( q , d ) = c o o r d _ f a c t o r ( q , d ) × q u e r y _ b o o s t ( q ) × V ( q ) ⋅ V ( d ) ∣ V ( q ) ∣ × d o c _ l e n _ n o r m ( d ) × d o c _ b o o s t ( d )
s
c
o
r
e
(
q
,
d
)
=
c
o
o
r
d
_
f
a
c
t
o
r
(
q
,
d
)
×
q
u
e
r
y
_
b
o
o
s
t
(
q
)
×
V
(
q
)
⋅
V
(
d
)
∣
V
(
q
)
∣
×
d
o
c
_
l
e
n
_
n
o
r
m
(
d
)
×
d
o
c
_
b
o
o
s
t
(
d
)
score(q,d) = coord\_factor(q,d) \times query\_boost(q) \times \frac{V(q)·V(d)}{|V(q)|} \times doc\_len\_norm(d) \times doc\_boost(d)
s c o r e ( q , d ) = c o o r d _ f a c t o r ( q , d ) × q u e r y _ b o o s t ( q ) × ∣ V ( q ) ∣ V ( q ) ⋅ V ( d ) × d o c _ l e n _ n o r m ( d ) × d o c _ b o o s t ( d )
為什么說它是理論公式呢,因為它由VSM直接推導出來的公式。然則它在實際運用上並不是很方便和高效,因此我們對它進行一系列的變轉使得它的計算得到一個簡化的式子。
2.1.1 細說相似度部分
前面提到過Lucene相似度是通過VSM來計算(當然*TFIDFSimilarty的官方文檔 *也是提及的),相似度similarity通過如下公式計算的:
c o s i n e _ s i m i l a r i t y ( q , d ) = V ( q ) ⋅ V ( q ) ∣ V ( q ) ∣ × ∣ V ( d ) ∣
c
o
s
i
n
e
_
s
i
m
i
l
a
r
i
t
y
(
q
,
d
)
=
V
(
q
)
⋅
V
(
q
)
∣
V
(
q
)
∣
×
∣
V
(
d
)
∣
cosine\_similarity(q,d) = \frac{V(q) · V(q)}{|V(q)| \times |V(d)|}
c o s i n e _ s i m i l a r i t y ( q , d ) = ∣ V ( q ) ∣ × ∣ V ( d ) ∣ V ( q ) ⋅ V ( q )
a. 如何計算倆向量的內積
由於我們研究的是TFIDFSimilarity的評分公式,我們知道TFIDFSimilarity評分過程是采用了tf-idf算法作為向量的權重(weight)。 因此有
q ⃗ = ( w 1 , w 2 , . . . , w n )
q
⃗
=
(
w
1
,
w
2
,
.
.
.
,
w
n
)
\vec{q}=(w_1, w_2, ..., w_n)
q
= ( w 1 , w 2 , . . . , w n ) ,且
w i = t f ( t i ) × i d f ( t i , q )
w
i
=
t
f
(
t
i
)
×
i
d
f
(
t
i
,
q
)
w_i=tf(t_i)\times idf(t_i, q)
w i = t f ( t i ) × i d f ( t i , q ) ;
d ⃗ = ( d 1 , d 2 , . . . , d n )
d
⃗
=
(
d
1
,
d
2
,
.
.
.
,
d
n
)
\vec{d}=(d_1, d_2, ..., d_n)
d
= ( d 1 , d 2 , . . . , d n ) ,且
d i = t f ( t i ) × i d f ( t i , d )
d
i
=
t
f
(
t
i
)
×
i
d
f
(
t
i
,
d
)
d_i=tf(t_i)\times idf(t_i, d)
d i = t f ( t i ) × i d f ( t i , d )
通常來說每個Query的每個詞條的出現次數都是1
,因此
t f ( t 1 ) = t f ( t 2 ) = . . . = t f ( t i ) = a , a ∈ ( 0 , 1 ]
t
f
(
t
1
)
=
t
f
(
t
2
)
=
.
.
.
=
t
f
(
t
i
)
=
a
,
a
∈
(
0
,
1
]
tf(t_1) = tf(t_2) = ... = tf(t_i) = a, a\in(0, 1]
t f ( t 1 ) = t f ( t 2 ) = . . . = t f ( t i ) = a , a ∈ ( 0 , 1 ] 。
V ( q ) ⋅ V ( d ) = q ⃗ ⋅ d ⃗ = ∑ t i n q ( w t × d t )
V
(
q
)
⋅
V
(
d
)
=
q
⃗
⋅
d
⃗
=
∑
t
i
n
q
(
w
t
×
d
t
)
V(q)·V(d) = \vec{q} · \vec{d} = \sum_{t\ in\ q}{(w_t \times d_t)}
V ( q ) ⋅ V ( d ) = q
⋅ d
= t i n q ∑ ( w t × d t )
= ∑ t i n q ( t f ( t , q ) × i d f ( t , q ) × t f ( t , d ) × i d f ( t , d ) )
=
∑
t
i
n
q
(
t
f
(
t
,
q
)
×
i
d
f
(
t
,
q
)
×
t
f
(
t
,
d
)
×
i
d
f
(
t
,
d
)
)
= \sum_{t\ in\ q}{(tf(t,q)\times idf(t,q)\times tf(t,d)\times idf(t,d))}
= t i n q ∑ ( t f ( t , q ) × i d f ( t , q ) × t f ( t , d ) × i d f ( t , d ) )
= t f ( t , q ) × ∑ t i n q i d f ( t , q ) × t f ( t , d ) × i d f ( t , d ) )
=
t
f
(
t
,
q
)
×
∑
t
i
n
q
i
d
f
(
t
,
q
)
×
t
f
(
t
,
d
)
×
i
d
f
(
t
,
d
)
)
= tf(t,q) \times \sum_{t\ in\ q}{idf(t,q)\times tf(t,d)\times idf(t,d))}
= t f ( t , q ) × t i n q ∑ i d f ( t , q ) × t f ( t , d ) × i d f ( t , d ) )
= a × ∑ t i n q i d f ( t , q ) × t f ( t , d ) × i d f ( t , d ) )
=
a
×
∑
t
i
n
q
i
d
f
(
t
,
q
)
×
t
f
(
t
,
d
)
×
i
d
f
(
t
,
d
)
)
= a \times \sum_{t\ in\ q}{idf(t,q)\times tf(t,d)\times idf(t,d))}
= a × t i n q ∑ i d f ( t , q ) × t f ( t , d ) × i d f ( t , d ) )
由上式易知a對同一個Query而言是一個常量,因此上式可以進一步簡化為
V ( q ) ⋅ V ( d ) = ∑ t i n q t f ( t , d ) × i d f ( t , d ) × i d f ( t , q )
V
(
q
)
⋅
V
(
d
)
=
∑
t
i
n
q
t
f
(
t
,
d
)
×
i
d
f
(
t
,
d
)
×
i
d
f
(
t
,
q
)
V(q)·V(d) = \sum_{t\ in\ q}{tf(t,d)\times idf(t,d) \times idf(t,q)}
V ( q ) ⋅ V ( d ) = t i n q ∑ t f ( t , d ) × i d f ( t , d ) × i d f ( t , q )
那么又是怎么計算Query
的
i d f ( t , q )
i
d
f
(
t
,
q
)
idf(t,q)
i d f ( t , q ) 呢? 已知道
i d f ( t , d ) = 1 + log d o c _ c o u n t + 1 d o c _ f r e q + 1
i
d
f
(
t
,
d
)
=
1
+
log
d
o
c
_
c
o
u
n
t
+
1
d
o
c
_
f
r
e
q
+
1
idf(t,d) = 1 + \log{\frac{doc\_count+1}{doc\_freq+1}}
i d f ( t , d ) = 1 + log d o c _ f r e q + 1 d o c _ c o u n t + 1 ,同時我們可以把Query也當作一篇文檔。因此對於
i d f ( t , q )
i
d
f
(
t
,
q
)
idf(t,q)
i d f ( t , q ) 有
d o c _ c o u n t q = d o c _ c o u n t d + 1 ; d o c _ f r e q q = d o c _ f r e q d + 1
d
o
c
_
c
o
u
n
t
q
=
d
o
c
_
c
o
u
n
t
d
+
1
;
d
o
c
_
f
r
e
q
q
=
d
o
c
_
f
r
e
q
d
+
1
doc\_count_q=doc\_count_d + 1; doc\_freq_q = doc\_freq_d+1
d o c _ c o u n t q = d o c _ c o u n t d + 1 ; d o c _ f r e q q = d o c _ f r e q d + 1 (即直接把原文檔總數以及對應的文檔頻率都加上1
)。整理可得
i d f ( t , q ) = 1 + log 1 + ( d o c _ c o u n t + 1 ) 1 + ( d o c _ f r e q + 1 )
i
d
f
(
t
,
q
)
=
1
+
log
1
+
(
d
o
c
_
c
o
u
n
t
+
1
)
1
+
(
d
o
c
_
f
r
e
q
+
1
)
idf(t,q) = 1 + \log{\frac{1 + (doc\_count+1)}{1 + (doc\_freq+1)}}
i d f ( t , q ) = 1 + log 1 + ( d o c _ f r e q + 1 ) 1 + ( d o c _ c o u n t + 1 ) 當文檔數量比較大的時候,我們可以認為
i d f ( t , q ) = i d f ( t , d )
i
d
f
(
t
,
q
)
=
i
d
f
(
t
,
d
)
idf(t,q) = idf(t,d)
i d f ( t , q ) = i d f ( t , d ) ,因此上式可以進一步簡化為
V ( q ) ⋅ V ( d ) = ∑ t i n q t f ( t , d ) × i d f 2 ( t , q ) )
V
(
q
)
⋅
V
(
d
)
=
∑
t
i
n
q
t
f
(
t
,
d
)
×
i
d
f
2
(
t
,
q
)
)
V(q)·V(d) = \sum_{t\ in\ q}{tf(t,d)\times idf^2(t,q))}
V ( q ) ⋅ V ( d ) = t i n q ∑ t f ( t , d ) × i d f 2 ( t , q ) )
中間的計算過程不能理解也沒關系,你只需要知道並記住最終結果就可以了。
b. 為什么|V(d)|不見了
先看一下Lucene Docs對
∣ V ( d ) ∣
∣
V
(
d
)
∣
|V(d)|
∣ V ( d ) ∣ 的解釋吧。
Normalizing V(d) to the unit vector is known to be problematic in that it removes all document length information. For some documents removing this info is probably ok, e.g. a document made by duplicating a certain paragraph 10 times, especially if that paragraph is made of distinct terms. But for a document which contains no duplicated paragraphs, this might be wrong. To avoid this problem, a different document length normalization factor is used, which normalizes to a vector equal to or larger than the unit vector: doc-len-norm(d).
大意是說|V(d)|是一個單位向量,因此它並不帶文檔的長度信息。如果文檔是由一段文本重復十次組成的,尤其這段文本由完全不一樣詞條組成時,文檔長度信息對於這類文檔可能並不會有影響。但是文檔由多段不一樣文本構成的,那么文檔長度信息可能會有影響。為此,使用不同文檔長度歸一化因子,可實現一個向量大於或等於它的單位向量doc-len-norm(d)。
我猜你沒看懂。簡單說,如你所知文檔長度信息是會影響相似度,即文檔長度越大可能更有優勢。為了解決這個問題我們引用**doc-len-norm(d)**來代替
∣ V ( d ) ∣
∣
V
(
d
)
∣
|V(d)|
∣ V ( d ) ∣ 。
到此為止,並沒有解釋
∣ V ( d ) ∣
∣
V
(
d
)
∣
|V(d)|
∣ V ( d ) ∣ 為什么可以不要,只是說明了doc-len-norm(d)的作用。
至於為什么不要
∣ V ( d ) ∣
∣
V
(
d
)
∣
|V(d)|
∣ V ( d ) ∣ 呢?雖然
∣ V ( d ) ∣
∣
V
(
d
)
∣
|V(d)|
∣ V ( d ) ∣ 是文檔歸一化因子,理論上它是可以評價文檔的重要性的。但是它計算比較復雜(又有開文又有平方),關鍵還沒什么用。下面是
∣ V ( d ) ∣
∣
V
(
d
)
∣
|V(d)|
∣ V ( d ) ∣ 的計算公式:
∣ V ( d ) ∣ = ∑ t i n q ( t f ( t , d ) × i d f ( t , d ) ) 2 − − − − − − − − − − − − − − − − − − − − − √
∣
V
(
d
)
∣
=
∑
t
i
n
q
(
t
f
(
t
,
d
)
×
i
d
f
(
t
,
d
)
)
2
|V(d)| = \sqrt{\sum_{t\ in\ q}{(tf(t,d)\times idf(t,d))^2}}
∣ V ( d ) ∣ = t i n q ∑ ( t f ( t , d ) × i d f ( t , d ) ) 2
上式易知它的計算復雜同時並沒有涉及文檔的長度信息,因此Lucene選擇另一種方式來表示,它能把文檔的長度信息考慮進來,這就是我們前面提到doc-len-norm(d)。
c. 什么是 doc-len-norm(d)
故名思義,它是文檔長度歸一化因子,即是弱化文檔長度對最終評分的影響。那我們怎么在搜索過程引用文檔的長度對評分的影響呢? 首先lucene文檔是可以有多個字段,而且搜索時被指定字段. 由此可以用搜索時指定搜索字段
f
f
f
f 的歸一化因子來表示文檔的歸一化因子,所以就把問題轉化算字段
f
f
f
f 的歸一化因子的問題了。設
n o r m ( t , d )
n
o
r
m
(
t
,
d
)
norm(t,d)
n o r m ( t , d ) 表示文檔d的搜索字段
f
f
f
f 的歸一化因子。
d o c _ l e n _ n o r m ( d ) = ∑ t i n q n o r m ( t , d )
d
o
c
_
l
e
n
_
n
o
r
m
(
d
)
=
∑
t
i
n
q
n
o
r
m
(
t
,
d
)
doc\_len\_norm(d) = \sum_{t\ in\ q}{norm(t,d)}
d o c _ l e n _ n o r m ( d ) = t i n q ∑ n o r m ( t , d )
用什么來表示
n o r m ( t , d )
n
o
r
m
(
t
,
d
)
norm(t,d)
n o r m ( t , d ) 呢?Lucene用了下面的式子來表示:
n o r m ( t , d ) = l e n g t h N o r m ∏ f i n d f . g e t B o o s t ( )
n
o
r
m
(
t
,
d
)
=
l
e
n
g
t
h
N
o
r
m
∏
f
i
n
d
f
.
g
e
t
B
o
o
s
t
(
)
norm(t,d) = lengthNorm \prod_{f\ in\ d}{f.getBoost()}
n o r m ( t , d ) = l e n g t h N o r m f i n d ∏ f . g e t B o o s t ( )
l e n g t h N o r m = 1 l e n g t h ( f ) − n u m O v e r l a p ( f ) √
l
e
n
g
t
h
N
o
r
m
=
1
l
e
n
g
t
h
(
f
)
−
n
u
m
O
v
e
r
l
a
p
(
f
)
lengthNorm = \frac{1}{\sqrt{length(f) - numOverlap(f)}}
l e n g t h N o r m = l e n g t h ( f ) − n u m O v e r l a p ( f )
1
length : 字段的所有詞條的數量 numOverlap : 字段的所有詞條中出現過2次及以上詞條的數量
lengthNorm是索引時計算好跟其它字段信息一樣存儲的,因此在搜索時它的“計算”是比較高效的。同時它並不是所有字段類型都會存儲的,例如數值類型就不會計算和存儲。當然對文本類型也可以關閉norm的計算,同時如果開啟norm的計算的話,還能選擇是否壓縮。為了減小索引的體積,默認情況下是帶用壓縮的。
這里lengthNorm只是一般情況下的計算公式,並非所有情況都是這個公式
說到這里,我們順便把norm(d)編碼和解碼兩過程出現誤差的情況解釋一下吧。 其實前面已經解釋過了,即是lucene為了減小索引的體積,對norm進行壓縮。即是把原本應該用float表示norm數值,壓縮成一個byte造成精度缺失,這就是decodeNormValue(encodeNormValue(norm))不一定等於norm的原因。
Lucene docs對LengthNorm的說明是這樣的:
computed when the document is added to the index in accordance with the number of tokens of this field in the document, so that shorter fields contribute more to the score. LengthNorm is computed by the Similarity class in effect at indexing.
d. |V(q)|是什么呢
細心的你可能已經知道了|V(q)|是怎么回事,對的沒錯它就是queryNorm的別名。看一下QueryNorm的公式
q u e r y N o r m ⎛ ⎝ ⎜ q ⎞ ⎠ ⎟ = 1 q . g e t B o o s t ( ) 2 × ∑ t i n q ( i d f ( t , q ) × t . g e t B o o s t ( ) ) 2 √
q
u
e
r
y
N
o
r
m
(
q
)
=
1
q
.
g
e
t
B
o
o
s
t
(
)
2
×
∑
t
i
n
q
(
i
d
f
(
t
,
q
)
×
t
.
g
e
t
B
o
o
s
t
(
)
)
2
queryNorm(q)=\frac{1}{\sqrt{q.getBoost()^2 \times \sum_{t\ in\ q}{(idf(t,q)\times t.getBoost())}^2}}
q u e r y N o r m ( q ) = q . g e t B o o s t ( ) 2 × ∑ t i n q ( i d f ( t , q ) × t . g e t B o o s t ( ) ) 2
1
我們先假定完全不設boost,即先假定boost=1
。因此原式可以變成
q u e r y N o r m ( q ) = 1 ∑ t i n q i d f 2 ( t , q ) √
q
u
e
r
y
N
o
r
m
(
q
)
=
1
∑
t
i
n
q
i
d
f
2
(
t
,
q
)
queryNorm(q)=\frac{1}{\sqrt{\sum_{t\ in\ q}{idf^2(t,q)}}}
q u e r y N o r m ( q ) = ∑ t i n q i d f 2 ( t , q )
1 。 再回顧一下
∣ V ( q ) ∣
∣
V
(
q
)
∣
|V(q)|
∣ V ( q ) ∣ 的公式,
∣ V ( q ) ∣ = 1 ∑ t i n q i d f 2 ( t , q ) × t f 2 ( t , q ) √
∣
V
(
q
)
∣
=
1
∑
t
i
n
q
i
d
f
2
(
t
,
q
)
×
t
f
2
(
t
,
q
)
|V(q)|=\frac{1}{\sqrt{\sum_{t\ in\ q}{idf^2(t,q) \times tf^2(t,q)}}}
∣ V ( q ) ∣ = ∑ t i n q i d f 2 ( t , q ) × t f 2 ( t , q )
1 ,因為一般情況下Query中每個詞出現的頻率都是1。因此原式可簡寫成
∣ V ( q ) ∣ = 1 ∑ t i n q i d f 2 ( t , q ) √
∣
V
(
q
)
∣
=
1
∑
t
i
n
q
i
d
f
2
(
t
,
q
)
|V(q)|=\frac{1}{\sqrt{\sum_{t\ in\ q}{idf^2(t,q)}}}
∣ V ( q ) ∣ = ∑ t i n q i d f 2 ( t , q )
1 ,對於這點我們前面解釋過了。然后再把各種boost考慮進去,你會發現
∣ V ( q ) ∣
∣
V
(
q
)
∣
|V(q)|
∣ V ( q ) ∣ 的式子跟
q u e r y N o r m ( q )
q
u
e
r
y
N
o
r
m
(
q
)
queryNorm(q)
q u e r y N o r m ( q ) 一模一樣。
我們知道打分是對文檔打分,因此是每個被檢索到的文檔都要套這個公式來計算它的分值。簡而言之,評分公式是文檔級別的。
它使得兩個不同Queries的搜索結果的每個文檔的得分可以比較,可以比較意思是它們的比較是有意義的。
QueryNorm不影響排名,也就是不影響評分,就是對於同一個Query來說queryNorm是唯一的。好吧,這說法並不准確,應該是對於同一個Index的同一個Query它的queryNorm是唯一的。如果不能理解就看公式吧,作為查詢歸一化,那么它作用就是縮小同一個Query在不同Index上產生的影響。這使得分布式查詢(同一個Query用在不同的Index上並計算文檔的分數)的評分變得有意義和有可比性。
不影響排名,也就是不影響評分,有兩層意思:
在單個Index而queryNorm是沒意義,不會影響評分和排序。
對於多個Index,queryNorm實際上是會影響的評分和排序。只是這影響是降低不同的index之間在搜索時的影響,因此可以認為沒有影響。
2.2 coord因子
coord相關性,overlap與maxoverlap比值
c o o r d ( q , d ) = o v e r l a p m a x O v e r l a p
c
o
o
r
d
(
q
,
d
)
=
o
v
e
r
l
a
p
m
a
x
O
v
e
r
l
a
p
coord(q,d) = \frac{overlap}{maxOverlap}
c o o r d ( q , d ) = m a x O v e r l a p o v e r l a p maxOverlap:是Query中有效的詞條數 overlap:表示文檔中出現詞條數
2.3 boost的作用
boost的作用就是在索引時或搜索時,改變字段或者詞條的重要,從而影響文檔的最終得分。
兩個時間點:搜索時和索引時,都能設置
四個級別:Query條件、文檔、字段和詞條
三、實踐公式即將出現
我們先上面推導出來最終式子羅列一下:
V ( q ) ⋅ V ( d ) = ∑ t i n q t f ( t , d ) × i d f 2 ( t , q ) )
V
(
q
)
⋅
V
(
d
)
=
∑
t
i
n
q
t
f
(
t
,
d
)
×
i
d
f
2
(
t
,
q
)
)
V(q)·V(d) = \sum_{t\ in\ q}{tf(t,d)\times idf^2(t,q))}
V ( q ) ⋅ V ( d ) = ∑ t i n q t f ( t , d ) × i d f 2 ( t , q ) )
d o c _ l e n _ n o r m ( d ) = ∑ t i n q n o r m ( t , d )
d
o
c
_
l
e
n
_
n
o
r
m
(
d
)
=
∑
t
i
n
q
n
o
r
m
(
t
,
d
)
doc\_len\_norm(d) = \sum_{t\ in\ q}{norm(t,d)}
d o c _ l e n _ n o r m ( d ) = ∑ t i n q n o r m ( t , d )
∣ V ⎛ ⎝ ⎜ q ⎞ ⎠ ⎟ ∣ = q u e r y N o r m ⎛ ⎝ ⎜ q ⎞ ⎠ ⎟ = 1 q . g e t B o o s t ( ) 2 × ∑ t i n q ( i d f ( t , q ) × t . g e t B o o s t ( ) ) 2 √
∣
V
(
q
)
∣
=
q
u
e
r
y
N
o
r
m
(
q
)
=
1
q
.
g
e
t
B
o
o
s
t
(
)
2
×
∑
t
i
n
q
(
i
d
f
(
t
,
q
)
×
t
.
g
e
t
B
o
o
s
t
(
)
)
2
|V(q)| = queryNorm(q) = \frac{1}{\sqrt{q.getBoost()^2 \times \sum_{t\ in\ q}{(idf(t,q)\times t.getBoost())}^2}}
∣ V ( q ) ∣ = q u e r y N o r m ( q ) = q . g e t B o o s t ( ) 2 × ∑ t i n q ( i d f ( t , q ) × t . g e t B o o s t ( ) ) 2
1
把上面三個式子代入下式
s c o r e ( q , d ) = c o o r d ( q , d ) × q u e r y N o r m ( q ) × ∑ t i n q ( i d f 2 ( t , q ) × t f ( t , d ) ) × d o c _ l e n _ n o r m ( d )
s
c
o
r
e
(
q
,
d
)
=
c
o
o
r
d
(
q
,
d
)
×
q
u
e
r
y
N
o
r
m
(
q
)
×
∑
t
i
n
q
(
i
d
f
2
(
t
,
q
)
×
t
f
(
t
,
d
)
)
×
d
o
c
_
l
e
n
_
n
o
r
m
(
d
)
score(q,d) = coord(q,d)\times queryNorm(q) \times \sum_{t\ in\ q}{(idf^2(t,q)\times tf(t,d))} \times doc\_len\_norm(d)
s c o r e ( q , d ) = c o o r d ( q , d ) × q u e r y N o r m ( q ) × t i n q ∑ ( i d f 2 ( t , q ) × t f ( t , d ) ) × d o c _ l e n _ n o r m ( d ) 整理可得
= c o o r d ( q , d ) × q u e r y N o r m ( q ) × ∑ t i n q ( i d f 2 ( t , q ) × t f ( t , d ) × n o r m ( t , d ) )
=
c
o
o
r
d
(
q
,
d
)
×
q
u
e
r
y
N
o
r
m
(
q
)
×
∑
t
i
n
q
(
i
d
f
2
(
t
,
q
)
×
t
f
(
t
,
d
)
×
n
o
r
m
(
t
,
d
)
)
= coord(q,d) \times queryNorm(q) \times \sum_{t\ in\ q}{(idf^2(t,q)\times tf(t,d) \times norm(t,d))}
= c o o r d ( q , d ) × q u e r y N o r m ( q ) × t i n q ∑ ( i d f 2 ( t , q ) × t f ( t , d ) × n o r m ( t , d ) )
四、結語
之前在學習lucene的時候就想寫這么一篇博客,但是一直沒能實現。如今也是能花好幾個小時才整理出來,當第一次把所有內容都羅列出來的時候,篇幅是那么那么的長。經過幾番裁剪才如今這個樣子,肯定是有一些地方沒說明白的,若問題可以一起論,這么復雜的博文難免會出錯誤,若有發現錯誤望不吝指教 。
</div>
原文地址:https://blog.csdn.net/zteny/article/details/57366074