tranfi 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +177 -0
- package/NOTICE +8 -0
- package/README.md +443 -51
- package/app/assets/{index-pDFMluyz.js → index-BIAIKnrp.js} +1 -1
- package/app/index.html +1 -1
- package/binding.gyp +55 -3
- package/csrc/arena.c +7 -5
- package/csrc/batch.c +818 -71
- package/csrc/buffer.c +84 -8
- package/csrc/cJSON.c +262 -19
- package/csrc/cJSON.h +17 -1
- package/csrc/codec_csv.c +1074 -181
- package/csrc/codec_jsonl.c +830 -118
- package/csrc/codec_table.c +108 -78
- package/csrc/codec_text.c +286 -68
- package/csrc/compiler.c +31 -3
- package/csrc/config.h +21 -0
- package/csrc/dsl.c +4722 -485
- package/csrc/expr.c +363 -55
- package/csrc/expr.h +2 -0
- package/csrc/internal.h +316 -27
- package/csrc/ir.c +65 -18
- package/csrc/ir.h +41 -0
- package/csrc/ir_schema.c +20 -5
- package/csrc/ir_serialize.c +68 -6
- package/csrc/ir_sql.c +796 -185
- package/csrc/ir_validate.c +462 -6
- package/csrc/json_path.c +210 -0
- package/csrc/main.c +879 -30
- package/csrc/memory_estimate.c +477 -0
- package/csrc/op_acf.c +171 -21
- package/csrc/op_across.c +477 -0
- package/csrc/op_anomaly.c +167 -32
- package/csrc/op_assert.c +761 -0
- package/csrc/op_bin.c +168 -29
- package/csrc/op_cast.c +383 -55
- package/csrc/op_clip.c +30 -19
- package/csrc/op_date_trunc.c +208 -34
- package/csrc/op_datetime.c +259 -77
- package/csrc/op_derive.c +65 -97
- package/csrc/op_diff.c +146 -30
- package/csrc/op_ewma.c +149 -30
- package/csrc/op_explode.c +124 -26
- package/csrc/op_fill_down.c +125 -53
- package/csrc/op_fill_null.c +176 -31
- package/csrc/op_filter.c +89 -40
- package/csrc/op_frequency.c +571 -43
- package/csrc/op_grep.c +36 -18
- package/csrc/op_group_agg.c +1790 -119
- package/csrc/op_hash.c +48 -15
- package/csrc/op_head.c +21 -86
- package/csrc/op_interpolate.c +268 -62
- package/csrc/op_join.c +2700 -182
- package/csrc/op_json_extract.c +227 -0
- package/csrc/op_json_filter.c +384 -0
- package/csrc/op_json_flatten.c +293 -0
- package/csrc/op_json_schema.c +503 -0
- package/csrc/op_label_encode.c +328 -53
- package/csrc/op_lag.c +181 -0
- package/csrc/op_lead.c +141 -89
- package/csrc/op_normalize.c +363 -79
- package/csrc/op_onehot.c +345 -73
- package/csrc/op_pivot.c +1546 -162
- package/csrc/op_quarantine.c +189 -0
- package/csrc/op_registry.c +2062 -166
- package/csrc/op_rename.c +41 -50
- package/csrc/op_replace.c +270 -118
- package/csrc/op_rleid.c +297 -0
- package/csrc/op_rowid.c +559 -0
- package/csrc/op_sample.c +80 -23
- package/csrc/op_schema.c +1341 -0
- package/csrc/op_schema_infer.c +252 -0
- package/csrc/op_select.c +265 -65
- package/csrc/op_set.c +3449 -0
- package/csrc/op_skip.c +30 -87
- package/csrc/op_sort.c +670 -124
- package/csrc/op_source_name.c +120 -0
- package/csrc/op_split.c +65 -28
- package/csrc/op_split_data.c +41 -9
- package/csrc/op_stack.c +178 -222
- package/csrc/op_stats.c +206 -110
- package/csrc/op_step.c +217 -55
- package/csrc/op_tail.c +21 -12
- package/csrc/op_tee.c +338 -0
- package/csrc/op_top.c +260 -53
- package/csrc/op_trim.c +48 -19
- package/csrc/op_unique.c +1193 -150
- package/csrc/op_unpivot.c +100 -66
- package/csrc/op_validate.c +601 -24
- package/csrc/op_window.c +492 -51
- package/csrc/path_policy.c +85 -0
- package/csrc/pipeline.c +872 -99
- package/csrc/recipes.c +3 -1
- package/csrc/report.c +73 -30
- package/csrc/selector.c +1097 -0
- package/csrc/size_utils.c +352 -0
- package/csrc/spill.c +317 -0
- package/csrc/spill.h +21 -0
- package/csrc/tranfi.h +169 -1
- package/csrc/transform.h +209 -0
- package/csrc/transform_api.c +2237 -0
- package/csrc/transform_categorical.c +923 -0
- package/csrc/transform_internal.h +472 -0
- package/csrc/transform_json.c +3812 -0
- package/csrc/transform_numeric.c +1966 -0
- package/csrc/transform_sha256.c +154 -0
- package/csrc/transform_wasm.h +162 -0
- package/csrc/transform_wasm_api.c +1373 -0
- package/csrc/wasm_api.c +70 -9
- package/napi_api.c +219 -11
- package/napi_transform.c +1648 -0
- package/napi_transform.h +8 -0
- package/package.json +27 -11
- package/scripts/install-native.js +76 -0
- package/scripts/prepack.js +64 -0
- package/scripts/sync-csrc.js +23 -0
- package/src/cli.js +81 -41
- package/src/engines/duckdb.js +45 -12
- package/src/index.js +661 -42
- package/src/memory_policy.js +411 -0
- package/src/native.js +1 -5
- package/src/pipeline.js +454 -31
- package/src/recipe_json.js +80 -0
- package/src/server.js +10 -8
- package/src/transform.js +403 -0
- package/src/transform_error.js +10 -0
- package/src/wasm.js +6 -4
- package/wasm/index.js +498 -10
- package/wasm/tranfi_core.js +0 -0
- package/wasm/transform.js +1156 -0
- package/wasm/worker.js +786 -0
- package/csrc/plan.c +0 -206
package/csrc/op_stats.c
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* op_stats.c — Streaming aggregates with online algorithms.
|
|
3
3
|
*
|
|
4
|
-
* Config: {"stats": ["count","
|
|
5
|
-
* "
|
|
6
|
-
* "
|
|
4
|
+
* Config: {"stats": ["count","missing","complete_rate","sum","avg",
|
|
5
|
+
* "min","max","var","stddev","median","p25",
|
|
6
|
+
* "p75","skewness","kurtosis","distinct",
|
|
7
|
+
* "hist","sample"]}
|
|
7
8
|
* or {} for default stats (count, sum, avg, min, max, var, stddev, median).
|
|
9
|
+
* The scan op uses this engine with profile defaults: count, missing,
|
|
10
|
+
* complete_rate, distinct, min, max, avg, stddev, p25, median, p75,
|
|
11
|
+
* hist, and sample.
|
|
8
12
|
*
|
|
9
13
|
* Algorithms ported from OnlineStats.jl (MIT):
|
|
10
14
|
* - Welford's online variance (var, stddev)
|
|
@@ -182,8 +186,9 @@ static void hll_update(hll_state *h, const char *val) {
|
|
|
182
186
|
uint32_t x = hll_hash(val);
|
|
183
187
|
uint32_t idx = x & (HLL_M - 1);
|
|
184
188
|
uint32_t w = x >> HLL_P;
|
|
185
|
-
int rho = hll_clz32(w) + 1;
|
|
186
|
-
if (rho
|
|
189
|
+
int rho = w == 0 ? (32 - HLL_P + 1) : (hll_clz32(w) - HLL_P + 1);
|
|
190
|
+
if (rho < 1) rho = 1;
|
|
191
|
+
if (rho > 32 - HLL_P + 1) rho = 32 - HLL_P + 1;
|
|
187
192
|
if ((uint8_t)rho > h->M[idx]) h->M[idx] = (uint8_t)rho;
|
|
188
193
|
}
|
|
189
194
|
|
|
@@ -345,6 +350,7 @@ static void reservoir_update(reservoir_state *r, double y) {
|
|
|
345
350
|
|
|
346
351
|
typedef struct {
|
|
347
352
|
/* Basic stats */
|
|
353
|
+
size_t total;
|
|
348
354
|
size_t count;
|
|
349
355
|
double sum;
|
|
350
356
|
double min;
|
|
@@ -381,7 +387,8 @@ typedef struct {
|
|
|
381
387
|
size_t n_cols;
|
|
382
388
|
int initialized;
|
|
383
389
|
/* Which stats to output */
|
|
384
|
-
int want_count,
|
|
390
|
+
int want_count, want_missing, want_complete_rate;
|
|
391
|
+
int want_sum, want_avg, want_min, want_max;
|
|
385
392
|
int want_var, want_stddev;
|
|
386
393
|
int want_median, want_p25, want_p75;
|
|
387
394
|
int want_skewness, want_kurtosis;
|
|
@@ -390,7 +397,18 @@ typedef struct {
|
|
|
390
397
|
int want_sample;
|
|
391
398
|
} stats_state;
|
|
392
399
|
|
|
393
|
-
static
|
|
400
|
+
static char *stats_strdup(const char *s) {
|
|
401
|
+
const char *src = s ? s : "";
|
|
402
|
+
size_t len = strlen(src);
|
|
403
|
+
size_t n;
|
|
404
|
+
if (tf_size_add(len, 1, &n) != TF_OK) return NULL;
|
|
405
|
+
char *out = tf_mallocarray_checked(n, sizeof(char));
|
|
406
|
+
if (!out) return NULL;
|
|
407
|
+
memcpy(out, src, len + 1);
|
|
408
|
+
return out;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
static int accum_init(col_accum *a, const stats_state *st) {
|
|
394
412
|
a->min = DBL_MAX;
|
|
395
413
|
a->max = -DBL_MAX;
|
|
396
414
|
p2_init(&a->p2_median, 0.5);
|
|
@@ -398,17 +416,21 @@ static void accum_init(col_accum *a, const stats_state *st) {
|
|
|
398
416
|
p2_init(&a->p2_p75, 0.75);
|
|
399
417
|
|
|
400
418
|
if (st->want_distinct) {
|
|
401
|
-
a->hll =
|
|
402
|
-
if (a->hll)
|
|
419
|
+
a->hll = tf_callocarray_checked(1, sizeof(hll_state));
|
|
420
|
+
if (!a->hll) return TF_ERROR;
|
|
421
|
+
hll_init(a->hll);
|
|
403
422
|
}
|
|
404
423
|
if (st->want_hist) {
|
|
405
|
-
a->hist =
|
|
406
|
-
if (a->hist)
|
|
424
|
+
a->hist = tf_callocarray_checked(1, sizeof(hist_state));
|
|
425
|
+
if (!a->hist) return TF_ERROR;
|
|
426
|
+
hist_init(a->hist);
|
|
407
427
|
}
|
|
408
428
|
if (st->want_sample) {
|
|
409
|
-
a->reservoir =
|
|
410
|
-
if (a->reservoir)
|
|
429
|
+
a->reservoir = tf_callocarray_checked(1, sizeof(reservoir_state));
|
|
430
|
+
if (!a->reservoir) return TF_ERROR;
|
|
431
|
+
reservoir_init(a->reservoir);
|
|
411
432
|
}
|
|
433
|
+
return TF_OK;
|
|
412
434
|
}
|
|
413
435
|
|
|
414
436
|
static void accum_update(col_accum *a, double val, const char *str_val,
|
|
@@ -455,6 +477,23 @@ static void accum_free(col_accum *a) {
|
|
|
455
477
|
free(a->reservoir);
|
|
456
478
|
}
|
|
457
479
|
|
|
480
|
+
static void stats_clear_accumulation(stats_state *st) {
|
|
481
|
+
if (!st) return;
|
|
482
|
+
if (st->accums) {
|
|
483
|
+
for (size_t i = 0; i < st->n_cols; i++)
|
|
484
|
+
accum_free(&st->accums[i]);
|
|
485
|
+
free(st->accums);
|
|
486
|
+
}
|
|
487
|
+
if (st->col_names) {
|
|
488
|
+
for (size_t i = 0; i < st->n_cols; i++) free(st->col_names[i]);
|
|
489
|
+
free(st->col_names);
|
|
490
|
+
}
|
|
491
|
+
st->accums = NULL;
|
|
492
|
+
st->col_names = NULL;
|
|
493
|
+
st->n_cols = 0;
|
|
494
|
+
st->initialized = 0;
|
|
495
|
+
}
|
|
496
|
+
|
|
458
497
|
/* ---- Process / Flush / Destroy ---- */
|
|
459
498
|
|
|
460
499
|
static int stats_process(tf_step *self, tf_batch *in, tf_batch **out,
|
|
@@ -465,18 +504,26 @@ static int stats_process(tf_step *self, tf_batch *in, tf_batch **out,
|
|
|
465
504
|
|
|
466
505
|
if (!st->initialized) {
|
|
467
506
|
st->n_cols = in->n_cols;
|
|
468
|
-
st->accums =
|
|
469
|
-
st->col_names =
|
|
470
|
-
if (!st->accums || !st->col_names)
|
|
507
|
+
st->accums = tf_callocarray_checked(in->n_cols ? in->n_cols : 1, sizeof(col_accum));
|
|
508
|
+
st->col_names = tf_callocarray_checked(in->n_cols ? in->n_cols : 1, sizeof(char *));
|
|
509
|
+
if (!st->accums || !st->col_names) {
|
|
510
|
+
stats_clear_accumulation(st);
|
|
511
|
+
return TF_ERROR;
|
|
512
|
+
}
|
|
471
513
|
for (size_t c = 0; c < in->n_cols; c++) {
|
|
472
|
-
st->col_names[c] =
|
|
473
|
-
accum_init(&st->accums[c], st)
|
|
514
|
+
st->col_names[c] = stats_strdup(in->col_names[c]);
|
|
515
|
+
if (!st->col_names[c] || accum_init(&st->accums[c], st) != TF_OK) {
|
|
516
|
+
stats_clear_accumulation(st);
|
|
517
|
+
return TF_ERROR;
|
|
518
|
+
}
|
|
474
519
|
}
|
|
475
520
|
st->initialized = 1;
|
|
476
521
|
}
|
|
477
522
|
|
|
478
523
|
for (size_t r = 0; r < in->n_rows; r++) {
|
|
479
524
|
for (size_t c = 0; c < st->n_cols && c < in->n_cols; c++) {
|
|
525
|
+
col_accum *a = &st->accums[c];
|
|
526
|
+
a->total++;
|
|
480
527
|
if (tf_batch_is_null(in, r, c)) continue;
|
|
481
528
|
|
|
482
529
|
double val = 0;
|
|
@@ -524,7 +571,7 @@ static int stats_process(tf_step *self, tf_batch *in, tf_batch **out,
|
|
|
524
571
|
default:
|
|
525
572
|
break;
|
|
526
573
|
}
|
|
527
|
-
accum_update(
|
|
574
|
+
accum_update(a, val, str_val, is_num);
|
|
528
575
|
}
|
|
529
576
|
}
|
|
530
577
|
|
|
@@ -540,8 +587,10 @@ static int stats_flush(tf_step *self, tf_batch **out, tf_side_channels *side) {
|
|
|
540
587
|
|
|
541
588
|
/* Count output columns */
|
|
542
589
|
size_t n_stat_cols = 1; /* "column" */
|
|
543
|
-
if (st->want_count)
|
|
544
|
-
if (st->
|
|
590
|
+
if (st->want_count) n_stat_cols++;
|
|
591
|
+
if (st->want_missing) n_stat_cols++;
|
|
592
|
+
if (st->want_complete_rate) n_stat_cols++;
|
|
593
|
+
if (st->want_sum) n_stat_cols++;
|
|
545
594
|
if (st->want_avg) n_stat_cols++;
|
|
546
595
|
if (st->want_min) n_stat_cols++;
|
|
547
596
|
if (st->want_max) n_stat_cols++;
|
|
@@ -558,86 +607,102 @@ static int stats_flush(tf_step *self, tf_batch **out, tf_side_channels *side) {
|
|
|
558
607
|
|
|
559
608
|
tf_batch *ob = tf_batch_create(n_stat_cols, st->n_cols);
|
|
560
609
|
if (!ob) return TF_ERROR;
|
|
610
|
+
int rc = TF_ERROR;
|
|
611
|
+
#define STATS_WRITE(expr) do { if ((expr) != TF_OK) goto done; } while (0)
|
|
561
612
|
|
|
562
613
|
/* Set schema */
|
|
563
614
|
size_t ci = 0;
|
|
564
|
-
tf_batch_set_schema(ob, ci++, "column", TF_TYPE_STRING);
|
|
565
|
-
if (st->want_count)
|
|
566
|
-
if (st->
|
|
567
|
-
if (st->
|
|
568
|
-
if (st->
|
|
569
|
-
if (st->
|
|
570
|
-
if (st->
|
|
571
|
-
if (st->
|
|
572
|
-
if (st->
|
|
573
|
-
if (st->
|
|
574
|
-
if (st->
|
|
575
|
-
if (st->
|
|
576
|
-
if (st->
|
|
577
|
-
if (st->
|
|
578
|
-
if (st->
|
|
579
|
-
if (st->
|
|
615
|
+
STATS_WRITE(tf_batch_set_schema(ob, ci++, "column", TF_TYPE_STRING));
|
|
616
|
+
if (st->want_count) STATS_WRITE(tf_batch_set_schema(ob, ci++, "count", TF_TYPE_INT64));
|
|
617
|
+
if (st->want_missing) STATS_WRITE(tf_batch_set_schema(ob, ci++, "missing", TF_TYPE_INT64));
|
|
618
|
+
if (st->want_complete_rate) STATS_WRITE(tf_batch_set_schema(ob, ci++, "complete_rate", TF_TYPE_FLOAT64));
|
|
619
|
+
if (st->want_sum) STATS_WRITE(tf_batch_set_schema(ob, ci++, "sum", TF_TYPE_FLOAT64));
|
|
620
|
+
if (st->want_avg) STATS_WRITE(tf_batch_set_schema(ob, ci++, "avg", TF_TYPE_FLOAT64));
|
|
621
|
+
if (st->want_min) STATS_WRITE(tf_batch_set_schema(ob, ci++, "min", TF_TYPE_FLOAT64));
|
|
622
|
+
if (st->want_max) STATS_WRITE(tf_batch_set_schema(ob, ci++, "max", TF_TYPE_FLOAT64));
|
|
623
|
+
if (st->want_var) STATS_WRITE(tf_batch_set_schema(ob, ci++, "var", TF_TYPE_FLOAT64));
|
|
624
|
+
if (st->want_stddev) STATS_WRITE(tf_batch_set_schema(ob, ci++, "stddev", TF_TYPE_FLOAT64));
|
|
625
|
+
if (st->want_median) STATS_WRITE(tf_batch_set_schema(ob, ci++, "median", TF_TYPE_FLOAT64));
|
|
626
|
+
if (st->want_p25) STATS_WRITE(tf_batch_set_schema(ob, ci++, "p25", TF_TYPE_FLOAT64));
|
|
627
|
+
if (st->want_p75) STATS_WRITE(tf_batch_set_schema(ob, ci++, "p75", TF_TYPE_FLOAT64));
|
|
628
|
+
if (st->want_skewness) STATS_WRITE(tf_batch_set_schema(ob, ci++, "skewness", TF_TYPE_FLOAT64));
|
|
629
|
+
if (st->want_kurtosis) STATS_WRITE(tf_batch_set_schema(ob, ci++, "kurtosis", TF_TYPE_FLOAT64));
|
|
630
|
+
if (st->want_distinct) STATS_WRITE(tf_batch_set_schema(ob, ci++, "distinct", TF_TYPE_INT64));
|
|
631
|
+
if (st->want_hist) STATS_WRITE(tf_batch_set_schema(ob, ci++, "hist", TF_TYPE_STRING));
|
|
632
|
+
if (st->want_sample) STATS_WRITE(tf_batch_set_schema(ob, ci++, "sample", TF_TYPE_STRING));
|
|
580
633
|
|
|
581
634
|
/* One row per input column */
|
|
582
635
|
for (size_t c = 0; c < st->n_cols; c++) {
|
|
583
|
-
tf_batch_ensure_capacity(ob, c + 1);
|
|
636
|
+
STATS_WRITE(tf_batch_ensure_capacity(ob, c + 1));
|
|
584
637
|
ci = 0;
|
|
585
|
-
tf_batch_set_string(ob, c, ci++, st->col_names[c]);
|
|
638
|
+
STATS_WRITE(tf_batch_set_string(ob, c, ci++, st->col_names[c]));
|
|
586
639
|
|
|
587
640
|
col_accum *a = &st->accums[c];
|
|
588
641
|
|
|
589
642
|
if (st->want_count) {
|
|
590
|
-
tf_batch_set_int64(ob, c, ci++, (int64_t)a->count);
|
|
643
|
+
STATS_WRITE(tf_batch_set_int64(ob, c, ci++, (int64_t)a->count));
|
|
644
|
+
}
|
|
645
|
+
if (st->want_missing) {
|
|
646
|
+
size_t missing = a->total >= a->count ? a->total - a->count : 0;
|
|
647
|
+
STATS_WRITE(tf_batch_set_int64(ob, c, ci++, (int64_t)missing));
|
|
648
|
+
}
|
|
649
|
+
if (st->want_complete_rate) {
|
|
650
|
+
if (a->total > 0) {
|
|
651
|
+
STATS_WRITE(tf_batch_set_float64(ob, c, ci, (double)a->count / (double)a->total));
|
|
652
|
+
} else {
|
|
653
|
+
STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
654
|
+
}
|
|
655
|
+
ci++;
|
|
591
656
|
}
|
|
592
657
|
if (st->want_sum) {
|
|
593
|
-
if (a->has_numeric) tf_batch_set_float64(ob, c, ci, a->sum);
|
|
594
|
-
else tf_batch_set_null(ob, c, ci);
|
|
658
|
+
if (a->has_numeric) STATS_WRITE(tf_batch_set_float64(ob, c, ci, a->sum));
|
|
659
|
+
else STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
595
660
|
ci++;
|
|
596
661
|
}
|
|
597
662
|
if (st->want_avg) {
|
|
598
663
|
if (a->has_numeric && a->count > 0)
|
|
599
|
-
tf_batch_set_float64(ob, c, ci, a->sum / (double)a->count);
|
|
600
|
-
else tf_batch_set_null(ob, c, ci);
|
|
664
|
+
STATS_WRITE(tf_batch_set_float64(ob, c, ci, a->sum / (double)a->count));
|
|
665
|
+
else STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
601
666
|
ci++;
|
|
602
667
|
}
|
|
603
668
|
if (st->want_min) {
|
|
604
|
-
if (a->has_numeric && a->count > 0) tf_batch_set_float64(ob, c, ci, a->min);
|
|
605
|
-
else tf_batch_set_null(ob, c, ci);
|
|
669
|
+
if (a->has_numeric && a->count > 0) STATS_WRITE(tf_batch_set_float64(ob, c, ci, a->min));
|
|
670
|
+
else STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
606
671
|
ci++;
|
|
607
672
|
}
|
|
608
673
|
if (st->want_max) {
|
|
609
|
-
if (a->has_numeric && a->count > 0) tf_batch_set_float64(ob, c, ci, a->max);
|
|
610
|
-
else tf_batch_set_null(ob, c, ci);
|
|
674
|
+
if (a->has_numeric && a->count > 0) STATS_WRITE(tf_batch_set_float64(ob, c, ci, a->max));
|
|
675
|
+
else STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
611
676
|
ci++;
|
|
612
677
|
}
|
|
613
678
|
if (st->want_var) {
|
|
614
679
|
if (a->has_numeric && a->count > 1)
|
|
615
|
-
tf_batch_set_float64(ob, c, ci, a->wf_m2 / (double)(a->count - 1));
|
|
616
|
-
else tf_batch_set_null(ob, c, ci);
|
|
680
|
+
STATS_WRITE(tf_batch_set_float64(ob, c, ci, a->wf_m2 / (double)(a->count - 1)));
|
|
681
|
+
else STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
617
682
|
ci++;
|
|
618
683
|
}
|
|
619
684
|
if (st->want_stddev) {
|
|
620
685
|
if (a->has_numeric && a->count > 1)
|
|
621
|
-
tf_batch_set_float64(ob, c, ci, sqrt(a->wf_m2 / (double)(a->count - 1)));
|
|
622
|
-
else tf_batch_set_null(ob, c, ci);
|
|
686
|
+
STATS_WRITE(tf_batch_set_float64(ob, c, ci, sqrt(a->wf_m2 / (double)(a->count - 1))));
|
|
687
|
+
else STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
623
688
|
ci++;
|
|
624
689
|
}
|
|
625
690
|
if (st->want_median) {
|
|
626
691
|
if (a->has_numeric && a->count > 0)
|
|
627
|
-
tf_batch_set_float64(ob, c, ci, p2_value(&a->p2_median));
|
|
628
|
-
else tf_batch_set_null(ob, c, ci);
|
|
692
|
+
STATS_WRITE(tf_batch_set_float64(ob, c, ci, p2_value(&a->p2_median)));
|
|
693
|
+
else STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
629
694
|
ci++;
|
|
630
695
|
}
|
|
631
696
|
if (st->want_p25) {
|
|
632
697
|
if (a->has_numeric && a->count > 0)
|
|
633
|
-
tf_batch_set_float64(ob, c, ci, p2_value(&a->p2_p25));
|
|
634
|
-
else tf_batch_set_null(ob, c, ci);
|
|
698
|
+
STATS_WRITE(tf_batch_set_float64(ob, c, ci, p2_value(&a->p2_p25)));
|
|
699
|
+
else STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
635
700
|
ci++;
|
|
636
701
|
}
|
|
637
702
|
if (st->want_p75) {
|
|
638
703
|
if (a->has_numeric && a->count > 0)
|
|
639
|
-
tf_batch_set_float64(ob, c, ci, p2_value(&a->p2_p75));
|
|
640
|
-
else tf_batch_set_null(ob, c, ci);
|
|
704
|
+
STATS_WRITE(tf_batch_set_float64(ob, c, ci, p2_value(&a->p2_p75)));
|
|
705
|
+
else STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
641
706
|
ci++;
|
|
642
707
|
}
|
|
643
708
|
if (st->want_skewness) {
|
|
@@ -646,11 +711,11 @@ static int stats_flush(tf_step *self, tf_batch **out, tf_side_channels *side) {
|
|
|
646
711
|
double vr = m2 - m1 * m1;
|
|
647
712
|
if (vr > 1e-15) {
|
|
648
713
|
double sk = (m3 - 3.0*m1*vr - m1*m1*m1) / pow(vr, 1.5);
|
|
649
|
-
tf_batch_set_float64(ob, c, ci, sk);
|
|
714
|
+
STATS_WRITE(tf_batch_set_float64(ob, c, ci, sk));
|
|
650
715
|
} else {
|
|
651
|
-
tf_batch_set_float64(ob, c, ci, 0.0);
|
|
716
|
+
STATS_WRITE(tf_batch_set_float64(ob, c, ci, 0.0));
|
|
652
717
|
}
|
|
653
|
-
} else tf_batch_set_null(ob, c, ci);
|
|
718
|
+
} else STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
654
719
|
ci++;
|
|
655
720
|
}
|
|
656
721
|
if (st->want_kurtosis) {
|
|
@@ -661,17 +726,17 @@ static int stats_flush(tf_step *self, tf_batch **out, tf_side_channels *side) {
|
|
|
661
726
|
if (vr > 1e-15) {
|
|
662
727
|
double kt = (m4 - 4.0*m1*m3 + 6.0*m1*m1*m2
|
|
663
728
|
- 3.0*m1*m1*m1*m1) / (vr*vr) - 3.0;
|
|
664
|
-
tf_batch_set_float64(ob, c, ci, kt);
|
|
729
|
+
STATS_WRITE(tf_batch_set_float64(ob, c, ci, kt));
|
|
665
730
|
} else {
|
|
666
|
-
tf_batch_set_float64(ob, c, ci, 0.0);
|
|
731
|
+
STATS_WRITE(tf_batch_set_float64(ob, c, ci, 0.0));
|
|
667
732
|
}
|
|
668
|
-
} else tf_batch_set_null(ob, c, ci);
|
|
733
|
+
} else STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
669
734
|
ci++;
|
|
670
735
|
}
|
|
671
736
|
if (st->want_distinct) {
|
|
672
737
|
if (a->hll && a->count > 0)
|
|
673
|
-
tf_batch_set_int64(ob, c, ci, (int64_t)round(hll_estimate(a->hll)));
|
|
674
|
-
else tf_batch_set_null(ob, c, ci);
|
|
738
|
+
STATS_WRITE(tf_batch_set_int64(ob, c, ci, (int64_t)round(hll_estimate(a->hll))));
|
|
739
|
+
else STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
675
740
|
ci++;
|
|
676
741
|
}
|
|
677
742
|
if (st->want_hist) {
|
|
@@ -684,9 +749,9 @@ static int stats_flush(tf_step *self, tf_batch **out, tf_side_channels *side) {
|
|
|
684
749
|
if (b > 0) buf[pos++] = ',';
|
|
685
750
|
pos += snprintf(buf + pos, sizeof(buf) - pos, "%zu", a->hist->counts[b]);
|
|
686
751
|
}
|
|
687
|
-
tf_batch_set_string(ob, c, ci, buf);
|
|
752
|
+
STATS_WRITE(tf_batch_set_string(ob, c, ci, buf));
|
|
688
753
|
} else {
|
|
689
|
-
tf_batch_set_null(ob, c, ci);
|
|
754
|
+
STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
690
755
|
}
|
|
691
756
|
ci++;
|
|
692
757
|
}
|
|
@@ -700,38 +765,83 @@ static int stats_flush(tf_step *self, tf_batch **out, tf_side_channels *side) {
|
|
|
700
765
|
pos += snprintf(buf + pos, sizeof(buf) - pos,
|
|
701
766
|
"%.6g", a->reservoir->values[s]);
|
|
702
767
|
}
|
|
703
|
-
tf_batch_set_string(ob, c, ci, buf);
|
|
768
|
+
STATS_WRITE(tf_batch_set_string(ob, c, ci, buf));
|
|
704
769
|
} else {
|
|
705
|
-
tf_batch_set_null(ob, c, ci);
|
|
770
|
+
STATS_WRITE(tf_batch_set_null(ob, c, ci));
|
|
706
771
|
}
|
|
707
772
|
ci++;
|
|
708
773
|
}
|
|
709
|
-
ob
|
|
774
|
+
STATS_WRITE(tf_batch_expose_row(ob, c));
|
|
710
775
|
}
|
|
711
776
|
|
|
712
777
|
*out = ob;
|
|
713
|
-
|
|
778
|
+
ob = NULL;
|
|
779
|
+
rc = TF_OK;
|
|
780
|
+
|
|
781
|
+
done:
|
|
782
|
+
if (ob) tf_batch_free(ob);
|
|
783
|
+
#undef STATS_WRITE
|
|
784
|
+
return rc;
|
|
714
785
|
}
|
|
715
786
|
|
|
716
787
|
static void stats_destroy(tf_step *self) {
|
|
717
788
|
stats_state *st = self->state;
|
|
718
789
|
if (st) {
|
|
719
|
-
|
|
720
|
-
for (size_t i = 0; i < st->n_cols; i++)
|
|
721
|
-
accum_free(&st->accums[i]);
|
|
722
|
-
free(st->accums);
|
|
723
|
-
}
|
|
724
|
-
if (st->col_names) {
|
|
725
|
-
for (size_t i = 0; i < st->n_cols; i++) free(st->col_names[i]);
|
|
726
|
-
free(st->col_names);
|
|
727
|
-
}
|
|
790
|
+
stats_clear_accumulation(st);
|
|
728
791
|
free(st);
|
|
729
792
|
}
|
|
730
793
|
free(self);
|
|
731
794
|
}
|
|
732
795
|
|
|
733
|
-
|
|
734
|
-
|
|
796
|
+
static void stats_enable_name(stats_state *st, const char *s) {
|
|
797
|
+
if (strcmp(s, "count") == 0) st->want_count = 1;
|
|
798
|
+
else if (strcmp(s, "missing") == 0) st->want_missing = 1;
|
|
799
|
+
else if (strcmp(s, "complete_rate") == 0) st->want_complete_rate = 1;
|
|
800
|
+
else if (strcmp(s, "sum") == 0) st->want_sum = 1;
|
|
801
|
+
else if (strcmp(s, "avg") == 0) st->want_avg = 1;
|
|
802
|
+
else if (strcmp(s, "min") == 0) st->want_min = 1;
|
|
803
|
+
else if (strcmp(s, "max") == 0) st->want_max = 1;
|
|
804
|
+
else if (strcmp(s, "var") == 0) st->want_var = 1;
|
|
805
|
+
else if (strcmp(s, "stddev") == 0) st->want_stddev = 1;
|
|
806
|
+
else if (strcmp(s, "median") == 0) st->want_median = 1;
|
|
807
|
+
else if (strcmp(s, "p25") == 0) st->want_p25 = 1;
|
|
808
|
+
else if (strcmp(s, "p75") == 0) st->want_p75 = 1;
|
|
809
|
+
else if (strcmp(s, "skewness") == 0) st->want_skewness = 1;
|
|
810
|
+
else if (strcmp(s, "kurtosis") == 0) st->want_kurtosis = 1;
|
|
811
|
+
else if (strcmp(s, "distinct") == 0) st->want_distinct = 1;
|
|
812
|
+
else if (strcmp(s, "hist") == 0) st->want_hist = 1;
|
|
813
|
+
else if (strcmp(s, "sample") == 0) st->want_sample = 1;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
static void stats_enable_default(stats_state *st) {
|
|
817
|
+
st->want_count = 1;
|
|
818
|
+
st->want_sum = 1;
|
|
819
|
+
st->want_avg = 1;
|
|
820
|
+
st->want_min = 1;
|
|
821
|
+
st->want_max = 1;
|
|
822
|
+
st->want_var = 1;
|
|
823
|
+
st->want_stddev = 1;
|
|
824
|
+
st->want_median = 1;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
static void scan_enable_default(stats_state *st) {
|
|
828
|
+
st->want_count = 1;
|
|
829
|
+
st->want_missing = 1;
|
|
830
|
+
st->want_complete_rate = 1;
|
|
831
|
+
st->want_distinct = 1;
|
|
832
|
+
st->want_min = 1;
|
|
833
|
+
st->want_max = 1;
|
|
834
|
+
st->want_avg = 1;
|
|
835
|
+
st->want_stddev = 1;
|
|
836
|
+
st->want_p25 = 1;
|
|
837
|
+
st->want_median = 1;
|
|
838
|
+
st->want_p75 = 1;
|
|
839
|
+
st->want_hist = 1;
|
|
840
|
+
st->want_sample = 1;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
static tf_step *stats_create_common(const cJSON *args, int scan_defaults) {
|
|
844
|
+
stats_state *st = tf_callocarray_checked(1, sizeof(stats_state));
|
|
735
845
|
if (!st) return NULL;
|
|
736
846
|
|
|
737
847
|
cJSON *stats_arr = args ? cJSON_GetObjectItemCaseSensitive(args, "stats") : NULL;
|
|
@@ -739,37 +849,15 @@ tf_step *tf_stats_create(const cJSON *args) {
|
|
|
739
849
|
int n = cJSON_GetArraySize(stats_arr);
|
|
740
850
|
for (int i = 0; i < n; i++) {
|
|
741
851
|
cJSON *item = cJSON_GetArrayItem(stats_arr, i);
|
|
742
|
-
if (
|
|
743
|
-
const char *s = item->valuestring;
|
|
744
|
-
if (strcmp(s, "count") == 0) st->want_count = 1;
|
|
745
|
-
else if (strcmp(s, "sum") == 0) st->want_sum = 1;
|
|
746
|
-
else if (strcmp(s, "avg") == 0) st->want_avg = 1;
|
|
747
|
-
else if (strcmp(s, "min") == 0) st->want_min = 1;
|
|
748
|
-
else if (strcmp(s, "max") == 0) st->want_max = 1;
|
|
749
|
-
else if (strcmp(s, "var") == 0) st->want_var = 1;
|
|
750
|
-
else if (strcmp(s, "stddev") == 0) st->want_stddev = 1;
|
|
751
|
-
else if (strcmp(s, "median") == 0) st->want_median = 1;
|
|
752
|
-
else if (strcmp(s, "p25") == 0) st->want_p25 = 1;
|
|
753
|
-
else if (strcmp(s, "p75") == 0) st->want_p75 = 1;
|
|
754
|
-
else if (strcmp(s, "skewness") == 0) st->want_skewness = 1;
|
|
755
|
-
else if (strcmp(s, "kurtosis") == 0) st->want_kurtosis = 1;
|
|
756
|
-
else if (strcmp(s, "distinct") == 0) st->want_distinct = 1;
|
|
757
|
-
else if (strcmp(s, "hist") == 0) st->want_hist = 1;
|
|
758
|
-
else if (strcmp(s, "sample") == 0) st->want_sample = 1;
|
|
852
|
+
if (cJSON_IsString(item)) stats_enable_name(st, item->valuestring);
|
|
759
853
|
}
|
|
854
|
+
} else if (scan_defaults) {
|
|
855
|
+
scan_enable_default(st);
|
|
760
856
|
} else {
|
|
761
|
-
|
|
762
|
-
st->want_count = 1;
|
|
763
|
-
st->want_sum = 1;
|
|
764
|
-
st->want_avg = 1;
|
|
765
|
-
st->want_min = 1;
|
|
766
|
-
st->want_max = 1;
|
|
767
|
-
st->want_var = 1;
|
|
768
|
-
st->want_stddev = 1;
|
|
769
|
-
st->want_median = 1;
|
|
857
|
+
stats_enable_default(st);
|
|
770
858
|
}
|
|
771
859
|
|
|
772
|
-
tf_step *step =
|
|
860
|
+
tf_step *step = tf_callocarray_checked(1, sizeof(tf_step));
|
|
773
861
|
if (!step) { free(st); return NULL; }
|
|
774
862
|
step->process = stats_process;
|
|
775
863
|
step->flush = stats_flush;
|
|
@@ -777,3 +865,11 @@ tf_step *tf_stats_create(const cJSON *args) {
|
|
|
777
865
|
step->state = st;
|
|
778
866
|
return step;
|
|
779
867
|
}
|
|
868
|
+
|
|
869
|
+
tf_step *tf_stats_create(const cJSON *args) {
|
|
870
|
+
return stats_create_common(args, 0);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
tf_step *tf_scan_create(const cJSON *args) {
|
|
874
|
+
return stats_create_common(args, 1);
|
|
875
|
+
}
|