elasticsearch2.x中es-sql的distinct欄位和原生的cardinality使用及適用場景
阿新 • • 發佈:2018-11-10
場景:
使用者通過資料集dataset分組,並通過event_no欄位去重進行資料去重後統計。
使用es-sql實現等價去重查詢:
SELECT dataset,count(DISTINCT event_no) as count from json_archives_qc/info group by dataset
為什麼我要說類似等價呢? 因為從精確性、效能等角度還是和普通sql有很大區別的~!!!
使用cardinality聚合函式(只支援40000以內統計結果的精確度)
dsl:
{
"from": 0,
"size": 0,
"fields": "dataset",
"aggregations": {
"dataset": {
"terms": {
"field": "dataset",
"size": 200
},
"aggregations": {
"count": {
"cardinality": {
"field": "event_no",
"precision_threshold": 40000
}
}
}
}
}
}
詳細程式碼:
SearchRequestBuilder builder = transportClient.prepareSearch("json_archives_qc"); builder.setTypes("info"); builder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH); AggregationBuilder terms = AggregationBuilders.terms("dataset").field("dataset").size(200); CardinalityBuilder childTerms = AggregationBuilders.cardinality("count").field("event_no").precisionThreshold(40000); terms.subAggregation(childTerms); builder.addAggregation(terms); builder.setSize(0); builder.setFrom(0); SearchResponse response = builder.get(); StringTerms longTerms = response.getAggregations().get("dataset"); for (Terms.Bucket item : longTerms.getBuckets()) { InternalCardinality extendedStats = item.getAggregations().get("count"); Map<String, Object> temp = new HashMap<>(); temp.put("dataset", item.getKeyAsString()); temp.put("count", extendedStats.getValue()); resultList.add(temp); num1 += extendedStats.getValue(); }
主要程式碼:InternalCardinality extendedStats = item.getAggregations().get("count"); //獲取去重過濾後的統計結果; 需要使用InternalCardinality 進行獲取資料, 之前直接通過item.getAggregations().get("count") 去獲取去重後結果,一直無法獲取成功;
優點:效能快,億級別的記錄在1秒內完成
缺點:返回結果只能保證最大40000條記錄的精確,統計結果超過40000的話會存在5%的誤差,不適合需要精確去重場景
精度要求場景:
未研究哈,後續繼續研究下,有問題的同學可以留言互相探討