elasticsearch去重查詢
1、業務背景:
最近的實際中業務中,要對用戶訂單數據進行統計,用戶訂單數據從用戶下單到支付的過程都會記錄,同時每次用戶訂單查看也會產生一次訂單更新數據,但是由於歷史原因,用戶訂單更新數據入庫沒有進行整理,都是直接把訂單相關的數據存入es。今天某項數據分析需要對用戶訂單進行查詢並去重做一些針對訂單維度的分析。
2、切入正題:去重查詢
2.1、關係型數據庫處理
一般關係型數據庫去重統計直接sql中的distinct函數就可以實現,
獲取統計去重後的數量:
select distinct(count(1)) from order;
獲取去重後的結果:
select distinct order_id from order;
2.2、es中查詢處理方法
獲取統計去重後的數量一般使用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 去重查詢的基本總結結束了,歡迎大家留言批評指正。