ElasticSearch使用text类型字段排序报错

在使用 ElasticSearch 进行查询时,排序是相当常见的一种操作。不过,一般情况下,我们都会对数字、日期类型等进行排序,较少直接对 text 类型进行排序。今天偶然遇到了需要对 text 类型进行排序的情况,就一不小心掉坑里了,这边记录下解决方法。

问题还原

我们的问题是,对 text 类型进行排序时,ES 会报错。

错误内容形如:

1
2
3
Fielddata is disabled on text fields by default.  Set `fielddata=true` on
[`your_field_name`] in order to load fielddata in memory by uninverting the
inverted index. Note that this can however use significant memory.

解决问题

默认的 text 类型字段的 mapping 大概是这样的。

1
2
3
{
"dm": { "type": "text" }
}

根据上面的错误信息,我们可以去 ES 的文档中查一下Fielddata这个属性的说明。

fielddata mapping parameter

fielddata mapping parameter

按照官方的说明,text 类型的字段默认不支持聚合、排序等操作,此时如果进行聚合、排序等操作就会出现上文所示的错误信息。

第一种方法

那么,第一种启用 text 字段的聚合、排序等操作的方法也就清楚了,就是在 mapping 中将fielddata设置为true,此属性默认为false。这样,就能对该 text 字段进行常规的聚合、排序等操作了。

1
2
3
4
5
6
7
8
{
"properties": {
"my_field": {
"type": "text",
"fielddata": true
}
}
}

不过需要注意的是,启用fielddata会将数据存储到程序的堆中,可能会带来性能、内存使用量增大等问题,这通常是没有必要的。

第二种方法【推荐】

Before enabling fielddata

为了解决上面提到的性能和资源的浪费,官方更推荐使用多字段映射的方式。也就是一方面保留原字段来进行全文搜索,另一方面使用一个未做处理的keyword字段来进行聚合、排序等操作。配置方法如下示例所示。

1
2
3
4
5
6
7
8
9
10
11
12
{
"properties": {
"my_field": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}

在这样配置以后,在进行搜索时使用my_field字段,在进行聚合、排序等操作时使用my_field.keyword字段,这样能够比直接启用fielddata获得更好的性能表现。