DataSketches Theta Sketch 모듈
DataSketches Theta Sketch 모듈
Apache DataSketches 라이브러리의 Theta sketch를 기반으로 한 근사 고유값(distinct) 개수 세기 애그리게이터를 제공하는 모듈이에요. 스케치는 근사적이며, 쿼리 시점에 union/intersection/difference 같은 집합 연산을 지원해요.
출처: 문서
본문
이 모듈은 Apache DataSketches 라이브러리의 Theta sketch를 기반으로 한 Apache Druid 애그리게이터를 제공해요. 스케치 알고리즘은 근사적이에요. 자세한 내용은 DataSketches 문서의 Accuracy를 참고하세요.
인제이션 시점에 Theta sketch 애그리게이터는 Druid 세그먼트에 저장되는 Theta sketch 객체를 만들어요. 논리적으로 Theta sketch 객체는 Set 데이터 구조로 생각할 수 있어요. 쿼리 시점에 스케치는 함께 읽혀 집계(집합 union)돼요. 결국 기본적으로 스케치 객체의 고유 항목 수 추정치를 받게 돼요. post aggregator를 사용해 같은 행의 sketch 컬럼에 대해 union, intersection 또는 difference를 수행할 수 있어요.
thetaSketch 애그리게이터를 사용해 동일하게 인제스트되지 않은 컬럼에도 사용할 수 있다는 점을 유의하세요. 해당 컬럼의 추정 카디널리티를 반환해요. 쿼리를 더 빠르게 하려면 인제이션 시점에도 사용하는 것이 권장돼요.
이 애그리게이터를 사용하려면 config 파일에 확장 기능을 포함하세요:
druid.extensions.loadList=["druid-datasketches"]
Druid가 지원하는 추가 sketch 유형은 DataSketches extension을 참고하세요.
애그리게이터 (Aggregator)
{
"type" : "thetaSketch",
"name" : <output_name>,
"fieldName" : <metric_name>,
"isInputThetaSketch": false,
"size": 16384
}
| Property | Description | Required? | | type | This string should always be "thetaSketch" | yes | | name | String representing the output column to store sketch values. | yes | | fieldName | A string for the name of the aggregator used at ingestion time. | yes | | isInputThetaSketch | Only set this to true at indexing time if your input data contains Theta sketch objects. This applies to cases when you use DataSketches outside of Druid, for example with Pig or Hive, to produce the data to ingest into Druid | no, defaults to false | | size | Must be a power of 2. Internally, size refers to the maximum number of entries sketch object retains. Higher size means higher accuracy but more space to store sketches. After you index with a particular size, Druid persists the sketch in segments. At query time you must use a size greater or equal to the ingested size. See the DataSketches site for details. The default is recommended for the majority of use cases. | no, defaults to 16384 | | shouldFinalize | Return the final double type representing the estimate rather than the intermediate sketch type itself. In addition to controlling the finalization of this aggregator, you can control whether all aggregators are finalized with the query context parameters finalize and sqlFinalizeOuterSketches . | no, defaults to true |
Post aggregator (Post aggregators)
Sketch estimator
{
"type" : "thetaSketchEstimate",
"name": <output name>,
"field" : <post aggregator of type fieldAccess that refers to a thetaSketch aggregator or that of type thetaSketchSetOp>
}
Sketch operations
{
"type" : "thetaSketchSetOp",
"name": <output name>,
"func": <UNION|INTERSECT|NOT>,
"fields" : <array of fieldAccess type post aggregators to access the thetaSketch aggregators or thetaSketchSetOp type post aggregators to allow arbitrary combination of set operations>,
"size": <16384 by default, must be max of size from sketches in fields input>
}
Sketch summary
디버깅에 사용할 수 있는 sketch의 요약을 반환해요. toString() 메서드를 호출한 결과예요.
{
"type" : "thetaSketchToString",
"name": <output name>,
"field" : <post aggregator that refers to a Theta sketch (fieldAccess or another post aggregator)>
}
상수 Theta Sketch (Constant Theta Sketch)
constant theta sketch post aggregator를 사용해 다른 post-aggregator에서 사용할 Base64로 인코딩된 상수 theta sketch 값을 추가할 수 있어요. 예를 들어 thetaSketchSetOp에서요.
{
"type" : "thetaSketchConstant",
"name": DESTINATION_COLUMN_NAME,
"value" : CONSTANT_SKETCH_VALUE
}
상수 Theta Sketch 사용 예제 (Example using a constant Theta Sketch)
다양한 사용자들로 구성된 데이터소스가 있다고 가정해요. 필터와 집계를 사용해 모든 축구 팬의 theta sketch를 생성해요.
제3자 제공자가 모든 크리켓 팬의 constant theta sketch를 제공했고, post-aggregation 단계에서 크리켓 팬과 축구 팬을 모두 INTERSECT해 두 가지 모두에 관심이 있는 사용자를 식별하려 한다고 가정해요. 그런 다음 thetaSketchEstimate를 사용해 고유 사용자 수를 계산하려 해요.
{
"type":"thetaSketchEstimate",
"name":"football_cricket_users_count",
"field":{
"type":"thetaSketchSetOp",
"name":"football_cricket_fans_users_theta_sketch",
"func":"INTERSECT",
"fields":[
{
"type":"fieldAccess",
"fieldName":"football_fans_users_theta_sketch"
},
{
"type":"thetaSketchConstant",
"name":"cricket_fans_users_theta_sketch",
"value":"AgMDAAAazJMCAAAAAACAPzz9j7pWTMdROWGf15uY1nI="
}
]
}
}
예제 (Examples)
(timestamp, product, user_id)를 포함한 데이터셋이 있다고 가정해요. 다음과 같은 질문에 답하고 싶어요:
- 제품 A를 방문한 고유 사용자는 몇 명인가?
- 제품 A와 제품 B를 모두 방문한 고유 사용자는 몇 명인가?
위 질문에 답하려면 다음 애그리게이터로 데이터를 인덱싱해요.
{ "type": "thetaSketch", "name": "user_id_sketch", "fieldName": "user_id" }
그런 다음 "제품 A를 방문한 고유 사용자는 몇 명인가?"에 대한 샘플 쿼리:
{
"queryType": "groupBy",
"dataSource": "test_datasource",
"granularity": "ALL",
"dimensions": [],
"aggregations": [
{ "type": "thetaSketch", "name": "unique_users", "fieldName": "user_id_sketch" }
],
"filter": { "type": "selector", "dimension": "product", "value": "A" },
"intervals": [ "2014-10-19T00:00:00.000Z/2014-10-22T00:00:00.000Z" ]
}
"제품 A와 B를 모두 방문한 고유 사용자는 몇 명인가?"에 대한 샘플 쿼리:
{
"queryType": "groupBy",
"dataSource": "test_datasource",
"granularity": "ALL",
"dimensions": [],
"filter": {
"type": "or",
"fields": [
{"type": "selector", "dimension": "product", "value": "A"},
{"type": "selector", "dimension": "product", "value": "B"}
]
},
"aggregations": [
{
"type" : "filtered",
"filter" : {
"type" : "selector",
"dimension" : "product",
"value" : "A"
},
"aggregator" : {
"type": "thetaSketch", "name": "A_unique_users", "fieldName": "user_id_sketch"
}
},
{
"type" : "filtered",
"filter" : {
"type" : "selector",
"dimension" : "product",
"value" : "B"
},
"aggregator" : {
"type": "thetaSketch", "name": "B_unique_users", "fieldName": "user_id_sketch"
}
}
],
"postAggregations": [
{
"type": "thetaSketchEstimate",
"name": "final_unique_users",
"field":
{
"type": "thetaSketchSetOp",
"name": "final_unique_users_sketch",
"func": "INTERSECT",
"fields": [
{
"type": "fieldAccess",
"fieldName": "A_unique_users"
},
{
"type": "fieldAccess",
"fieldName": "B_unique_users"
}
]
}
}
],
"intervals": [
"2014-10-19T00:00:00.000Z/2014-10-22T00:00:00.000Z"
]
}
리텐션 분석 예제 (Retention analysis example)
"특정 기간에 특정 액션을 수행하고 다른 기간에 또 다른 특정 액션을 수행한 고유 사용자는 몇 명인가?" 같은 질문에 답하고 싶다고 가정해요.
예: "1주차에 가입하고 2주차에 무언가를 구매한 고유 사용자는 몇 명인가?"
(timestamp, product, user_id) 예제 데이터셋을 사용하면, 위 예제처럼 다음 애그리게이터로 데이터를 인덱싱해요:
{ "type": "thetaSketch", "name": "user_id_sketch", "fieldName": "user_id" }
다음 쿼리는 다음을 표현해요:
"2014/10/01과 2014/10/07 사이에 Product A를 방문한 고유 사용자 중, 2014/10/08부터 2014/10/14까지의 주에 Product A를 다시 방문한 사용자는 몇 명인가?"
{
"queryType": "groupBy",
"dataSource": "test_datasource",
"granularity": "ALL",
"dimensions": [],
"filter": {
"type": "or",
"fields": [
{"type": "selector", "dimension": "product", "value": "A"}
]
},
"aggregations": [
{
"type" : "filtered",
"filter" : {
"type" : "and",
"fields" : [
{
"type" : "selector",
"dimension" : "product",
"value" : "A"
},
{
"type" : "interval",
"dimension" : "__time",
"intervals" : ["2014-10-01T00:00:00.000Z/2014-10-07T00:00:00.000Z"]
}
]
},
"aggregator" : {
"type": "thetaSketch", "name": "A_unique_users_week_1", "fieldName": "user_id_sketch"
}
},
{
"type" : "filtered",
"filter" : {
"type" : "and",
"fields" : [
{
"type" : "selector",
"dimension" : "product",
"value" : "A"
},
{
"type" : "interval",
"dimension" : "__time",
"intervals" : ["2014-10-08T00:00:00.000Z/2014-10-14T00:00:00.000Z"]
}
]
},
"aggregator" : {
"type": "thetaSketch", "name": "A_unique_users_week_2", "fieldName": "user_id_sketch"
}
},
],
"postAggregations": [
{
"type": "thetaSketchEstimate",
"name": "final_unique_users",
"field":
{
"type": "thetaSketchSetOp",
"name": "final_unique_users_sketch",
"func": "INTERSECT",
"fields": [
{
"type": "fieldAccess",
"fieldName": "A_unique_users_week_1"
},
{
"type": "fieldAccess",
"fieldName": "A_unique_users_week_2"
}
]
}
}
],
"intervals": ["2014-10-01T00:00:00.000Z/2014-10-14T00:00:00.000Z"]
}