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 以后的版本才可以使用这两个类型。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alphathur

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值