需求
如果我们需要根据一个字段进行排序,如何支持呢?
像日期、价格这些数值型的(日期底层其实是转换为数值),排序其实是很自然也是很简单的。但是如果是字符串类型的字段呢?有几个问题需要考虑:
- 分词对排序的影响
- 大小写、单复数之类区别
字符串类型的字段一般都需要进行搜索的,那么需要对其进行Analyzed。但是Analyzed的结果就是将该字符串解析为分散的token(term)。这样子,ES就不知道到底是根据那个term来排序,事实上根据哪一个都是错的,应该是整个字符串。所以为了对字符串类型字段进行排序,需要保存整个字符串为一个term——也就是说保存一个not_analyzed string。同时为了保证该字段能够被搜索,还要保存该字符串analyzed的结果。
The naive approach to indexing the same string in two ways would be to include two separate fields in the document: one which is analyzed for searching, and one which is not_analyzed for sorting.
ES提供了一个便利的机制——multi-field mapping,可以让我们简单配置一下达到这个目的:
"tweet": { // 1
"type": "string",
"analyzer": "english",
"fields": {
"raw": { // 2
"type": "string",
"index": "not_analyzed"
}
}
}
- The main tweet field is just the same as before: an analyzed full text field.
- The new tweet.raw sub-field is not_analyzed.
现在,我们可以通过tweet字段作为搜索,而用tweet.raw字段作为排序:
GET /_search
{
"query": {
"match": {
"tweet": "elasticsearch"
}
},
"sort": "tweet.raw"
}
但是依赖于额外的not_analyzed字段进行排序也有局限性——它只能完全匹配原始字符串,如果稍微有大小写、单复数之类的区别,会被单做不同的值的。如何处理这种情况呢?得益于Lucene Analyzer的pipeline机制,只要简单配置一下就可以了,比如使用如下配置可以组建一个emit a single lower case token的分析器:
PUT /my_index
{
"settings": {
"analysis": {
"analyzer": {
"case_insensitive_sort": {
"tokenizer": "keyword",
"filter": [ "lowercase" ]
}
}
}
}
}
然后我们可以这样子使用:
PUT /my_index/_mapping/user
{
"properties": {
"name": {
"type": "string",
"fields": {
"lower_case_sort": { // 1
"type": "string",
"analyzer": "case_insensitive_sort"
}
}
}
}
}
- The name.lower_case_sort field will provide us with case-insentive sorting.
ES还提供了unicode sorting: unicode collation algorithm。
参考文档
本文由 arganzheng 创作,采用 CC BY 4.0 许可协议。在保留原文作者、署名以及完整原文链接(https://arganzheng.life/sorting-in-elasticsearch.html)的前提下,欢迎各种形式的转载、翻译或商业引用。
YOU MIGHT ALSO LIKE
- 23 Jan 2018 » ElasticSearch的节点类型
- 10 Jan 2018 » ElasticSearch如何支持深度分页
- 28 Dec 2017 » ElasticSearch如何支持嵌套属性检索
OUTLINE
没有匹配的标题
COMMENTS
评论存放在 GitHub Discussions, 用 GitHub 账号登录即可发表,支持 Markdown。 想针对正文某句话说?选中那段文字,点浮出的「评论」即可划线评论;觉得哪里写错了,发表时勾上「同时提交 Issue」。 有人回复你时 GitHub 会按你的通知设置发邮件,不用守在这里。