开启fielddata后Elasticsearch获取字段唯一值异常求助
解决Elasticsearch聚合text字段时被拆分的问题
你的问题根源在于vip_name是text类型字段,这类字段默认会被分词器(比如标准分词器)拆分内容——像你的域名ppcbcl00021.domain.com会被拆成ppcbcl00021和domain.com两个独立的词,所以即使开启了fielddata,聚合的也是分词后的碎片,而非完整的原始值。
正确的解决方法(优先推荐第一种)
1. 使用字段的keyword子字段聚合
很多时候创建text字段时,Elasticsearch会自动生成一个同名的keyword子字段(专门用于精确匹配、聚合和排序)。你可以直接聚合这个子字段:
curl -XGET http://172.31.38.157:9200/cb_inventory/_search?pretty=true -d '{ "size":0, "aggs":{ "vips":{ "terms":{ "field":"vip_name.keyword", "size":1000 } } } }'
这样就能得到完整的ppcbcl00021.domain.com作为唯一聚合值了。
2. 手动添加keyword子字段(如果没有自动生成)
如果你的mapping里没有vip_name.keyword,可以先更新mapping添加这个子字段:
curl -XPUT http://172.31.38.157:9200/cb_inventory/_mapping -d '{ "properties":{ "vip_name":{ "type":"text", "fields":{ "keyword":{ "type":"keyword", "ignore_above":256 } } } } }'
注意:更新mapping后,旧数据不会自动生成keyword子字段的值,你需要重新索引现有数据(比如用Elasticsearch的_reindex API),之后再用vip_name.keyword执行聚合查询。
3. 将字段改为keyword类型(不推荐,除非不需要全文搜索)
如果这个字段不需要做全文搜索,你可以把它改成keyword类型,但这需要重建整个索引(因为Elasticsearch不允许直接修改已有字段的类型):
- 先创建一个新索引,把
vip_name设为keyword类型 - 用
_reindexAPI把旧索引的数据迁移到新索引 - 之后用新索引执行聚合查询
为什么不推荐开启fielddata?
开启fielddata虽然能让text字段支持聚合,但它是把分词后的词加载到内存中,不仅会占用大量内存,而且本质上还是聚合分词后的碎片,解决不了你需要完整值的需求。而keyword字段是存储原始的完整值,磁盘存储更高效,也能直接满足精确聚合的需求。
内容的提问来源于stack exchange,提问作者user2405589




