赞
踩
最近的实际中业务中,要对用户订单数据进行统计,用户订单数据从用户下单到支付的过程都会记录,同时每次用户订单查看也会产生一次订单更新数据,但是由于历史原因,用户订单更新数据入库没有进行整理,都是直接把订单相关的数据存入es。今天某项数据分析需要对用户订单进行查询并去重做一些针对订单维度的分析。
一般关系型数据库去重统计直接sql中的distinct函数就可以实现,
获取统计去重后的数量:
select distinct(count(1)) from order;
获取去重后的结果:
select distinct order_id from order;
获取统计去重后的数量一般使用Cardinality聚合函数,DSL样例如下:
GET /index_name/_search { "size": 1, "_source": { "includes": ["设置需要的返回字段"], "excludes": [] }, "query": { "bool": { "设置查询条件": "使用term/terms/filter等" } }, "aggregations": { "cardinality_field": { "cardinality": { "field": "设置根据哪个字段进行去重" } } } }
上述DSL执行返回:
{ "took": 7, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 3, "max_score": null, "hits": [ ] }, "aggregations": { "cardinality_field": { "value": 1 } } }
从执行结果可以看到,查询结果是3条数据,通过某字段进行聚合去重后只有一条符合,同时我们也发现通过这样 Cardinality 聚合函数我不知道具体是那条数据符合要求。
Java-api使用:
jar包:
<!-- https://mvnrepository.com/artifact/org.elasticsearch.client/transport -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>根据自己使用版本设置</version>
</dependency>
Java代码:
//构造DSL
cardinalityBuilder = AggregationBuilders.cardinality("uid_aggs").field("orderId");
SearchRequestBuilder request = client.prepareSearch("XXXX")
.setTypes("XXX")
.setSearchType(SearchType.QUERY_THEN_FETCH)
.setQuery(QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("orderId", "")))
.addAggregation(cardinalityBuilder)
.setSize(1);
//获取返回结果
SearchResponse response = request.execute().actionGet();
获取去重后的结果:5.3版本之前只有top_hits聚合,但5.3以上的版本仍然可用,DSL如下:
POST /index_name/ { "size": 0, "query": { "bool": { } }, "aggregations": { "uid_top": { "top_hits": { "sort": [{ "orderId": { "order": "desc" } }], "size": 1, "_source": { "includes": [ "orderId" ], "excludes": [] } } } } }
上述DSL中我对去重后的结果返回字段进行了设置,执行返回:
{ "took": 4, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 3, "max_score": 0, "hits": [] }, "aggregations": { "uid_top": { "hits": { "total": 3, "max_score": null, "hits": [ { "_index": "", "_id": "", "_score": null, "_source": { "order_id": "" }, "sort": [ "" ] } ] } } } }
java-api参考:
//在聚合中进行设置:
AggregationBuilder aggregationBuilder = AggregationBuilders.terms("orderId_aggs").field("orderId").size(10000).subAggregation(AggregationBuilders.topHits("uid_top").addSort("offline_time", SortOrder.DESC).setSize(1));
es5.3版本以上,新增了字段折叠(Field Collapsing)功能,所谓的字段折叠理解就是按特定字段进行合并去重,DSL样例如下:
{
"size": 100,
"query": {
"设置查询条件"
},
"collapse": {
"field": "orderId"
}
}
上述DSL执行返回的结果中会把重复的数据直接过滤调,相同的数据只会返回一条,这样有利于后续其他的维度分析。
java-api参考:
CollapseBuilder collapseBuilder = new CollapseBuilder("orderId");
SearchRequestBuilder requestBuilder = transportClient.prepareSearch("XXX").setTypes("XXX")
.setSize(111).setQuery(queryBuilder).setCollapse(collapseBuilder);
到这里我个人对 elasticsearch 去重查询的基本总结结束了,欢迎大家留言批评指正。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。