Elasticsearch 5.4:使用Java Client API获取字段去重值及查询问题
解决Elasticsearch 5.4获取字段去重值的问题
嘿,我来帮你搞定这个ES 5.4里获取字段去重值的问题~先分析你当前查询失效的可能原因,再给出靠谱的解决方案和Java API实现方式。
一、先排查查询没生效的常见坑
- 字段类型踩坑:如果你的
status字段是text类型,默认会被分词处理,直接用terms聚合拿到的会是分词后的碎片,不是你想要的原始去重值。这时候得确认字段有没有对应的keyword子字段(ES 5.x默认会给text字段自动生成这个子字段,除非你手动关了),或者考虑开启fielddata(但这个不推荐,太占内存)。 - 语法小细节:你的查询JSON要确保格式完全正确,比如括号、逗号不能漏,请求体要和
GET请求匹配好。
二、正确的DSL查询写法
情况1:用keyword子字段(最推荐)
如果status字段有自动生成的keyword子字段,直接针对这个子字段做聚合就能拿到正确的去重值:
GET /index/index_type/_search { "size": 0, "aggs": { "distinct_status": { "terms": { "field": "status.keyword", "size": 10000 // 要是去重值多,得设足够大的数,默认只返回前10个 } } } }
情况2:字段是keyword类型/不得不开启fielddata
如果status本身就是keyword类型,直接用field: "status"就行;要是是text类型且必须用原始字段聚合(不推荐生产环境这么干),先更新字段映射打开fielddata:
PUT /index/_mapping/index_type { "properties": { "status": { "type": "text", "fielddata": true } } }
然后再执行查询(记得加size参数):
GET /index/index_type/_search { "size": 0, "aggs": { "distinct_status": { "terms": { "field": "status", "size": 10000 } } } }
三、Java Client API(ES 5.4 TransportClient)实现
下面是用ES 5.4官方的TransportClient获取去重值的代码示例,直接就能用:
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.transport.client.PreBuiltTransportClient; import java.net.InetAddress; import java.net.UnknownHostException; public class EsDistinctDemo { public static void main(String[] args) throws UnknownHostException { // 初始化客户端 Settings settings = Settings.builder() .put("cluster.name", "你的集群名") .build(); try (TransportClient client = new PreBuiltTransportClient(settings) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300))) { // 构建查询和聚合 SearchResponse response = client.prepareSearch("index") .setTypes("index_type") .setQuery(QueryBuilders.matchAllQuery()) // 可以换成你自己的查询条件 .setSize(0) // 不返回原始文档,只拿聚合结果 .addAggregation( AggregationBuilders.terms("distinct_status") .field("status.keyword") .size(10000) ) .get(); // 解析聚合结果 Terms termsAgg = response.getAggregations().get("distinct_status"); for (Terms.Bucket bucket : termsAgg.getBuckets()) { String distinctVal = bucket.getKeyAsString(); long count = bucket.getDocCount(); System.out.println("去重值:" + distinctVal + ",出现次数:" + count); } } catch (Exception e) { e.printStackTrace(); } } }
额外提醒
- size参数别忘:
terms聚合默认只返回前10个桶,要是你的去重值很多,一定要设足够大的size,不然会丢数据。 - 性能考量:如果去重值数量特别大(比如百万级),
terms聚合可能会拖慢集群,这时候可以先用cardinality聚合统计去重总数,或者用滚动查询结合客户端去重(ES 5.4还没Composite聚合,这个是6.x之后才有的)。
内容的提问来源于stack exchange,提问作者YK mar
相关产品推荐
相关产品推荐

