ElasticSearch 2.4.X實現中文拼音排序

前言

最近接到一個需求,要求實現搜索框的搜索結果可以按照中文排序,本人靈機一動,那不很簡單嗎,直接按照es自帶的sort功能處理下不就行了嗎?兩分鐘的代碼量,半天的喝茶時間,白賺半天的故事點,嘿嘿。

然而問題纔剛剛開始,多次測試結果表明,當文本以中文開頭,排序結果總是不正確。翻閱資料才知道這麼一回事:ES是用的unicode的字節碼做排序的。即先對字符(包括漢字)轉換成byte[]數組,然後對字節數組進行排序。這種排序規則對ASIC碼(英文)是有效的,但對於中文等亞洲國家的字符不適用。

作爲一個es小白,對這塊懂的還是太少了。沒辦法,只要了半天的故事點,這次真是把自己給坑了。還好是週末可以抽點時間研究,說幹就幹,搗鼓了一番,終於明白要實現拼音排序功能得依靠一個es插件-拼音分詞器。

切入正文,以下是個demo,演示了拼音排序的具體實現方案。

1.準備實驗數據

數據下載鏈接: https://pan.baidu.com/s/1X6qA_dI4Jz2V0ihDWhUjzQ 密碼:gjcv

數據來源於官網:https://download.elastic.co/demos/kibana/gettingstarted/accounts.zip

因爲官網數據沒有中文字段,所以我做了修改,增加了fullName字段,並將其中200條數據的fullName設置爲中文,其餘數據的fullName設置爲原始數據的firstname+lastname。

2.準備拼音分詞器

需要下載拼音分詞器插件,下載地址: https://github.com/medcl/elasticsearch-analysis-pinyin/ ,根據當前elasticsearch版本找到對應的release版本進行下載。在elasticsearch安裝目錄的plugins下新建文件夾pinyin, 將分詞器壓縮包的所有文件解壓到這個pinyin文件夾。

注意:

1.如果你還不知道當前es版本,訪問 http://localhost:9200/ ,version對象的number就是版本。

2.如果你沒找到對應的release版本,就找離當前es版本最近的,然後修改plugin-descriptor.properties文件,設置elasticsearch.version爲自己的es版本號。

3.必須重啓es,如果插件安裝成功則不會報錯。

3.創建索引,設置mapping,導入數據並測試。

如果你不喜歡敲命令,則用postman來提交請求。我放上了每一步的截圖,並粘貼了每一步需要的請求參數。直接按照流程一步一步走即可。

如果習慣用macos,linux敲命令的同學,直接在終端通過curl來提交請求即可。命令我已經總結好,直接運行即可。(ps:windows對curl命令相當不友好,需要用轉義符 / 來轉義請求參數中的雙引號。) 

  • 使用postman 

1.創建索引並設置分詞器

定義索引爲actor,使用了拼音分詞器,分詞器的各項參數功能見官方文檔,這裏只用到了部分參數。

URL和ReqeustBody:

http://localhost:9200/actor
{
    "index" : {
        "analysis" : {                          
            "analyzer" : {
               "pinyin_analyzer" : {          
                     "tokenizer" : "my_pinyin"
               }
            },
            "tokenizer" : {
                "my_pinyin" : {                    
                    "type": "pinyin",
                    "keep_first_letter": false,
                    "keep_full_pinyin": false,
                    "keep_joined_full_pinyin": true,
                    "keep_none_chinese_in_joined_full_pinyin": true,
                    "keep_none_chinese_in_first_letter": true,
                    "none_chinese_pinyin_tokenize": false,
                    "lowercase": true
                 }
            }
        }
    }
}

2.設置mapping

定義了文檔類型爲account,且對fullName字段使用分詞器。

URL和RequestBody:

http://localhost:9200/actor/account/_mapping
{
    "account": {
        "properties": {
            "fullName": {
                "type": "string",
                "analyzer": "pinyin_analyzer",
                "fields": {
                    "keyword": {
                        "type": "string",
                        "ignore_above": 256
                    }
                }
            }
        }
    }
}

3.測試分詞器

直接調用es的分詞器接口_analyze,測試對文檔‘李雲龍’的分詞效果。

URL和RequestBody:

http://localhost:9200/actor/_analyze
{
  "analyzer": "pinyin_analyzer",
  "text": "李雲龍"
}

從返回結果可以看出分詞效果爲liyunlong,這確實是正確的,且tokens數組只返回一個元素,只有這種情況下,中文拼音排序纔是準的,否則不準。

4.導入實驗數據

URL:

http://localhost:9200/actor/account/_bulk

5.測試排序效果

URL和RequestBody:

http://localhost:9200/actor/account/_search
{
    "from": 0,
    "size": 50,
    "sort": [
        {
            "fullName": {
                "order": "desc",
                "unmapped_type": "string"
            }
        }
    ]
}

部分返回結果如下圖:

可以看出,fullName的拼音以z開頭的數據排在了最前面,這恰好符合預期,證明實驗成功。

  • 使用curl

1.創建索引並設置分詞器

curl -XPUT http://localhost:9200/actor -d '
{
    "index": {
        "analysis": {
            "analyzer": {
                "pinyin_analyzer": {
                    "tokenizer": "my_pinyin"
                }
            },
            "tokenizer": {
                "my_pinyin": {
                    "type": "pinyin",
                    "keep_first_letter": false,
                    "keep_full_pinyin": false,
                    "keep_joined_full_pinyin": true,
                    "keep_none_chinese_in_joined_full_pinyin": true,
                    "keep_none_chinese_in_first_letter": true,
                    "none_chinese_pinyin_tokenize": false,
                    "lowercase": true
                }
            }
        }
    }
}'

2.創建mapping

curl -XPUT http://localhost:9200/actor/account/_mapping -d '
{
    "account": {
        "properties": {
            "fullName": {
                "type": "string",
                "analyzer": "pinyin_analyzer",
                "fields": {
                    "keyword": {
                        "type": "string",
                        "ignore_above": 256
                    }
                }
            }
        }
    }
}'

3.測試分詞器

curl -XPOST http://localhost:9200/actor/_analyze -d'{
  "analyzer": "pinyin_analyzer",
  "text": "李雲龍"
}'|json_pp

4.導入實驗數據

curl -XPOST 'localhost:9200/actor/account/_bulk?pretty' --data-binary @new_account.json

5.測試排序

curl -XPOST http://localhost:9200/actor/account/_search -d'
{
    "from": 0,
    "size": 50,
    "sort": [
        {
            "fullName": {
                "order": "desc",
                "unmapped_type": "string"
            }
        }
    ]
}
'|json_pp

注意:json_pp用來美化json格式的輸出結果,如果你的環境沒有這個工具則去掉 | json_pp 這條指令即可。

後記

由於是客戶方是銀行,es版本相當老,仍然是2.4.6版本,所以es的字段類型沒有用到keyword和text,這種字段早期版本是不支持的,5.X 以後的版本纔可以使用這兩個類型。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章