從對之前作法的 Review 中,大致可以總結以下幾個可以改善的地方:
第 1 點在官方文件中有提到 significant-text aggregation 應該要搭配 sampler 一起用,也就是並非對全部的資料進行計算,而是只計算經過抽樣的資料,這樣可以解決搜尋效率的問題。
第 2 點其實我們只要把所有的搜尋字加入 suggestion 部分的 query, 讓 aggregation 的範圍限制在有符合搜尋字的資料中,讓 suggestion 和搜尋字的關聯更強烈,在應該可以解決某個程度上建議字比較單一的問題:
我們試試看在原本的方法做以下的修改:
修改後的 query 和 python 查詢 script:
import elasticsearch
import itertools
import re
def get_token_compelete(kw_phrase, index_name):
tail = re.findall("\S+", kw_phrase)[-1] # 取得最後沒有打完的那個字
query_to_compelete = {
"query": {
"prefix": {
"tweet": {
"value": tail
}
}
},
"aggregations": {
"my_sample": {
"sampler": {
"shard_size": 1000
},
"aggregations": {
"find_the_whole_token": {
"significant_text": {
"field": "tweet",
"include": f"{tail}.+",
"min_doc_count": 10,
"size": 2
}
}
}
}
},
"fields": ["aggregation"],
"_source": False
}
r = es_cli.search(index=index_name, body=query_to_compelete)
buckets = r["aggregations"]["my_sample"]["find_the_whole_token"]["buckets"]
tokens = [bucket["key"] for bucket in buckets]
return tokens
def get_suggestion(search_phrase, index_name):
suggestion_query = {
"query": {
"match": {
"tweet": search_phrase
}
},
"aggregations": {
"my_sample": {
"sampler": {
"shard_size": 1000
},
"aggregations": {
"tags": {
"significant_text": {
"field": "tweet",
"exclude": search_phrase.split(" "),
"min_doc_count": 10,
"size": 3
}
}
}
}
}
}
r = es_cli.search(index=index_name, body=suggestion_query)
buckets = r["aggregations"]["my_sample"]["tags"]["buckets"]
suggestions = [bucket["key"] for bucket in buckets]
return suggestions
def get_auto_complete(search_phrase):
pre_search_phrase = " ".join(re.findall("\S+", search_phrase)[0:-1])
comelete_tokens = get_token_compelete(search_phrase, index_name)
guess = []
for token in comelete_tokens:
compelete_search_prahse = " ".join([pre_search_phrase, token])
suggestions = get_suggestion(compelete_search_prahse, index_name)
if not suggestions:
guess.append(token)
for suggestion in suggestions:
guess.append(" ".join([compelete_search_prahse, suggestion]).strip())
return guess
es_cli = elasticsearch.Elasticsearch("http://localhost:9200")
index_name = 'covid19_tweets'
search_phrase = "syn"
print(get_auto_complete(search_phrase))
稍微說明一下 sampler 的 shard_size
參數,代表的是每一個 shard 要取出幾分篩選後分數最高的資
料;因爲我使用的環境是單一節點,也只有一個 shard,所以就是我要取分數最高的前多少筆的意思。
加了 sampler 之後,搜尋的速度有明顯的提升,然 suggestion 的部分使用跟前一版的測試相同案例,結果如下:
輸入: cov
輸出:['covid19 stayathome', 'covid19 thelockdown', 'covid19 coronavirus', 'covid 19']
輸入: covid
輸出:['covid19 stayathome', 'covid19 thelockdown', 'covid19 coronavirus', 'covid_19 coronavirus', 'covid_19 coronaupdate', 'covid_19 evirahealth']
輸入: covid sym
輸出:['covid symptoms mild', 'covid symptoms 19', 'covid symptoms showing', 'covid symptom 19']
似乎只有最後一個有顯著的差異,看起來是有比較好一點(就一點點 XD)
關於主題的部分今天先到這邊,下一篇會繼續看有什麼優化可以進行。
這是鐵人賽的第 17 篇文章,也就是我連續寫了第 17 天的文章,第一天雖然有發文,但因為技術問題(用手機發文不知道為什麼沒有發成鐵人賽的文),再加上中間有一天確實是過了 12 點才發(純粹是忘記了),已經沒有領取完賽證明的資格了。
大概在第 10 天時已經沒有存稿了,所以每天都是當天寫的,最近幾天的內容更是邊寫邊研究作法,研究不太順利的時候真是壓力山大 Q Q,往回看發現好像理解錯了的時候也壓力山大 Q Q,覺得有在定期寫文章的大大們都太厲害了。
總之,如果內容有什麼錯誤,不論是筆誤、覺得我理解錯誤、覺得我根本胡言亂語,都希望有看到這邊的朋友盡量跟我說,希望可以有更正的機會;然,如果你是跟這個主題不熟的朋友,請抱持著質疑的心看這些文章,有什麼覺得不太合理的、不明白的,也歡迎發問,感激不盡。