很多情況下,我們希望在搜索時,有時能夠使用一個詞的同義詞來進行補充搜索,這樣我們能搜索出來更多相關的內(nèi)容。這個場景可以通過 text analysis 來幫助我們生成同義詞。那么在進行同義詞搜索時,我們有如下的幾種方案:
通過修改setting配置同義詞
首先,我們來創(chuàng)建一個具有如下 anaylzer 及 mapping 的一個索引:
PUT myindex
{
"settings": {
"analysis": {
"filter": {
"my_synonyms": {
"type": "synonym_graph",
"synonyms": [
"清新,可愛,動漫,粉色,浪漫"
]
}
},
"analyzer": {
"my_analyzer": {
"type": "custom",
"tokenizer": "ik_max_word",
"filter":[
"lowercase",
"my_synonyms"
]
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "my_analyzer"
}
}
}
}
在上面,我們使用 synonym_graph 過濾器對 quey 時的詞進行過濾。在這個過濾器中,我們把如下的一個詞都視為同義詞:
清新,可愛,動漫,粉色,浪漫
在mapping 中,我們定義了 search_analyzer 為 my_analyzer,也就是說在 query 時,它會對所有的詞進行分詞。但凡有任何一個詞是 '清新,可愛,動漫,粉色,浪漫' 其中的一個,它都將被視為同義詞。
我們首先來創(chuàng)建一個文檔:
PUT myindex/_doc/1
{
"title": "通用清新粉色高端醫(yī)院美容企業(yè)春暖花開職等你來招聘"
}
運行上面的指令,我們將創(chuàng)建一個 title 為 '通用清新粉色高端醫(yī)院美容企業(yè)春暖花開職等你來招聘' 的文檔。
接下來,我們做如下的查詢:
GET myindex/_search
{
"query": {
"match": {
"title": "粉色"
}
}
}
那么顯示的結果是:
{
"took" : 256,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.4384104,
"hits" : [
{
"_index" : "myindex",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.4384104,
"_source" : {
"title" : "通用清新粉色高端醫(yī)院美容企業(yè)春暖花開職等你來招聘"
}
}
]
}
}
可能有人說了,這是因為上面的 title 里本身就含有 '粉色', 所以上面的結果證明不了什么。接下來,我們進行如下的搜索:
GET myindex/_search
{
"query": {
"match": {
"title": "浪漫"
}
}
}
結果,我們可以發(fā)現(xiàn),我們同樣顯示上面的搜索的結果。這個說明了這個同義詞的搜索是成功的。
接下來,我們想通過搜索 '素雅' 也能搜索出'清新'來,那么我怎么做呢?
我們來執(zhí)行如下的命令:
POST myindex/_close
PUT myindex/_settings
{
"analysis": {
"filter": {
"my_synonyms": {
"type": "synonym_graph",
"synonyms": [
"清新,素雅,可愛,動漫,粉色,浪漫"
]
}
},
"analyzer": {
"my_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"my_synonyms"
]
}
}
}
}
POST myindex/_open
我們可以通過更新 setting 來實現(xiàn)這個。在上面請注意:當我們更新一個索引的 index 時,我們必須先把它關掉,等設置好后,在重新打開。否則會有錯誤。那么經(jīng)過上面的修改后,我們重新運行如下的搜索:
GET myindex/_search
{
"query": {
"match": {
"title": "素雅"
}
}
}
那么上面的搜索結果將會顯示我們之前顯示的結果。在這里 ‘素雅’ 也就是和之前的其它詞都是同義詞。
通過修改文件配置同義詞
有人可能覺得上面在 settings 里配置太多的同義詞很麻煩,而且關閉索引會影響線上查詢(可以放到凌晨進行)。按照 Elastic 的官方文檔,我們可以把所有的同義詞放到一個文檔中。首先,我們在 Elasticsearch 的 config 目錄中,創(chuàng)建一個叫做 analysis 的子目錄,然后創(chuàng)建一個叫做 synonyms.txt 的文檔,而它的內(nèi)容如下:
$ pwd
/Users/liuxg/elastic/elasticsearch-7.8.0/config/analysis
$ cat synonyms.txt
"清新,素雅,可愛,動漫,粉色,浪漫",
"elk, elastic stack"
在這里,我們多添加了一個 elk, elastic stack 的同義詞。我們來創(chuàng)建一個新的索引:
PUT myindex1
{
"settings": {
"analysis": {
"filter": {
"my_synonyms": {
"type": "synonym_graph",
"synonyms_path": "analysis/synonyms.txt"
}
},
"analyzer": {
"my_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter":[
"lowercase",
"my_synonyms"
]
}
}
}
},
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "standard",
"search_analyzer": "my_analyzer"
}
}
}
}
運行完上的指令后,我們來創(chuàng)建一個文檔:
PUT myindex1/_doc/1
{
"content": "I love elastic stack"
}
然后我們做如下的搜索:
GET myindex1/_search
{
"query": {
"match": {
"content": "elk"
}
}
}
上面的搜索結果顯示:
{
"took" : 451,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.5753642,
"hits" : [
{
"_index" : "myindex1",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.5753642,
"_source" : {
"content" : "I love elastic stack"
}
}
]
}
}
顯然,我可以看到搜索 elk,我們就可以搜索到含有 elastic stack 的文檔。
在實際的使用中,如果我們更新 synonyms.txt 文件,那么,我們可以使用如下的 API 來進行更新:
POST myindex1/_reload_search_analyzers
總結
在上面,我們展示了兩種方法進行同義詞的查詢。在實際的使用中,你可以根據(jù)自己的情況適當進行選擇。當然,我們有可以把上面的兩種方法進行同時并用。通過這兩種方法,也有可能會造成搜索的精確度的問題。這個是你必須要想清楚的。這個就像我們?nèi)鼍W(wǎng)打魚一樣,把網(wǎng)撒大了,撈上來的也有可能不是我們想要的。
需要注意的是如果我們想在索引階段就對同義詞token進行索引的話,那么需要使用synonym分析器而不是synonym_graph