Daniel Augusto
05/31/2024, 5:28 PMAPPROX_QUANTILE_DS when requested for a single quantile vs multiple quantiles?
After some weird results, I've wrote a small script to alternate queries between a single random percentile from a set and all percentiles in the set.
export ROUTER_URL=xxx
export MY_TABLE=xxx
export FIELD=xxx
export HEAD_JSON='Content-Type: application/json'
for ((i=1; i<=10; i++))
do
per=`gshuf -n1 -e 10 25 50 75 90`
curl "https://${ROUTER_URL}/druid/v2/sql" --header $HEAD_JSON --data '{"query": "SELECT COUNT(*) as \"records\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.'${per}') as \"p'${per}'\" FROM \"'${MY_TABLE}'\"" }'
curl "https://${ROUTER_URL}/druid/v2/sql" --header $HEAD_JSON --data '{"query": "SELECT COUNT(*) as \"records\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.10) as \"p10\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.25) as \"p25\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.50) as \"p50\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.75) as \"p75\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.90) as \"p90\" FROM \"'${MY_TABLE}'\"" }'
done
Results:
[{"records":1071832,"p75":52.0}]
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p10":58.0}] <---- WRONG
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p25":52.0}] <---- WRONG
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p25":38.0}]
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p25":52.0}] <---- WRONG
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p25":38.0}]
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p90":58.0}]
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p75":38.0}] <---- WRONG
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p25":52.0}] <---- WRONG
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p50":38.0}] <---- WRONG
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
It's the same 1M records dataset in for queries.
• multiple quantiles in a single query results are consistent
• a single quantile in a query is not; in the example above the p25 is called 4 times in a row (all quantiles in between these calls) and it keeps changing between 38.0 and 52.0
What could explain this?Daniel Augusto
05/31/2024, 5:29 PMuseCache: false and useResultLevelCache: false
$ for ((i=1; i<=10; i++))
do
per=`gshuf -n1 -e 10 25 50 75 90`
curl "https://${ROUTER_URL}/druid/v2/sql" --header $HEAD_JSON --data '{"useCache":"false", "useResultLevelCache":"false", "query": "SELECT COUNT(*) as \"records\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.'${per}') as \"p'${per}'\" FROM \"'${MY_TABLE}'\"" }'
curl "https://${ROUTER_URL}/druid/v2/sql" --header $HEAD_JSON --data '{"useCache":"false", "useResultLevelCache":"false", "query": "SELECT COUNT(*) as \"records\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.10) as \"p10\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.25) as \"p25\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.50) as \"p50\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.75) as \"p75\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.90) as \"p90\" FROM \"'${MY_TABLE}'\"" }'
done
[{"records":1072744,"p10":32.0}]
[{"records":1072744,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1072744,"p75":52.0}]
[{"records":1072744,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1072744,"p25":38.0}]
[{"records":1072744,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1072744,"p90":57.0}] <-- OK I GUESS
[{"records":1072744,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1072744,"p10":32.0}]
[{"records":1072744,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1072744,"p25":52.0}] <---- WRONG
[{"records":1072744,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1072744,"p75":38.0}] <---- WRONG
[{"records":1072744,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1072744,"p25":52.0}] <---- WRONG
[{"records":1072744,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1072744,"p90":32.0}] <---- WRONG
[{"records":1072744,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1072744,"p90":57.0}] <-- OK I GUESS
[{"records":1072744,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]Daniel Augusto
05/31/2024, 5:38 PMJohn Kowtko
06/01/2024, 1:58 PMselect COUNT(*),
avg(added) avgAdded,
approx_quantile_ds(added, 0.90) p90,
approx_quantile_ds(added, 0.98) p98
from wikipedia
I will ask around ...Daniel Augusto
06/02/2024, 6:20 PMJohn Kowtko
06/03/2024, 3:02 PMDaniel Augusto
06/03/2024, 4:08 PM[{"records":1071832,"p75":52.0}]
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p10":58.0}] <--- here p10 returned what should be p90
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p25":52.0}] <--- in this one p25 returned p75
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p25":38.0}]
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p25":52.0}] <---- p25 returned again p75
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p25":38.0}]
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p90":58.0}]
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p75":38.0}] <---- now p75 returned p25
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p25":52.0}] <---- p25 returned p75 once more
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1071832,"p50":38.0}]
[{"records":1071832,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
If requesting for p25 returned me something like between p20 and p30 would be a significant-but-maybe-acceptable variation, but a p10 request returning p90 is just waaaay to much.
I know this column values follow a normal distribution, I can even see it in Druid Explore tab. There's no big skew.Daniel Augusto
06/03/2024, 4:12 PMJohn Kowtko
06/03/2024, 6:34 PMDaniel Augusto
06/04/2024, 9:20 AMDaniel Augusto
06/04/2024, 9:25 AMexport MY_TABLE=test_percentiles_daniel
export HEAD_JSON='Content-Type: application/json'
export FIELD=added
for ((i=1; i<=10; i++))
do
per=`gshuf -n1 -e 10 25 50 75 90`
curl "https://${ROUTER_URL}/druid/v2/sql" --header $HEAD_JSON --data '{"useCache":"false", "useResultLevelCache":"false", "query": "SELECT COUNT(*) as \"records\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.'${per}') as \"p'${per}'\" FROM \"'${MY_TABLE}'\" " }'
curl "https://${ROUTER_URL}/druid/v2/sql" --header $HEAD_JSON --data '{"useCache":"false", "useResultLevelCache":"false", "query": "SELECT COUNT(*) as \"records\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.10) as \"p10\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.25) as \"p25\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.50) as \"p50\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.75) as \"p75\", APPROX_QUANTILE_DS(\"'${FIELD}'\", 0.90) as \"p90\" FROM \"'${MY_TABLE}'\" " }'
done
[{"records":39244,"p90":0.0}] <--- NOT CONSISTENT
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":49.0,"p90":359.0}] <-- p90 is 359
[{"records":39244,"p90":359.0}]
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":50.0,"p90":331.0}] <-- p90 is 331
[{"records":39244,"p25":1.0}]
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":50.0,"p90":331.0}] <-- p90 is 331
[{"records":39244,"p75":50.0}]
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":49.0,"p90":359.0}] <-- p90 is 359
[{"records":39244,"p75":50.0}]
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":49.0,"p90":359.0}] <-- p90 is 359
[{"records":39244,"p25":1.0}]
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":50.0,"p90":331.0}] <-- p90 is 331
[{"records":39244,"p25":50.0}] <--- NOT CONSISTENT
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":49.0,"p90":359.0}] <-- p90 is 359
[{"records":39244,"p90":359.0}]
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":50.0,"p90":331.0}] <-- p90 is 331
[{"records":39244,"p10":0.0}]
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":49.0,"p90":359.0}] <-- p90 is 359
[{"records":39244,"p50":1.0}] <--- NOT CONSISTENT
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":50.0,"p90":331.0}] <-- p90 is 331Daniel Augusto
06/04/2024, 9:27 AMDaniel Augusto
06/04/2024, 9:51 AM[{"records":39244,"p50":1.0}]
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":51.0,"p90":357.0}]
[{"records":39244,"p50":1.0}]
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":51.0,"p90":357.0}]
[{"records":39244,"p75":18.0}] <--- NOT CONSISTENT
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":52.0,"p90":374.0}]
[{"records":39244,"p50":1.0}] <--- NOT CONSISTENT
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":51.0,"p90":357.0}]
[{"records":39244,"p10":0.0}]
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":52.0,"p90":374.0}]
[{"records":39244,"p75":1.0}] <--- NOT CONSISTENT
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":51.0,"p90":357.0}]
[{"records":39244,"p25":1.0}]
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":51.0,"p90":357.0}]
[{"records":39244,"p25":18.0}] <--- NOT CONSISTENT
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":52.0,"p90":374.0}]
[{"records":39244,"p90":374.0}]
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":51.0,"p90":357.0}]
[{"records":39244,"p25":18.0}] <--- NOT CONSISTENT
[{"records":39244,"p10":0.0,"p25":1.0,"p50":18.0,"p75":52.0,"p90":374.0}]Daniel Augusto
06/04/2024, 9:52 AMJohn Kowtko
06/04/2024, 1:55 PMjohnkowtko@John-Kowtko ~ % ./foo.sh
[{"records":24433,"p90":675.0}]
[{"records":24433,"p10":0.0,"p25":0.0,"p50":4.0,"p75":78.0,"p90":786.0}]
[{"records":24433,"p90":635.0}]
[{"records":24433,"p10":0.0,"p25":0.0,"p50":4.0,"p75":74.0,"p90":722.0}]
[{"records":24433,"p90":616.0}]
[{"records":24433,"p10":0.0,"p25":0.0,"p50":4.0,"p75":74.0,"p90":648.0}]
[{"records":24433,"p90":718.0}]
[{"records":24433,"p10":0.0,"p25":0.0,"p50":3.0,"p75":75.0,"p90":617.0}]
[{"records":24433,"p90":798.0}]
[{"records":24433,"p10":0.0,"p25":0.0,"p50":4.0,"p75":81.0,"p90":725.0}]
[{"records":24433,"p90":722.0}]
[{"records":24433,"p10":0.0,"p25":0.0,"p50":4.0,"p75":74.0,"p90":762.0}]
[{"records":24433,"p90":728.0}]
[{"records":24433,"p10":0.0,"p25":0.0,"p50":4.0,"p75":74.0,"p90":620.0}]
[{"records":24433,"p90":722.0}]
[{"records":24433,"p10":0.0,"p25":0.0,"p50":4.0,"p75":80.0,"p90":725.0}]
[{"records":24433,"p90":808.0}]
[{"records":24433,"p10":0.0,"p25":0.0,"p50":4.0,"p75":72.0,"p90":626.0}]
[{"records":24433,"p90":675.0}]
[{"records":24433,"p10":0.0,"p25":0.0,"p50":4.0,"p75":78.0,"p90":648.0}]
johnkowtko@John-Kowtko ~ %Daniel Augusto
06/04/2024, 2:17 PMAPPROX_QUANTILE_DS as approximate, but kinda a deterministic approximation, so 20 repetitions would return the same value which would be in a ±3% range from the actual value you would get using an exact algorithm.John Kowtko
06/04/2024, 2:53 PMDaniel Augusto
06/04/2024, 4:45 PMGian Merlino
06/05/2024, 5:20 AMAPPROX_QUANTILE_DS isn't guaranteed to be a stable approximation— the intended guarantee is that each result adheres to the advertised error bounds on the datasketches website, but will not necessarily be the same number from run to run. this is true of most datasketches operationsGian Merlino
06/05/2024, 5:22 AMcontext like this {"context": {"useCache":"false", "useResultLevelCache":"false"}, "query": " ... sql sql sql ..."}Gian Merlino
06/05/2024, 5:33 AMGian Merlino
06/05/2024, 5:34 AMDaniel Augusto
06/05/2024, 9:04 AM[{"records":1373315,"p10":32.0,"p25":38.0,"p50":45.0,"p75":52.0,"p90":58.0}]
[{"records":1373315,"p10":32.0}]
[{"records":1373315,"p50":45.0}]
[{"records":1373315,"p25":38.0}]
[{"records":1373315,"p75":52.0}]
[{"records":1373315,"p90":58.0}]
[{"records":1373315,"p50":45.0}]
[{"records":1373315,"p25":38.0}]
[{"records":1373315,"p90":58.0}]
[{"records":1373315,"p10":32.0}]
[{"records":1373315,"p10":32.0}]
[{"records":1373315,"p25":38.0}]
[{"records":1373315,"p25":38.0}]
[{"records":1373315,"p90":58.0}]
[{"records":1373315,"p25":38.0}]
[{"records":1373315,"p10":32.0}]
[{"records":1373315,"p10":32.0}]
[{"records":1373315,"p25":38.0}]
[{"records":1373315,"p25":38.0}]
[{"records":1373315,"p10":32.0}]
[{"records":1373315,"p10":32.0}]
all as expected
testing the combinations:
"context": { "useCache":"true", "useResultLevelCache":"true" } --> bad results
"context": { "useCache":"false","useResultLevelCache":"true" } --> bad results
"context": { "useCache":"true", "useResultLevelCache":"false" } --> OK
"context": { "useCache":"false","useResultLevelCache":"false" } --> OK
So it's the result level cache that's messing with the resultsGian Merlino
06/05/2024, 9:14 AMDaniel Augusto
06/05/2024, 9:14 AMGian Merlino
06/05/2024, 9:16 AMDaniel Augusto
06/05/2024, 9:24 AMGian Merlino
06/05/2024, 9:28 AMGian Merlino
06/05/2024, 9:28 AMGian Merlino
06/05/2024, 9:29 AMDaniel Augusto
06/05/2024, 9:46 AM