* Sort centroids in the digest. * * We have to sort the whole array, because we don't just simply sort the * centroids - we do the rebalancing of items with the same mean too. */
| 227 | * centroids - we do the rebalancing of items with the same mean too. |
| 228 | */ |
| 229 | static void |
| 230 | tdigest_sort(tdigest_aggstate_t *state) |
| 231 | { |
| 232 | int i; |
| 233 | int64 count_so_far; |
| 234 | int64 next_group; |
| 235 | int64 median_count; |
| 236 | |
| 237 | /* do qsort on the non-sorted part */ |
| 238 | pg_qsort(state->centroids, |
| 239 | state->ncentroids, |
| 240 | sizeof(centroid_t), centroid_cmp); |
| 241 | |
| 242 | /* |
| 243 | * The centroids are sorted by (mean,count). That's fine for centroids up |
| 244 | * to median, but above median this ordering is incorrect for centroids |
| 245 | * with the same mean (or for groups crossing the median boundary). To fix |
| 246 | * this we 'rebalance' those groups. Those entirely above median can be |
| 247 | * simply sorted in the opposite order, while those crossing the median |
| 248 | * need to be rebalanced depending on what part is below/above median. |
| 249 | */ |
| 250 | count_so_far = 0; |
| 251 | next_group = 0; /* includes count_so_far */ |
| 252 | median_count = (state->count / 2); |
| 253 | |
| 254 | /* |
| 255 | * Split the centroids into groups with the same mean, process each group |
| 256 | * depending on whether it falls before/after median. |
| 257 | */ |
| 258 | i = 0; |
| 259 | while (i < state->ncentroids) |
| 260 | { |
| 261 | int j = i; |
| 262 | int group_size = 0; |
| 263 | |
| 264 | /* determine the end of the group */ |
| 265 | while ((j < state->ncentroids) && |
| 266 | (state->centroids[i].mean == state->centroids[j].mean)) |
| 267 | { |
| 268 | next_group += state->centroids[j].count; |
| 269 | group_size++; |
| 270 | j++; |
| 271 | } |
| 272 | |
| 273 | /* |
| 274 | * We can ignore groups of size 1 (Total count of centroids, not counts), as |
| 275 | * those are trivially sorted. |
| 276 | */ |
| 277 | if (group_size > 1) |
| 278 | { |
| 279 | if (count_so_far >= median_count) |
| 280 | { |
| 281 | /* group fully above median - reverse the order */ |
| 282 | reverse_centroids(&state->centroids[i], group_size); |
| 283 | } |
| 284 | else if (next_group >= median_count) /* group split by median */ |
| 285 | { |
| 286 | rebalance_centroids(&state->centroids[i], group_size, |
no test coverage detected