需求
雪花啤酒 需要搜索雪花、啤酒 、雪花啤酒、xh、pj、xh啤酒、雪花pj
ik導入
參考https://www.cnblogs.com/LQBlog/p/10443862.html,不需要修改源碼步驟就行
拼音分詞器導入
跟ik一樣 下載下來打包移動到es plugins 目錄名字改為pinyin https://github.com/medcl/elasticsearch-analysis-pinyin
測試
get請求:http://127.0.0.1:9200/_analyze
body:
{ "analyzer":"pinyin", "text":"雪花啤酒" }
響應:
{ "tokens": [ { "token": "xue", "start_offset": 0, "end_offset": 0, "type": "word", "position": 0 }, { "token": "xhpj", "start_offset": 0, "end_offset": 0, "type": "word", "position": 0 }, { "token": "hua", "start_offset": 0, "end_offset": 0, "type": "word", "position": 1 }, { "token": "pi", "start_offset": 0, "end_offset": 0, "type": "word", "position": 2 }, { "token": "jiu", "start_offset": 0, "end_offset": 0, "type": "word", "position": 3 } ] }
說明導入成功
測試中文加拼音搜索
自定義mapping和自定義分詞器
put請求:http://127.0.0.1:9200/opcm3
body:
{ "settings": { "analysis": { "analyzer": { "ik_pinyin_analyzer": {//自定義一個分詞器名字叫ik_pinyin_analyzer "type": "custom",//表示自定義分詞器 "tokenizer": "ik_smart",//使用ik分詞 ik_smart為粗粒度分詞 ik_max_word為最細粒度分詞 "filter": ["my_pinyin"]//分詞后結果 交給過濾器再次分詞 }, "onlyOne_analyzer": { "tokenizer": "onlyOne_pinyin" } }, "tokenizer": { "onlyOne_pinyin": { "type": "pinyin", "keep_separate_first_letter": "true", "keep_full_pinyin":"false" } },"filter": { "my_pinyin": {//定義過濾器 "type": "pinyin", "keep_joined_full_pinyin": true,//分詞的時候詞組首字母分詞后組合 如:雪花 分詞:xuehua xh "keep_separate_first_letter": true//分詞的時候支持首字母不單獨分詞如:會分詞xue hua xuehua xh x,h "none_chinese_pinyin_tokenize": true//xh 分詞為x,h,xh } } } }, "mappings": { "doc": { "properties": { "productName": { "type": "text", "analyzer": "ik_pinyin_analyzer",//指定分詞索引為自定義分詞 中文分詞后再通過filter交給pinyin分詞 "fields": {//暫時未用 只是保留讓 自己能夠知道有這種方式根據不同條件選擇不同的搜索分詞 "keyword_once_pinyin": {//新的分詞字段 只分詞不存在source productName.keyword_once_pinyin 查詢時需要判斷如果是單字母使用此搜索 "type": "text", "analyzer": "onlyOne_analyzer" } } } } } } }
filter個人理解
我的理解是 ik分詞 然后將分詞后的逐項結果通過filter交給拼音分詞 雪花啤酒 ik會分成 雪花,啤酒 然后雪花交給pinyin會分詞 xue,hua,xh,x,h 啤酒會分詞 pi,jiu,p,j
插入測試數據
http://127.0.0.1:9200/opcm3/doc/1
{ "productName":"雪花純生勇闖天涯9度100ml" }
put請求:http://127.0.0.1:9200/opcm3/doc/2
body:
{ "productName":"金威純生勇闖天涯9度100ml" }
查看分詞結果
get請求:http://127.0.0.1:9200/opcm3/topic/{id}/_termvectors?fields=productName
get請求:http://127.0.0.1:9200/opcm3/topic/{id}/_termvectors?fields=productName.keyword_once_pinyin
測試搜索
http://127.0.0.1:9200/opcm3/_search
{ "query":{ "match_phrase":{ "productName":{ "query":"雪花純生" } } } }
會查出雪花純生和金威純生 看個人是模糊匹配還是相鄰匹配 選用match或者match_phrase
我的需求是相鄰匹配改為
{ "query":{ "match_phrase":{ "productName":{ "query":"雪花純生" } } } }
則只會搜索出雪花純生
搜索雪花純生9度的產品
{ "query":{ "match_phrase":{ "productName":{ "query":"雪花純生9度" } } } }
會發現搜索不出來數據
原因請查閱:https://www.cnblogs.com/LQBlog/p/10580247.html
改為就能搜索出來:
{ "query":{ "match_phrase":{ "productName":{ "query":"雪花純生9度", "slop":5 } } } }
pingpin分詞還支持很多參數 比如:
以上模型排查及解決
添加測試數據
{
"productName":"純生"
}
{
"productName":"純爽"
}
測試
搜索
{ "query":{ "match_phrase":{ "productName":{ "query":"純生", "slop":5 } } } }
返回結果
{ "took": 3, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 2, "max_score": 2.8277423, "hits": [ { "_index": "opcm3", "_type": "doc", "_id": "1", "_score": 2.8277423, "_source": { "productName": "純爽" } }, { "_index": "opcm3", "_type": "doc", "_id": "2", "_score": 1.4466299, "_source": { "productName": "純生" } } ] } }
可以發現純爽也出來了
排查
1.查看純爽分詞結果
http://127.0.0.1:9200/opcm3/doc/2/_termvectors?fields=productName
[c,chun,s,sheng]
[c,chun,s,shuang]
2.查看搜索分詞
http://127.0.0.1:9200/opcm3/_validate/query?explain { "query":{ "match_phrase":{ "productName":{ "query":"純生", "slop":5 } } } }
body
{ "valid": true, "_shards": { "total": 1, "successful": 1, "failed": 0 }, "explanations": [ { "index": "opcm3", "valid": true, "explanation": "productName:\"(c chun) (s sheng)\"~5" } ] }
可以理解為index=(c or chun) and (s or shuang)
所以c,s 匹配了純爽
解決辦法
分詞按最小粒度分 搜索 按最大粒度分
如純生文檔分詞為[chun,sheng,chun,sheng,cs,c,s]
搜索分詞為[chun,sheng,chunsheng]
一下模型就能滿足搜索: 雪花,雪花cs ,雪花chunsheng ,xhcs,xh純生,雪花純生 都能正確搜索出數據
{ "settings": { "analysis": { "analyzer": { "ik_pinyin_analyzer": { "type": "custom", "tokenizer": "ik_smart", "filter": ["pinyin_max_word_filter"] }, "ik_pingying_smark": { "type": "custom", "tokenizer": "ik_smart", "filter": ["pinyin_smark_word_filter"] } }, "filter": { "pinyin_max_word_filter": { "type": "pinyin", "keep_full_pinyin": "true",#分詞全拼如雪花 分詞xue,hua "keep_separate_first_letter":"true",#分詞簡寫如雪花 分詞xh "keep_joined_full_pinyin":true#分詞會quanpin 連接 比如雪花分詞 xuehua }, "pinyin_smark_word_filter": { "type": "pinyin", "keep_separate_first_letter": "false",#不分詞簡寫如雪花 分詞不分詞xh "keep_first_letter":"false"#不分詞單個首字母 如雪花 不分詞 x,h } } } }, "mappings": { "doc": { "properties": { "productName": { "type": "text", "analyzer": "ik_pinyin_analyzer",#做文檔所用的分詞器 "search_analyzer":"ik_pingying_smark"#搜索使用的分詞器 } } } } }