使用停用詞的利弊
我們擁有更多硬盤資源,但是比較少的內存資源。從索引中去掉一些停用詞平均每百萬個文檔中也就節省了4MB的資源。所以停用詞並不是來節省存儲資源的。
並且,我們移除一些停用詞會帶來一些壞處。比如我們就很難無法做到以下幾種事情:
- 區分 happy from not happy
- 搜索 the band The The
- 找到莎士比亞的名言”to be, or not to be”
- 用國家的代碼,例如 挪威:no
而移除停用詞帶來的好處主要是性能。用fox這個詞來搜索一百萬的文檔。可能fox這個詞僅僅存在於20個文檔中,這樣ElasticSearch只需要計算20個文檔的相關度然後排序再返回top 10. 但是如果我們搜索 the or fox。 單詞 the 可能存在於幾乎所有的文檔,這就意味着ElasticSearch必須計算所有文檔的_score(相關度)再排序。這是不可想象的。
我們有辦法來解決上述描述的問題。下面來講一下如何使用停用詞。
使用停用詞
停用詞和標準分析器
我們只需要創建一個配置的分析器,並且把停用詞輸入進去就可以使用用戶自定義的停用詞了
PUT /my_index
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"type": "standard",
"stopwords": [ "and", "the" ]
}
}
}
}
}
分治法
在訪問字符串中,可以把字符串中的詞分爲兩個部分,一個種是重要的詞(低頻詞,在比較少文檔出現的詞),一種是不重要的詞(在文檔中經常出現的,例如the、a、to)。我們要的搜索結果儘量多匹配更多的重要的詞。
而match查詢可以增多一個cutoff_frequency的參數,用來區分方位字符串中重要的詞和不重要的詞。這樣重要的詞先把訪問的文檔查出來,然後不重要的詞僅僅用來計算相關度,而不是匹配。通過兩種不同的方式,我們可以在查詢速度上得到一個巨大的提升。
Domain-Specific Stopwords
通過cutoff_frequency的方式我們可以得到一個很大的好處就是很輕鬆的獲取了領域相關的停用詞,例如在電影領域movie、color這些詞基本上就沒什麼意義。如果是自定義停用詞,還需要手動把這些停用詞表加進去,而這個算法會通過cutoff_frequency自動將區分那些高頻詞。
話不多說,來個代碼
{
"match": {
"text": {
"query": "Quick and the dead",
"cutoff_frequency": 0.01
}
}
這個查詢會用cutoff_frequency 先把訪問字符串中詞氛圍兩個部分,一個是重要的詞(quick dead),另一個一個部分是(and the)。然後再執行一個bool查詢
如下
{
"bool": {
"must": {
"bool": {
"should": [
{ "term": { "text": "quick" }},
{ "term": { "text": "dead" }}
]
}
},
"should": {
"bool": {
"should": [
{ "term": { "text": "and" }},
{ "term": { "text": "the" }}
]
}
}
}
}
其中must塊中意思是quick 和dead至少要匹配一個。 而should塊僅僅是用來幫助計算相關度的,並沒有強制要求匹配。這種方法的執行過程是先把必須要匹配的詞 quick or dead的文檔先查出來,然後在將所有的詞綜合考慮進去來計算相關度。因爲must塊中的詞是低頻詞,所以這就大大減少了需要計算相關度和需要排序的文檔,提綱了查詢性能。
控制精度
minimum_should_match 可以跟cutoff_frequency 聯合起來使用
只有高頻詞咋辦?
比如查詢字符串是 “to be, or not to be”,搜索這樣詞簡直一臉懵逼。在這種情況下,沒有一個詞是重要的,我們僅僅關心擁有這所有詞的文檔,這種情況下EalsticSearch會執行如下語句{
“bool”: {
“must”: [
{ “term”: { “text”: “to” }},
{ “term”: { “text”: “be” }},
{ “term”: { “text”: “or” }},
{ “term”: { “text”: “not” }},
{ “term”: { “text”: “to” }},
{ “term”: { “text”: “be” }}
]
}
}含有所有這些不重要詞的文檔
更多的高頻詞(常用詞的)查詢可以訪問https://www.elastic.co/guide/en/elasticsearch/reference/2.4/query-dsl-common-terms-query.html
停用詞和短語查詢
大約有5%的查詢是短語查詢,但是這些查詢是查詢速度比較慢的主力軍。短語查詢可能表現的很糟糕。特別是短語裏存在一些非常常見的詞,例如:to be, or not to be。所以我們需要做一些事情來解決短語查詢的問題。
在上文講過的停用詞的優缺點中,我們說移除一些停用詞僅僅會在反向索引中節省微不足道的存儲空間。這僅僅對了一部分,一個典型的索引還會包含其他的數據。如下表
- 詞典。 一個對所有詞排過序的詞典,並且保存了含有每個詞的文檔的數量。
- Posting list。 A list of which documents contain each term.
- 詞頻。每一個詞出現在每一個文檔中的次數
- 每一個詞出現在每一個文檔中的位置,這是爲了短語查詢
- The start and end character offsets of each term in each document, for snippet highlighting. Disabled by default.
- 一個用來歸一化不同文檔長度的參數,它會給短的文檔更多的權重
數據位置
位置信息在analyzed 是缺省的,爲了短語查詢能表現的更好多一點。但是某個詞出現的次數越多,那麼就需要越多存儲空間來存儲這些位置數據。而非常常見的詞,這些位置數據的量會達到兆字節甚至是G字節。
跑一個短語查詢,用了比較常見的詞,比如the,就會導致上G的數據從硬盤裏讀出來,這些數據會被保存在kernel文件系統中去加速後面的查詢,這看起來是一個好事,但這會把其他數據從緩存中替換出來,這回減慢接來下來的查詢。
這個問題需要被解決。
索引的選擇
首先需要自己問自己一個問題:我們是否需要短語查詢呢?
通常情況下,答案是不需要!index_options讓我們來控制在索引中需要保存那些信息 。
- docs. 僅僅保存含有某些特定詞的文檔
- freqs。保存文檔的信息,詞頻等,用來計算tf/idf
- positions. 不在多說
- offsets。
代碼如下:
PUT /my_index
{
"mappings": {
"my_type": {
"properties": {
"title": {
"type": "string"
},
"content": {
"type": "string",
"index_options": "freqs"
}
}
}
}
停用詞
移除停用詞是一個非常有力的減少位置數據的辦法。一個被移除停用詞的索引依然可以用來短語查詢,是因爲剩下詞的位置依然保存着,但是,移除的停用詞不再能搜索到。舉個例子,我們將不能區別 man in the moom 和 man on the moon.
幸運的是,我們還是有辦法解決。
這篇就先說到這裏~~~希望大家玩的開心