diff --git a/Cargo.lock b/Cargo.lock index 0072c7b1749..c0814785539 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6232,6 +6232,8 @@ dependencies = [ "omicron-common", "omicron-workspace-hack", "oximeter-macro-impl", + "rand 0.8.5", + "rand_distr", "regex", "rstest", "schemars", @@ -7463,6 +7465,16 @@ dependencies = [ "getrandom 0.2.14", ] +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "rand_hc" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 3c8a722c7f4..d83d0f1e74c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -402,6 +402,7 @@ proptest = "1.4.0" quote = "1.0" rand = "0.8.5" rand_core = "0.6.4" +rand_distr = "0.4.3" rand_seeder = "0.2.3" ratatui = "0.26.2" rayon = "1.10" diff --git a/openapi/nexus.json b/openapi/nexus.json index b358e387cd0..ab41e2083b9 100644 --- a/openapi/nexus.json +++ b/openapi/nexus.json @@ -12328,19 +12328,34 @@ "format": "double" }, "p50": { - "$ref": "#/components/schemas/Quantile" + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/Quantile" + } + ] }, "p90": { - "$ref": "#/components/schemas/Quantile" + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/Quantile" + } + ] }, "p99": { - "$ref": "#/components/schemas/Quantile" + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/Quantile" + } + ] }, - "sum_of_samples": { + "squared_mean": { "type": "number", "format": "double" }, - "sum_of_squares": { + "sum_of_samples": { "type": "number", "format": "double" } @@ -12348,11 +12363,8 @@ "required": [ "bins", "counts", - "p50", - "p90", - "p99", - "sum_of_samples", - "sum_of_squares" + "squared_mean", + "sum_of_samples" ] }, "Distributionint64": { @@ -12385,19 +12397,34 @@ "format": "int64" }, "p50": { - "$ref": "#/components/schemas/Quantile" + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/Quantile" + } + ] }, "p90": { - "$ref": "#/components/schemas/Quantile" + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/Quantile" + } + ] }, "p99": { - "$ref": "#/components/schemas/Quantile" + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/Quantile" + } + ] }, - "sum_of_samples": { - "type": "integer", - "format": "int64" + "squared_mean": { + "type": "number", + "format": "double" }, - "sum_of_squares": { + "sum_of_samples": { "type": "integer", "format": "int64" } @@ -12405,11 +12432,8 @@ "required": [ "bins", "counts", - "p50", - "p90", - "p99", - "sum_of_samples", - "sum_of_squares" + "squared_mean", + "sum_of_samples" ] }, "EphemeralIpCreate": { @@ -13212,6 +13236,11 @@ } ] }, + "squared_mean": { + "description": "M2 for Welford's algorithm for variance calculation.\n\nRead more on Welford's algorithm at ", + "type": "number", + "format": "double" + }, "start_time": { "description": "The start time of the histogram.", "type": "string", @@ -13221,11 +13250,6 @@ "description": "The sum of all samples in the histogram.", "type": "number", "format": "double" - }, - "sum_of_squares": { - "description": "The sum of the squares of all samples in the histogram.", - "type": "number", - "format": "double" } }, "required": [ @@ -13236,9 +13260,9 @@ "p50", "p90", "p99", + "squared_mean", "start_time", - "sum_of_samples", - "sum_of_squares" + "sum_of_samples" ] }, "Histogramfloat": { @@ -13292,6 +13316,11 @@ } ] }, + "squared_mean": { + "description": "M2 for Welford's algorithm for variance calculation.\n\nRead more on Welford's algorithm at ", + "type": "number", + "format": "double" + }, "start_time": { "description": "The start time of the histogram.", "type": "string", @@ -13301,11 +13330,6 @@ "description": "The sum of all samples in the histogram.", "type": "number", "format": "double" - }, - "sum_of_squares": { - "description": "The sum of the squares of all samples in the histogram.", - "type": "number", - "format": "double" } }, "required": [ @@ -13316,9 +13340,9 @@ "p50", "p90", "p99", + "squared_mean", "start_time", - "sum_of_samples", - "sum_of_squares" + "sum_of_samples" ] }, "Histogramint16": { @@ -13372,6 +13396,11 @@ } ] }, + "squared_mean": { + "description": "M2 for Welford's algorithm for variance calculation.\n\nRead more on Welford's algorithm at ", + "type": "number", + "format": "double" + }, "start_time": { "description": "The start time of the histogram.", "type": "string", @@ -13381,11 +13410,6 @@ "description": "The sum of all samples in the histogram.", "type": "integer", "format": "int64" - }, - "sum_of_squares": { - "description": "The sum of the squares of all samples in the histogram.", - "type": "integer", - "format": "int64" } }, "required": [ @@ -13396,9 +13420,9 @@ "p50", "p90", "p99", + "squared_mean", "start_time", - "sum_of_samples", - "sum_of_squares" + "sum_of_samples" ] }, "Histogramint32": { @@ -13452,6 +13476,11 @@ } ] }, + "squared_mean": { + "description": "M2 for Welford's algorithm for variance calculation.\n\nRead more on Welford's algorithm at ", + "type": "number", + "format": "double" + }, "start_time": { "description": "The start time of the histogram.", "type": "string", @@ -13461,11 +13490,6 @@ "description": "The sum of all samples in the histogram.", "type": "integer", "format": "int64" - }, - "sum_of_squares": { - "description": "The sum of the squares of all samples in the histogram.", - "type": "integer", - "format": "int64" } }, "required": [ @@ -13476,9 +13500,9 @@ "p50", "p90", "p99", + "squared_mean", "start_time", - "sum_of_samples", - "sum_of_squares" + "sum_of_samples" ] }, "Histogramint64": { @@ -13532,6 +13556,11 @@ } ] }, + "squared_mean": { + "description": "M2 for Welford's algorithm for variance calculation.\n\nRead more on Welford's algorithm at ", + "type": "number", + "format": "double" + }, "start_time": { "description": "The start time of the histogram.", "type": "string", @@ -13541,11 +13570,6 @@ "description": "The sum of all samples in the histogram.", "type": "integer", "format": "int64" - }, - "sum_of_squares": { - "description": "The sum of the squares of all samples in the histogram.", - "type": "integer", - "format": "int64" } }, "required": [ @@ -13556,9 +13580,9 @@ "p50", "p90", "p99", + "squared_mean", "start_time", - "sum_of_samples", - "sum_of_squares" + "sum_of_samples" ] }, "Histogramint8": { @@ -13612,6 +13636,11 @@ } ] }, + "squared_mean": { + "description": "M2 for Welford's algorithm for variance calculation.\n\nRead more on Welford's algorithm at ", + "type": "number", + "format": "double" + }, "start_time": { "description": "The start time of the histogram.", "type": "string", @@ -13621,11 +13650,6 @@ "description": "The sum of all samples in the histogram.", "type": "integer", "format": "int64" - }, - "sum_of_squares": { - "description": "The sum of the squares of all samples in the histogram.", - "type": "integer", - "format": "int64" } }, "required": [ @@ -13636,9 +13660,9 @@ "p50", "p90", "p99", + "squared_mean", "start_time", - "sum_of_samples", - "sum_of_squares" + "sum_of_samples" ] }, "Histogramuint16": { @@ -13694,6 +13718,11 @@ } ] }, + "squared_mean": { + "description": "M2 for Welford's algorithm for variance calculation.\n\nRead more on Welford's algorithm at ", + "type": "number", + "format": "double" + }, "start_time": { "description": "The start time of the histogram.", "type": "string", @@ -13703,11 +13732,6 @@ "description": "The sum of all samples in the histogram.", "type": "integer", "format": "int64" - }, - "sum_of_squares": { - "description": "The sum of the squares of all samples in the histogram.", - "type": "integer", - "format": "int64" } }, "required": [ @@ -13718,9 +13742,9 @@ "p50", "p90", "p99", + "squared_mean", "start_time", - "sum_of_samples", - "sum_of_squares" + "sum_of_samples" ] }, "Histogramuint32": { @@ -13776,6 +13800,11 @@ } ] }, + "squared_mean": { + "description": "M2 for Welford's algorithm for variance calculation.\n\nRead more on Welford's algorithm at ", + "type": "number", + "format": "double" + }, "start_time": { "description": "The start time of the histogram.", "type": "string", @@ -13785,11 +13814,6 @@ "description": "The sum of all samples in the histogram.", "type": "integer", "format": "int64" - }, - "sum_of_squares": { - "description": "The sum of the squares of all samples in the histogram.", - "type": "integer", - "format": "int64" } }, "required": [ @@ -13800,9 +13824,9 @@ "p50", "p90", "p99", + "squared_mean", "start_time", - "sum_of_samples", - "sum_of_squares" + "sum_of_samples" ] }, "Histogramuint64": { @@ -13858,6 +13882,11 @@ } ] }, + "squared_mean": { + "description": "M2 for Welford's algorithm for variance calculation.\n\nRead more on Welford's algorithm at ", + "type": "number", + "format": "double" + }, "start_time": { "description": "The start time of the histogram.", "type": "string", @@ -13867,11 +13896,6 @@ "description": "The sum of all samples in the histogram.", "type": "integer", "format": "int64" - }, - "sum_of_squares": { - "description": "The sum of the squares of all samples in the histogram.", - "type": "integer", - "format": "int64" } }, "required": [ @@ -13882,9 +13906,9 @@ "p50", "p90", "p99", + "squared_mean", "start_time", - "sum_of_samples", - "sum_of_squares" + "sum_of_samples" ] }, "Histogramuint8": { @@ -13940,6 +13964,11 @@ } ] }, + "squared_mean": { + "description": "M2 for Welford's algorithm for variance calculation.\n\nRead more on Welford's algorithm at ", + "type": "number", + "format": "double" + }, "start_time": { "description": "The start time of the histogram.", "type": "string", @@ -13949,11 +13978,6 @@ "description": "The sum of all samples in the histogram.", "type": "integer", "format": "int64" - }, - "sum_of_squares": { - "description": "The sum of the squares of all samples in the histogram.", - "type": "integer", - "format": "int64" } }, "required": [ @@ -13964,9 +13988,9 @@ "p50", "p90", "p99", + "squared_mean", "start_time", - "sum_of_samples", - "sum_of_squares" + "sum_of_samples" ] }, "Hostname": { @@ -16359,19 +16383,9 @@ } }, "Quantile": { - "description": "Structure for estimating the p-quantile of a population.\n\nThis is based on the P² algorithm for estimating quantiles using constant space.\n\nThe algorithm consists of maintaining five markers: the minimum, the p/2-, p-, and (1 + p)/2 quantiles, and the maximum.\n\nRead for more.", + "description": "Structure for estimating the p-quantile of a population.\n\nThis is based on the P² algorithm for estimating quantiles using constant space.\n\nThe algorithm consists of maintaining five markers: the minimum, the p/2-, p-, and (1 + p)/2 quantiles, and the maximum.", "type": "object", "properties": { - "desired_marker_increments": { - "description": "The increment for the desired marker positions.", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "minItems": 5, - "maxItems": 5 - }, "desired_marker_positions": { "description": "The desired marker positions.", "type": "array", @@ -16393,21 +16407,27 @@ "maxItems": 5 }, "marker_positions": { - "description": "The positions of the markers.", + "description": "The positions of the markers.\n\nWe track sample size in the 5th position, as useful observations won't start until we've filled the heights at the 6th sample anyway This does deviate from the paper, but it's a more useful representation that works according to the paper's algorithm.", "type": "array", "items": { "type": "integer", - "format": "int64" + "format": "uint64", + "minimum": 0 }, "minItems": 5, "maxItems": 5 + }, + "p": { + "description": "The p value for the quantile.", + "type": "number", + "format": "double" } }, "required": [ - "desired_marker_increments", "desired_marker_positions", "marker_heights", - "marker_positions" + "marker_positions", + "p" ] }, "Rack": { diff --git a/oximeter/db/schema/replicated/5/up.sql b/oximeter/db/schema/replicated/5/up.sql index 8cbe4a18d45..30d9e694dab 100644 --- a/oximeter/db/schema/replicated/5/up.sql +++ b/oximeter/db/schema/replicated/5/up.sql @@ -1,340 +1,279 @@ ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN min Int8; ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN max Int8; ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN min Int8; ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN max Int8; ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN min Int16; ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN max Int16; ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN min Int16; ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN max Int16; ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); - ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN min Int32; ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN max Int32; ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN min Int32; ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN max Int32; ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN min Int64; ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN max Int64; ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN min Int64; ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN max Int64; ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN min UInt8; ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN max UInt8; ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN min UInt8; ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN max UInt8; ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN min UInt16; ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN max UInt16; ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN min UInt16; ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN max UInt16; ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN min UInt32; ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN max UInt32; ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN min UInt32; ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN max UInt32; ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN min UNINT64; ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN max UNINT64; ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN min UNINT64; ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN max UNINT64; ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN min Float32; ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN max Float32; ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Float64; -ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Float64; +ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN min Float32; ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN max Float32; ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Float64; -ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Float64; +ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN min Float64; ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN max Float64; ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Float64; -ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Float64; +ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64_local ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN min Float64; ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN max Float64; ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_samples Float64; -ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN sum_of_squares Float64; +ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64 ON CLUSTER oximeter_cluster ADD COLUMN p99_desired_marker_increments Array(Float64); diff --git a/oximeter/db/schema/replicated/db-init.sql b/oximeter/db/schema/replicated/db-init.sql index ca2da18016a..7674f14e5fd 100644 --- a/oximeter/db/schema/replicated/db-init.sql +++ b/oximeter/db/schema/replicated/db-init.sql @@ -378,19 +378,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogrami8_local ON CLUSTER ox min Int8, max Int8, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/measurements_histogrami8_local', '{replica}') ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -407,19 +404,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogrami8 ON CLUSTER oximeter min Int8, max Int8, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = Distributed('oximeter_cluster', 'oximeter', 'measurements_histogrami8_local', xxHash64(splitByChar(':', timeseries_name)[1])); @@ -434,19 +428,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramu8_local ON CLUSTER ox min UInt8, max UInt8, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/measurements_histogramu8_local', '{replica}') ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -463,19 +454,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramu8 ON CLUSTER oximeter min UInt8, max UInt8, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = Distributed('oximeter_cluster', 'oximeter', 'measurements_histogramu8_local', xxHash64(splitByChar(':', timeseries_name)[1])); @@ -490,19 +478,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogrami16_local ON CLUSTER o min Int16, max Int16, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/measurements_histogrami16_local', '{replica}') ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -519,19 +504,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogrami16 ON CLUSTER oximete min Int16, max Int16, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = Distributed('oximeter_cluster', 'oximeter', 'measurements_histogrami16_local', xxHash64(splitByChar(':', timeseries_name)[1])); @@ -546,19 +528,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramu16_local ON CLUSTER o min UInt16, max UInt16, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/measurements_histogramu16_local', '{replica}') ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -575,19 +554,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramu16 ON CLUSTER oximete min UInt16, max UInt16, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = Distributed('oximeter_cluster', 'oximeter', 'measurements_histogramu16_local', xxHash64(splitByChar(':', timeseries_name)[1])); @@ -602,19 +578,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogrami32_local ON CLUSTER o min Int32, max Int32, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/measurements_histogrami32_local', '{replica}') ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -631,19 +604,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogrami32 ON CLUSTER oximete min Int32, max Int32, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = Distributed('oximeter_cluster', 'oximeter', 'measurements_histogrami32_local', xxHash64(splitByChar(':', timeseries_name)[1])); @@ -658,19 +628,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramu32_local ON CLUSTER o min UInt32, max UInt32, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/measurements_histogramu32_local', '{replica}') ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -687,19 +654,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramu32 ON CLUSTER oximete min UInt32, max UInt32, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = Distributed('oximeter_cluster', 'oximeter', 'measurements_histogramu32_local', xxHash64(splitByChar(':', timeseries_name)[1])); @@ -714,19 +678,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogrami64_local ON CLUSTER o min Int64, max Int64, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/measurements_histogrami64_local', '{replica}') ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -743,19 +704,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogrami64 ON CLUSTER oximete min Int64, max Int64, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = Distributed('oximeter_cluster', 'oximeter', 'measurements_histogrami64_local', xxHash64(splitByChar(':', timeseries_name)[1])); @@ -770,19 +728,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramu64_local ON CLUSTER o min UInt64, max UInt64, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/measurements_histogramu64_local', '{replica}') ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -799,19 +754,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramu64 ON CLUSTER oximete min UInt64, max UInt64, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = Distributed('oximeter_cluster', 'oximeter', 'measurements_histogramu64_local', xxHash64(splitByChar(':', timeseries_name)[1])); @@ -826,19 +778,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramf32_local ON CLUSTER o min Float32, max Float32, sum_of_samples Float64, - sum_of_squares Float64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/measurements_histogramf32_local', '{replica}') ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -855,19 +804,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramf32 ON CLUSTER oximete min Float32, max Float32, sum_of_samples Float64, - sum_of_squares Float64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = Distributed('oximeter_cluster', 'oximeter', 'measurements_histogramf32_local', xxHash64(splitByChar(':', timeseries_name)[1])); @@ -882,19 +828,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramf64_local ON CLUSTER o min Float64, max Float64, sum_of_samples Float64, - sum_of_squares Float64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/measurements_histogramf64_local', '{replica}') ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -911,19 +854,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramf64 ON CLUSTER oximete min Float64, max Float64, sum_of_samples Float64, - sum_of_squares Float64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = Distributed('oximeter_cluster', 'oximeter', 'measurements_histogramf64_local', xxHash64(splitByChar(':', timeseries_name)[1])); diff --git a/oximeter/db/schema/single-node/5/up.sql b/oximeter/db/schema/single-node/5/up.sql index 9bef98e8707..6f4d55392f1 100644 --- a/oximeter/db/schema/single-node/5/up.sql +++ b/oximeter/db/schema/single-node/5/up.sql @@ -1,170 +1,139 @@ ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN min Int8; ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN max Int8; ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami8 ADD COLUMN p99_desired_marker_increments Array(Float64); - ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN min Int16; ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN max Int16; ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami16 ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN min Int32; ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN max Int32; ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami32 ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN min Int64; ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN max Int64; ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogrami64 ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN min UInt8; ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN max UInt8; ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu8 ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN min UInt16; ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN max UInt16; ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu16 ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN min UInt32; ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN max UInt32; ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu32 ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN min UInt64; ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN max UInt64; ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN sum_of_samples Int64; -ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN sum_of_squares Int64; +ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramu64 ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN min Float32; ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN max Float32; ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN sum_of_samples Float64; -ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN sum_of_squares Float64; +ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf32 ADD COLUMN p99_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN min Float64; ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN max Float64; ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN sum_of_samples Float64; -ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN sum_of_squares Float64; +ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN squared_mean Float64; ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p50_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p50_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p50_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p50_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p50_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p90_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p90_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p90_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p90_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p90_desired_marker_increments Array(Float64); ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p99_marker_heights Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p99_marker_positions Array(Int64); +ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p99_marker_positions Array(UInt64); ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p99_desired_marker_positions Array(Float64); -ALTER TABLE oximeter.measurements_histogramf64 ADD COLUMN p99_desired_marker_increments Array(Float64); diff --git a/oximeter/db/schema/single-node/db-init.sql b/oximeter/db/schema/single-node/db-init.sql index 78772981ca7..38e9d0b70c7 100644 --- a/oximeter/db/schema/single-node/db-init.sql +++ b/oximeter/db/schema/single-node/db-init.sql @@ -239,19 +239,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogrami8 min Int8, max Int8, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = MergeTree() ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -268,19 +265,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramu8 min UInt8, max UInt8, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = MergeTree() ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -297,19 +291,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogrami16 min Int16, max Int16, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = MergeTree() ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -326,19 +317,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramu16 min UInt16, max UInt16, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = MergeTree() ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -355,19 +343,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogrami32 min Int32, max Int32, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = MergeTree() ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -384,19 +369,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramu32 min UInt32, max UInt32, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = MergeTree() ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -413,19 +395,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogrami64 min Int64, max Int64, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = MergeTree() ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -442,19 +421,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramu64 min UInt64, max UInt64, sum_of_samples Int64, - sum_of_squares Int64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = MergeTree() ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -471,19 +447,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramf32 min Float32, max Float32, sum_of_samples Float64, - sum_of_squares Float64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = MergeTree() ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) @@ -500,19 +473,16 @@ CREATE TABLE IF NOT EXISTS oximeter.measurements_histogramf64 min Float64, max Float64, sum_of_samples Float64, - sum_of_squares Float64, + squared_mean Float64, p50_marker_heights Array(Float64), - p50_marker_positions Array(Int64), + p50_marker_positions Array(UInt64), p50_desired_marker_positions Array(Float64), - p50_desired_marker_increments Array(Float64), p90_marker_heights Array(Float64), - p90_marker_positions Array(Int64), + p90_marker_positions Array(UInt64), p90_desired_marker_positions Array(Float64), - p90_desired_marker_increments Array(Float64), p99_marker_heights Array(Float64), - p99_marker_positions Array(Int64), - p99_desired_marker_positions Array(Float64), - p99_desired_marker_increments Array(Float64) + p99_marker_positions Array(UInt64), + p99_desired_marker_positions Array(Float64) ) ENGINE = MergeTree() ORDER BY (timeseries_name, timeseries_key, start_time, timestamp) diff --git a/oximeter/db/src/bin/oxdb/oxql.rs b/oximeter/db/src/bin/oxdb/oxql.rs index cc7982bdbce..ebe55dc7a77 100644 --- a/oximeter/db/src/bin/oxdb/oxql.rs +++ b/oximeter/db/src/bin/oxdb/oxql.rs @@ -185,7 +185,7 @@ pub(crate) fn prepare_columns( cols.push(special_idents::SUM_OF_SAMPLES.into()); types.push(special_idents::UINT64.into()); - cols.push(special_idents::SUM_OF_SQUARES.into()); + cols.push(special_idents::SQUARED_MEAN.into()); types.push(special_idents::UINT64.into()); for quantile in ["P50", "P90", "P99"].iter() { @@ -195,8 +195,6 @@ pub(crate) fn prepare_columns( types.push(special_idents::ARRAYINT64.into()); cols.push(format!("{}_DESIRED_MARKER_POSITIONS", quantile)); types.push(special_idents::ARRAYFLOAT64.into()); - cols.push(format!("{}_DESIRED_MARKER_INCREMENTS", quantile)); - types.push(special_idents::ARRAYFLOAT64.into()); } } else if schema.datum_type.is_cumulative() { cols.push(special_idents::START_TIME.into()); diff --git a/oximeter/db/src/client/oxql.rs b/oximeter/db/src/client/oxql.rs index 24844bd3c84..b389179b7aa 100644 --- a/oximeter/db/src/client/oxql.rs +++ b/oximeter/db/src/client/oxql.rs @@ -826,13 +826,13 @@ impl Client { ) -> String { let value_columns = if datum_type.is_histogram() { r#"timeseries_key, start_time, timestamp, bins, counts, min, max, - sum_of_samples, sum_of_squares, + sum_of_samples, squared_mean, p50_marker_heights, p50_marker_positions, - p50_desired_marker_positions, p50_desired_marker_increments, + p50_desired_marker_positions, p90_marker_heights, p90_marker_positions, - p90_desired_marker_positions, p90_desired_marker_increments + p90_desired_marker_positions, p99_marker_heights, p99_marker_positions, - p99_desired_marker_positions, p99_desired_marker_increments"# + p99_desired_marker_positions"# } else if datum_type.is_cumulative() { "timeseries_key, start_time, timestamp, datum" } else { @@ -1210,7 +1210,7 @@ mod tests { // Create the first metric, starting from a count of 0. let mut metric = SomeMetric { foo: *foo, datum }; - // Create all the samples,, incrementing the datum and sample + // Create all the samples, incrementing the datum and sample // time. for i in 0..N_SAMPLES_PER_TIMESERIES { let sample_time = diff --git a/oximeter/db/src/model.rs b/oximeter/db/src/model.rs index 7531cd287f0..e7f9f56b633 100644 --- a/oximeter/db/src/model.rs +++ b/oximeter/db/src/model.rs @@ -449,64 +449,60 @@ declare_cumulative_measurement_row! { CumulativeF32MeasurementRow, f32, "cumulat declare_cumulative_measurement_row! { CumulativeF64MeasurementRow, f64, "cumulativef64" } /// A representation of all quantiles for a histogram. -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq)] struct AllQuantiles { p50_marker_heights: [f64; 5], - p50_marker_positions: [i64; 5], + p50_marker_positions: [u64; 5], p50_desired_marker_positions: [f64; 5], - p50_desired_marker_increments: [f64; 5], p90_marker_heights: [f64; 5], - p90_marker_positions: [i64; 5], + p90_marker_positions: [u64; 5], p90_desired_marker_positions: [f64; 5], - p90_desired_marker_increments: [f64; 5], p99_marker_heights: [f64; 5], - p99_marker_positions: [i64; 5], + p99_marker_positions: [u64; 5], p99_desired_marker_positions: [f64; 5], - p99_desired_marker_increments: [f64; 5], } impl AllQuantiles { /// Create a flat `AllQuantiles` struct from the given quantiles. - fn flatten(p50: Quantile, p90: Quantile, p99: Quantile) -> Self { + fn flatten(q50: Quantile, q90: Quantile, q99: Quantile) -> Self { Self { - p50_marker_heights: p50.marker_hghts, - p50_marker_positions: p50.marker_pos, - p50_desired_marker_positions: p50.desired_marker_pos, - p50_desired_marker_increments: p50.desired_marker_incrs, - p90_marker_heights: p90.marker_hghts, - p90_marker_positions: p90.marker_pos, - p90_desired_marker_positions: p90.desired_marker_pos, - p90_desired_marker_increments: p90.desired_marker_incrs, - p99_marker_heights: p99.marker_hghts, - p99_marker_positions: p99.marker_pos, - p99_desired_marker_positions: p99.desired_marker_pos, - p99_desired_marker_increments: p99.desired_marker_incrs, + p50_marker_heights: q50.marker_heights(), + p50_marker_positions: q50.marker_positions(), + p50_desired_marker_positions: q50.desired_marker_positions(), + + p90_marker_heights: q90.marker_heights(), + p90_marker_positions: q90.marker_positions(), + p90_desired_marker_positions: q90.desired_marker_positions(), + + p99_marker_heights: q99.marker_heights(), + p99_marker_positions: q99.marker_positions(), + p99_desired_marker_positions: q99.desired_marker_positions(), } } /// Split the quantiles into separate `Quantile` structs in order of P. fn split(&self) -> (Quantile, Quantile, Quantile) { ( - Quantile { - marker_hghts: self.p50_marker_heights, - marker_pos: self.p50_marker_positions, - desired_marker_pos: self.p50_desired_marker_positions, - desired_marker_incrs: self.p50_desired_marker_increments, - }, - Quantile { - marker_hghts: self.p90_marker_heights, - marker_pos: self.p90_marker_positions, - desired_marker_pos: self.p90_desired_marker_positions, - desired_marker_incrs: self.p90_desired_marker_increments, - }, - Quantile { - marker_hghts: self.p99_marker_heights, - marker_pos: self.p99_marker_positions, - desired_marker_pos: self.p99_desired_marker_positions, - desired_marker_incrs: self.p99_desired_marker_increments, - }, + Quantile::from_parts( + 0.5, + self.p50_marker_heights, + self.p50_marker_positions, + self.p50_desired_marker_positions, + ), + Quantile::from_parts( + 0.9, + self.p90_marker_heights, + self.p90_marker_positions, + self.p90_desired_marker_positions, + ), + Quantile::from_parts( + 0.99, + self.p99_marker_heights, + self.p99_marker_positions, + self.p99_desired_marker_positions, + ), ) } } @@ -526,7 +522,7 @@ where pub min: T, pub max: T, pub sum_of_samples: T::Width, - pub sum_of_squares: T::Width, + pub squared_mean: f64, #[serde(flatten)] pub quantiles: AllQuantiles, } @@ -556,7 +552,7 @@ where min: T::zero(), max: T::zero(), sum_of_samples: T::Width::zero(), - sum_of_squares: T::Width::zero(), + squared_mean: 0.0, quantiles: AllQuantiles::flatten(p50, p90, p99), } } @@ -574,11 +570,11 @@ where min: hist.min(), max: hist.max(), sum_of_samples: hist.sum_of_samples(), - sum_of_squares: hist.sum_of_squares(), + squared_mean: hist.squared_mean(), quantiles: AllQuantiles::flatten( - hist.p50q().clone(), - hist.p90q().clone(), - hist.p99q().clone(), + hist.p50q(), + hist.p90q(), + hist.p99q(), ), } } @@ -1370,7 +1366,7 @@ where min: T, max: T, sum_of_samples: T::Width, - sum_of_squares: T::Width, + squared_mean: f64, #[serde(flatten)] quantiles: AllQuantiles, } @@ -1433,14 +1429,14 @@ where } let (p50, p90, p99) = sample.quantiles.split(); - let hist = Histogram::with( + let hist = Histogram::from_parts( sample.start_time, sample.bins, sample.counts, sample.min, sample.max, sample.sum_of_samples, - sample.sum_of_squares, + sample.squared_mean, p50, p90, p99, @@ -1963,12 +1959,12 @@ mod tests { assert_eq!(dbhist.min, hist.min()); assert_eq!(dbhist.max, hist.max()); assert_eq!(dbhist.sum_of_samples, hist.sum_of_samples()); - assert_eq!(dbhist.sum_of_squares, hist.sum_of_squares()); + assert_eq!(dbhist.squared_mean, hist.squared_mean()); let (p50, p90, p99) = dbhist.quantiles.split(); - assert_eq!(&p50, hist.p50q()); - assert_eq!(&p90, hist.p90q()); - assert_eq!(&p99, hist.p99q()); + assert_eq!(p50, hist.p50q()); + assert_eq!(p90, hist.p90q()); + assert_eq!(p99, hist.p99q()); } #[test] @@ -2020,14 +2016,14 @@ mod tests { let (unpacked_p50, unpacked_p90, unpacked_p99) = unpacked.datum.quantiles.split(); - let unpacked_hist = Histogram::with( + let unpacked_hist = Histogram::from_parts( unpacked.start_time, unpacked.datum.bins, unpacked.datum.counts, unpacked.datum.min, unpacked.datum.max, unpacked.datum.sum_of_samples, - unpacked.datum.sum_of_squares, + unpacked.datum.squared_mean, unpacked_p50, unpacked_p90, unpacked_p99, @@ -2146,19 +2142,16 @@ mod tests { "min": 0, "max": 1, "sum_of_samples": 2, - "sum_of_squares": 2, + "squared_mean": 2.0, "p50_marker_heights": [0.0, 0.0, 0.0, 0.0, 1.0], - "p50_marker_positions": [1, 2, 3, 4, 0], + "p50_marker_positions": [1, 2, 3, 4, 2], "p50_desired_marker_positions": [1.0, 3.0, 5.0, 5.0, 5.0], - "p50_desired_marker_increments": [0.0, 0.5, 1.0, 1.0, 1.0], "p90_marker_heights": [0.0, 0.0, 0.0, 0.0, 1.0], - "p90_marker_positions": [1, 2, 3, 4, 0], + "p90_marker_positions": [1, 2, 3, 4, 2], "p90_desired_marker_positions": [1.0, 3.0, 5.0, 5.0, 5.0], - "p90_desired_marker_increments": [0.0, 0.5, 1.0, 1.0, 1.0], "p99_marker_heights": [0.0, 0.0, 0.0, 0.0, 1.0], - "p99_marker_positions": [1, 2, 3, 4, 0], - "p99_desired_marker_positions": [1.0, 3.0, 5.0, 5.0, 5.0], - "p99_desired_marker_increments": [0.0, 0.5, 1.0, 1.0, 1.0] + "p99_marker_positions": [1, 2, 3, 4, 2], + "p99_desired_marker_positions": [1.0, 3.0, 5.0, 5.0, 5.0] }"#; let (key, measurement) = parse_measurement_from_row(line, DatumType::HistogramI64); @@ -2173,34 +2166,34 @@ mod tests { assert_eq!(hist.min(), 0); assert_eq!(hist.max(), 1); assert_eq!(hist.sum_of_samples(), 2); - assert_eq!(hist.sum_of_squares(), 2); + assert_eq!(hist.squared_mean(), 2.); assert_eq!( hist.p50q(), - &Quantile { - marker_hghts: [0.0, 0.0, 0.0, 0.0, 1.0], - marker_pos: [1, 2, 3, 4, 0], - desired_marker_pos: [1.0, 3.0, 5.0, 5.0, 5.0], - desired_marker_incrs: [0.0, 0.5, 1.0, 1.0, 1.0], - } + Quantile::from_parts( + 0.5, + [0.0, 0.0, 0.0, 0.0, 1.0], + [1, 2, 3, 4, 2], + [1.0, 3.0, 5.0, 5.0, 5.0], + ) ); assert_eq!( hist.p90q(), - &Quantile { - marker_hghts: [0.0, 0.0, 0.0, 0.0, 1.0], - marker_pos: [1, 2, 3, 4, 0], - desired_marker_pos: [1.0, 3.0, 5.0, 5.0, 5.0], - desired_marker_incrs: [0.0, 0.5, 1.0, 1.0, 1.0], - } + Quantile::from_parts( + 0.9, + [0.0, 0.0, 0.0, 0.0, 1.0], + [1, 2, 3, 4, 2], + [1.0, 3.0, 5.0, 5.0, 5.0], + ) ); assert_eq!( hist.p99q(), - &Quantile { - marker_hghts: [0.0, 0.0, 0.0, 0.0, 1.0], - marker_pos: [1, 2, 3, 4, 0], - desired_marker_pos: [1.0, 3.0, 5.0, 5.0, 5.0], - desired_marker_incrs: [0.0, 0.5, 1.0, 1.0, 1.0], - } + Quantile::from_parts( + 0.99, + [0.0, 0.0, 0.0, 0.0, 1.0], + [1, 2, 3, 4, 2], + [1.0, 3.0, 5.0, 5.0, 5.0], + ) ); } diff --git a/oximeter/db/src/oxql/ast/table_ops/filter.rs b/oximeter/db/src/oxql/ast/table_ops/filter.rs index 50ee1f3f2d4..1d425761e68 100644 --- a/oximeter/db/src/oxql/ast/table_ops/filter.rs +++ b/oximeter/db/src/oxql/ast/table_ops/filter.rs @@ -523,19 +523,16 @@ fn implicit_field_names( out.insert(special_idents::MIN); out.insert(special_idents::MAX); out.insert(special_idents::SUM_OF_SAMPLES); - out.insert(special_idents::SUM_OF_SQUARES); + out.insert(special_idents::SQUARED_MEAN); out.insert(special_idents::P50_MARKER_HEIGHTS); out.insert(special_idents::P50_MARKER_POSITIONS); out.insert(special_idents::P50_DESIRED_MARKER_POSITIONS); - out.insert(special_idents::P50_DESIRED_MARKER_INCREMENTS); out.insert(special_idents::P90_MARKER_HEIGHTS); out.insert(special_idents::P90_MARKER_POSITIONS); out.insert(special_idents::P90_DESIRED_MARKER_POSITIONS); - out.insert(special_idents::P90_DESIRED_MARKER_INCREMENTS); out.insert(special_idents::P99_MARKER_HEIGHTS); out.insert(special_idents::P99_MARKER_POSITIONS); out.insert(special_idents::P99_DESIRED_MARKER_POSITIONS); - out.insert(special_idents::P99_DESIRED_MARKER_INCREMENTS); } // Scalars, either delta or cumulatives. ( @@ -555,19 +552,16 @@ fn implicit_field_names( out.insert(special_idents::MIN); out.insert(special_idents::MAX); out.insert(special_idents::SUM_OF_SAMPLES); - out.insert(special_idents::SUM_OF_SQUARES); + out.insert(special_idents::SQUARED_MEAN); out.insert(special_idents::P50_MARKER_HEIGHTS); out.insert(special_idents::P50_MARKER_POSITIONS); out.insert(special_idents::P50_DESIRED_MARKER_POSITIONS); - out.insert(special_idents::P50_DESIRED_MARKER_INCREMENTS); out.insert(special_idents::P90_MARKER_HEIGHTS); out.insert(special_idents::P90_MARKER_POSITIONS); out.insert(special_idents::P90_DESIRED_MARKER_POSITIONS); - out.insert(special_idents::P90_DESIRED_MARKER_INCREMENTS); out.insert(special_idents::P99_MARKER_HEIGHTS); out.insert(special_idents::P99_MARKER_POSITIONS); out.insert(special_idents::P99_DESIRED_MARKER_POSITIONS); - out.insert(special_idents::P99_DESIRED_MARKER_INCREMENTS); out.insert(special_idents::START_TIME); } // Impossible combinations diff --git a/oximeter/db/src/oxql/point.rs b/oximeter/db/src/oxql/point.rs index 4d7b868c9f2..dd989a8ac87 100644 --- a/oximeter/db/src/oxql/point.rs +++ b/oximeter/db/src/oxql/point.rs @@ -1531,10 +1531,10 @@ pub struct Distribution { min: Option, max: Option, sum_of_samples: T, - sum_of_squares: T, - p50: Quantile, - p90: Quantile, - p99: Quantile, + squared_mean: f64, + p50: Option, + p90: Option, + p99: Option, } impl fmt::Display for Distribution @@ -1550,17 +1550,33 @@ where .collect::>() .join(", "); + let p50_estimate = self + .p50 + .as_ref() + .map(|q| q.estimate().unwrap_or_default()) + .unwrap_or_default(); + let p90_estimate = self + .p90 + .as_ref() + .map(|q| q.estimate().unwrap_or_default()) + .unwrap_or_default(); + let p99_estimate = self + .p99 + .as_ref() + .map(|q| q.estimate().unwrap_or_default()) + .unwrap_or_default(); + write!( f, "{}, min: {}, max: {}, mean: {}, std_dev: {}, p50: {}, p90: {}, p99: {}", elems, self.min.unwrap_or_default(), self.max.unwrap_or_default(), - self.mean().unwrap_or_default(), + self.mean(), self.std_dev().unwrap_or_default(), - self.p50.estimate().unwrap_or_default(), - self.p90.estimate().unwrap_or_default(), - self.p99.estimate().unwrap_or_default() + p50_estimate, + p90_estimate, + p99_estimate ) } } @@ -1589,16 +1605,10 @@ where .collect::>() .context("Underflow subtracting distributions values")?; - // Subtract sum_of_samples and sum_of_squares directly. + // Subtract sum_of_samples and squared_mean directly. // We allow underflow here. let sum_of_samples = self.sum_of_samples - rhs.sum_of_samples; - let sum_of_squares = self.sum_of_squares - rhs.sum_of_squares; - - // Subtract quantiles directly. - // We allow underflow here. - let p50 = self.p50.sub(&rhs.p50); - let p90 = self.p50.sub(&rhs.p90); - let p99 = self.p50.sub(&rhs.p99); + let squared_mean = self.squared_mean - rhs.squared_mean; Ok(Self { bins: self.bins.clone(), @@ -1606,10 +1616,10 @@ where min: None, max: None, sum_of_samples, - sum_of_squares, - p50, - p90, - p99, + squared_mean, + p50: None, + p90: None, + p99: None, }) } @@ -1639,46 +1649,66 @@ where } /// Return the mean of the distribution. - pub fn mean(&self) -> Option { - let n_samples = self.n_samples(); - if n_samples > 0 { - self.sum_of_samples.to_f64().map(|sum| sum / (n_samples as f64)) + pub fn mean(&self) -> f64 { + if self.n_samples() > 0 { + // We can unwrap here because we know n_samples() > 0, + // so the sum_of_samples should convert to f64 without issue. + self.sum_of_samples + .to_f64() + .map(|sum| sum / (self.n_samples() as f64)) + .unwrap() } else { - None + 0. } } - /// Return the sample mean of the distribution. + /// Return the variance for inputs to the histogram based on the Welford's + /// algorithm, using the squared mean (M2). + /// + /// Returns `None` if there are fewer than two samples. + pub fn variance(&self) -> Option { + (self.n_samples() > 1) + .then(|| self.squared_mean / (self.n_samples() as f64)) + } + + /// Return the sample variance for inputs to the histogram based on the + /// Welford's algorithm, using the squared mean (M2). + /// + /// Returns `None` if there are fewer than two samples. + pub fn sample_variance(&self) -> Option { + (self.n_samples() > 1) + .then(|| self.squared_mean / ((self.n_samples() - 1) as f64)) + } + + /// Return the standard deviation for inputs to the histogram. + /// + /// This is a biased (as a consequence of Jensen’s inequality), estimate of + /// the population deviation that returns the standard deviation of the + /// samples seen by the histogram. + /// + /// Returns `None` if the variance is `None`, i.e., if there are fewer than + /// two samples. pub fn std_dev(&self) -> Option { - let n_samples = self.n_samples(); - if n_samples > 1 { - self.mean().and_then(|mean| { - let sum_of_squares = self.sum_of_squares.to_f64()?; - let sum_of_samples = self.sum_of_samples.to_f64()?; - - let variance = (sum_of_squares - (sum_of_samples * mean)) - / (n_samples as f64); - Some(variance.sqrt()) - }) - } else { - None + match self.variance() { + Some(variance) => Some(variance.sqrt()), + None => None, } } - /// Return the sample standard deviation of the distribution. + /// Return the "corrected" sample standard deviation for inputs to the + /// histogram. + /// + /// This is an unbiased estimate of the population deviation, applying + /// Bessel's correction, which corrects the bias in the estimation of the + /// population variance, and some, but not all of the bias in the estimation + /// of the population standard deviation. + /// + /// Returns `None` if the variance is `None`, i.e., if there are fewer than + /// two samples. pub fn sample_std_dev(&self) -> Option { - let n_samples = self.n_samples(); - if n_samples > 1 { - self.mean().and_then(|mean| { - let sum_of_squares = self.sum_of_squares.to_f64()?; - let sum_of_samples = self.sum_of_samples.to_f64()?; - - let variance = (sum_of_squares - (sum_of_samples * mean)) - / (n_samples as f64 - 1.0); - Some(variance.sqrt()) - }) - } else { - None + match self.sample_variance() { + Some(variance) => Some(variance.sqrt()), + None => None, } } @@ -1699,10 +1729,10 @@ macro_rules! i64_dist_from { min: Some(hist.min() as i64), max: Some(hist.max() as i64), sum_of_samples: hist.sum_of_samples(), - sum_of_squares: hist.sum_of_squares(), - p50: hist.p50q().clone(), - p90: hist.p90q().clone(), - p99: hist.p99q().clone(), + squared_mean: hist.squared_mean(), + p50: Some(hist.p50q()), + p90: Some(hist.p90q()), + p99: Some(hist.p99q()), } } } @@ -1740,10 +1770,10 @@ impl TryFrom<&oximeter::histogram::Histogram> for Distribution { min: Some(hist.min() as i64), max: Some(hist.max() as i64), sum_of_samples: hist.sum_of_samples(), - sum_of_squares: hist.sum_of_squares(), - p50: hist.p50q().clone(), - p90: hist.p90q().clone(), - p99: hist.p99q().clone(), + squared_mean: hist.squared_mean(), + p50: Some(hist.p50q()), + p90: Some(hist.p90q()), + p99: Some(hist.p99q()), }) } } @@ -1768,10 +1798,10 @@ macro_rules! f64_dist_from { min: Some(hist.min() as f64), max: Some(hist.max() as f64), sum_of_samples: hist.sum_of_samples() as f64, - sum_of_squares: hist.sum_of_squares() as f64, - p50: hist.p50q().clone(), - p90: hist.p90q().clone(), - p99: hist.p99q().clone(), + squared_mean: hist.squared_mean(), + p50: Some(hist.p50q()), + p90: Some(hist.p90q()), + p99: Some(hist.p99q()), } } } @@ -1914,12 +1944,12 @@ mod tests { assert_eq!(diff.n_samples(), 1); assert!(diff.min().is_none()); assert!(diff.max().is_none()); - assert_eq!(diff.mean().unwrap(), 14.0); + assert_eq!(diff.mean(), 14.0); assert!(diff.std_dev().is_none()); assert!(diff.sample_std_dev().is_none()); - assert_eq!(diff.p50.estimate().unwrap(), 4.0); - assert_eq!(diff.p90.estimate().unwrap(), 4.0); - assert_eq!(diff.p99.estimate().unwrap(), 4.0); + assert!(diff.p50.is_none()); + assert!(diff.p90.is_none()); + assert!(diff.p99.is_none()); } fn timestamps(n: usize) -> Vec> { @@ -2153,10 +2183,10 @@ mod tests { min: Some(0), max: Some(2), sum_of_samples: 0, - sum_of_squares: 0, - p50: Quantile::p50(), - p90: Quantile::p90(), - p99: Quantile::p99(), + squared_mean: 0.0, + p50: Some(Quantile::p50()), + p90: Some(Quantile::p90()), + p99: Some(Quantile::p99()), }, )]), metric_type: MetricType::Gauge, @@ -2200,10 +2230,10 @@ mod tests { min: Some(0.0), max: Some(2.0), sum_of_samples: 0.0, - sum_of_squares: 0.0, - p50: Quantile::p50(), - p90: Quantile::p90(), - p99: Quantile::p99(), + squared_mean: 0.0, + p50: Some(Quantile::p50()), + p90: Some(Quantile::p90()), + p99: Some(Quantile::p99()), }, )]), metric_type: MetricType::Gauge, diff --git a/oximeter/db/src/oxql/query/mod.rs b/oximeter/db/src/oxql/query/mod.rs index f68ae5b5987..5e9c748bfd9 100644 --- a/oximeter/db/src/oxql/query/mod.rs +++ b/oximeter/db/src/oxql/query/mod.rs @@ -43,28 +43,22 @@ pub mod special_idents { pub const MIN: &str = "min"; pub const MAX: &str = "max"; pub const SUM_OF_SAMPLES: &str = "sum_of_samples"; - pub const SUM_OF_SQUARES: &str = "sum_of_squares"; + pub const SQUARED_MEAN: &str = "squared_mean"; pub const P50_MARKER_HEIGHTS: &str = gen_marker!("50", "marker_heights"); pub const P50_MARKER_POSITIONS: &str = gen_marker!("50", "marker_positions"); pub const P50_DESIRED_MARKER_POSITIONS: &str = gen_marker!("50", "desired_marker_positions"); - pub const P50_DESIRED_MARKER_INCREMENTS: &str = - gen_marker!("50", "desired_marker_increments"); pub const P90_MARKER_HEIGHTS: &str = gen_marker!("90", "marker_heights"); pub const P90_MARKER_POSITIONS: &str = gen_marker!("90", "marker_positions"); pub const P90_DESIRED_MARKER_POSITIONS: &str = gen_marker!("90", "desired_marker_positions"); - pub const P90_DESIRED_MARKER_INCREMENTS: &str = - gen_marker!("90", "desired_marker_increments"); pub const P99_MARKER_HEIGHTS: &str = gen_marker!("99", "marker_heights"); pub const P99_MARKER_POSITIONS: &str = gen_marker!("99", "marker_positions"); pub const P99_DESIRED_MARKER_POSITIONS: &str = gen_marker!("99", "desired_marker_positions"); - pub const P99_DESIRED_MARKER_INCREMENTS: &str = - gen_marker!("99", "desired_marker_increments"); pub const DATETIME64: &str = "DateTime64"; pub const ARRAYU64: &str = "Array[u64]"; pub const ARRAYFLOAT64: &str = "Array[f64]"; diff --git a/oximeter/db/src/sql/mod.rs b/oximeter/db/src/sql/mod.rs index da4086fa554..e742637503b 100644 --- a/oximeter/db/src/sql/mod.rs +++ b/oximeter/db/src/sql/mod.rs @@ -624,19 +624,16 @@ impl RestrictedQuery { "min", "max", "sum_of_samples", - "sum_of_squares", + "squared_mean", "p50_marker_heights", "p50_marker_positions", "p50_desired_marker_positions", - "p50_desired_marker_increments", "p90_marker_heights", "p90_marker_positions", "p90_desired_marker_positions", - "p90_desired_marker_increments", "p99_marker_heights", "p99_marker_positions", "p99_desired_marker_positions", - "p99_desired_marker_increments", ] } else if datum_type.is_cumulative() { &["start_time", "timestamp", "datum"] diff --git a/oximeter/oximeter/Cargo.toml b/oximeter/oximeter/Cargo.toml index b9d7e8a9c29..0fe52bc4ace 100644 --- a/oximeter/oximeter/Cargo.toml +++ b/oximeter/oximeter/Cargo.toml @@ -26,6 +26,8 @@ omicron-workspace-hack.workspace = true [dev-dependencies] approx.workspace = true +rand = { workspace = true, features = ["std_rng"] } +rand_distr.workspace = true rstest.workspace = true serde_json.workspace = true trybuild.workspace = true diff --git a/oximeter/oximeter/src/histogram.rs b/oximeter/oximeter/src/histogram.rs index 6a7b3fe23d5..2e185145052 100644 --- a/oximeter/oximeter/src/histogram.rs +++ b/oximeter/oximeter/src/histogram.rs @@ -109,8 +109,10 @@ pub enum HistogramError { NonmonotonicBins, /// A non-finite was encountered, either as a bin edge or a sample. - #[error("Bin edges and samples must be finite values, found: {0:?}")] - NonFiniteValue(String), + #[error( + "Bin edges and samples must be finite values, not Infinity or NaN" + )] + NonFiniteValue, /// Error returned when two neighboring bins are not adjoining (there's space between them) #[error("Neigboring bins {left} and {right} are not adjoining")] @@ -293,6 +295,10 @@ pub struct Bin { pub count: u64, } +/// Internal, creation-specific newtype wrapper around Vec> to implement +/// conversion(s). +struct Bins(Vec>); + /// Histogram metric /// /// A histogram maintains the count of any number of samples, over a set of bins. Bins are @@ -370,8 +376,11 @@ where max: T, /// The sum of all samples in the histogram. sum_of_samples: T::Width, - /// The sum of the squares of all samples in the histogram. - sum_of_squares: T::Width, + /// M2 for Welford's algorithm for variance calculation. + /// + /// Read more on Welford's algorithm at + /// + squared_mean: f64, /// p50 Quantile p50: Quantile, /// p95 Quantile @@ -401,39 +410,29 @@ macro_rules! impl_int_sample { self.max = <$type>::min_value(); } + // For squared mean (M2) calculation, before we update the + // count. + let value_f = value as f64; + let current_mean = self.mean(); + let index = self .bins .binary_search_by(|bin| bin.range.cmp(&value).reverse()) .unwrap(); // The `ensure_finite` call above catches values that don't end up in a bin self.bins[index].count += 1; self.n_samples += 1; + self.min = self.min.min(value); + self.max = self.max.max(value); + self.sum_of_samples = self.sum_of_samples.saturating_add(value as i64); - if value < self.min { - self.min = value; - } - if value > self.max { - self.max = value; - } - - // Ensure that the sum of samples and sum of squares don't overflow - let on_unwrap = || { - if value < <$type>::zero() { - i64::MIN - } else { - i64::MAX - } - }; - - self.sum_of_samples = self.sum_of_samples.checked_add(value as i64).unwrap_or_else(on_unwrap); - self.sum_of_squares = self - .sum_of_squares - .checked_add((value as i64).checked_mul(value as i64).unwrap_or_else(on_unwrap)) - .unwrap_or_else(on_unwrap); + let delta = value_f - current_mean; + let updated_mean = current_mean + delta / (self.n_samples as f64); + let delta2 = value_f - updated_mean; + self.squared_mean += (delta * delta2); self.p50.append(value)?; self.p90.append(value)?; self.p99.append(value)?; - Ok(()) } } @@ -455,6 +454,11 @@ macro_rules! impl_float_sample { self.max = <$type as num::Bounded>::min_value(); } + // For squared mean (M2) calculation, before we update the + // count. + let value_f = value as f64; + let current_mean = self.mean(); + let index = self .bins .binary_search_by(|bin| bin.range.cmp(&value).reverse()) @@ -469,8 +473,12 @@ macro_rules! impl_float_sample { self.max = value; } - self.sum_of_samples += value as f64; - self.sum_of_squares += (value as f64) * value as f64; + self.sum_of_samples += value_f; + + let delta = value_f - current_mean; + let updated_mean = current_mean + delta / (self.n_samples as f64); + let delta2 = value_f - updated_mean; + self.squared_mean += (delta * delta2); self.p50.append(value)?; self.p90.append(value)?; @@ -588,7 +596,7 @@ where min: T::zero(), max: T::zero(), sum_of_samples: T::Width::zero(), - sum_of_squares: T::Width::zero(), + squared_mean: 0.0, p50: Quantile::p50(), p90: Quantile::p90(), p99: Quantile::p99(), @@ -597,54 +605,19 @@ where /// Construct a new histogram from left bin edges. /// - /// The left edges of the bins must be specified as a non-empty, monotonically increasing - /// slice. An `Err` is returned if either constraint is violated. + /// The left edges of the bins must be specified as a non-empty, + /// monotonically increasing slice. An `Err` is returned if either + /// constraint is violated. pub fn new(left_edges: &[T]) -> Result { - let mut items = left_edges.iter(); - let mut bins = Vec::with_capacity(left_edges.len() + 1); - let mut current = *items.next().ok_or(HistogramError::EmptyBins)?; - ensure_finite(current)?; - let min = ::min_value(); - if current > min { - // Bin greater than the minimum was specified, insert a new one from `MIN..current`. - bins.push(Bin { range: BinRange::range(min, current), count: 0 }); - } else if current == min { - // An edge *at* the minimum was specified. Consume it, and insert a bin from - // `MIN..next`, if one exists. If one does not, or if this is the last item, the - // following loop will not be entered. - let next = - items.next().cloned().unwrap_or_else(::max_value); - bins.push(Bin { range: BinRange::range(min, next), count: 0 }); - current = next; - } - for &next in items { - if current < next { - ensure_finite(next)?; - bins.push(Bin { - range: BinRange::range(current, next), - count: 0, - }); - current = next; - } else if current >= next { - return Err(HistogramError::NonmonotonicBins); - } else { - return Err(HistogramError::NonFiniteValue(format!( - "{:?}", - current - ))); - } - } - if current < ::max_value() { - bins.push(Bin { range: BinRange::from(current), count: 0 }); - } + let bins = Bins::try_from(left_edges)?; Ok(Self { start_time: Utc::now(), - bins, + bins: bins.0, n_samples: 0, min: T::zero(), max: T::zero(), sum_of_samples: T::Width::zero(), - sum_of_squares: T::Width::zero(), + squared_mean: 0.0, p50: Quantile::p50(), p90: Quantile::p90(), p99: Quantile::p99(), @@ -652,16 +625,16 @@ where } /// Construct a new histogram with the given struct information, including - /// bins and and counts. + /// bins, counts, and quantiles. #[allow(clippy::too_many_arguments)] - pub fn with( + pub fn from_parts( start_time: DateTime, bins: Vec, counts: Vec, min: T, max: T, sum_of_samples: T::Width, - sum_of_squares: T::Width, + squared_mean: f64, p50: Quantile, p90: Quantile, p99: Quantile, @@ -673,21 +646,21 @@ where }); } - let mut hist = Self::new(&bins)?; + let mut bins = Bins::try_from(bins.as_slice())?.0; let mut n_samples = 0; - for (bin, count) in hist.bins.iter_mut().zip(counts.into_iter()) { + for (bin, count) in bins.iter_mut().zip(counts.into_iter()) { bin.count = count; n_samples += count; } Ok(Self { start_time, - bins: hist.bins, + bins, n_samples, min, max, sum_of_samples, - sum_of_squares, + squared_mean, p50, p90, p99, @@ -733,56 +706,75 @@ where self.max } + /// Return the sum of all inputs to the histogram. + pub fn sum_of_samples(&self) -> T::Width { + self.sum_of_samples + } + + /// Return the squared mean (M2) of all inputs to the histogram. + pub fn squared_mean(&self) -> f64 { + self.squared_mean + } + /// Return the mean of all inputs/samples in the histogram. - pub fn mean(&self) -> Option { + pub fn mean(&self) -> f64 { if self.n_samples() > 0 { self.sum_of_samples .to_f64() .map(|sum| sum / (self.n_samples() as f64)) + .unwrap() } else { - None + 0. } } - /// Return the sum of all inputs to the histogram. - pub fn sum_of_samples(&self) -> T::Width { - self.sum_of_samples + /// Return the variance for inputs to the histogram based on the Welford's + /// algorithm, using the squared mean (M2). + /// + /// Returns `None` if there are fewer than two samples. + pub fn variance(&self) -> Option { + (self.n_samples() > 1) + .then(|| self.squared_mean / (self.n_samples() as f64)) } - /// Return the sum of the squares of all inputs to the histogram. - pub fn sum_of_squares(&self) -> T::Width { - self.sum_of_squares + /// Return the sample variance for inputs to the histogram based on the + /// Welford's algorithm, using the squared mean (M2). + /// + /// Returns `None` if there are fewer than two samples. + pub fn sample_variance(&self) -> Option { + (self.n_samples() > 1) + .then(|| self.squared_mean / ((self.n_samples() - 1) as f64)) } /// Return the standard deviation for inputs to the histogram. + /// + /// This is a biased (as a consequence of Jensen’s inequality), estimate of + /// the population deviation that returns the standard deviation of the + /// samples seen by the histogram. + /// + /// Returns `None` if the variance is `None`, i.e., if there are fewer than + /// two samples. pub fn std_dev(&self) -> Option { - if self.n_samples() > 1 { - self.mean().and_then(|mean| { - let sum_of_squares = self.sum_of_squares.to_f64()?; - let sum_of_samples = self.sum_of_samples.to_f64()?; - - let variance = (sum_of_squares - (sum_of_samples * mean)) - / (self.n_samples() as f64); - Some(variance.sqrt()) - }) - } else { - None + match self.variance() { + Some(variance) => Some(variance.sqrt()), + None => None, } } - /// Return the sample standard deviation for inputs to the histogram. + /// Return the "corrected" sample standard deviation for inputs to the + /// histogram. + /// + /// This is an unbiased estimate of the population deviation, applying + /// Bessel's correction, which corrects the bias in the estimation of the + /// population variance, and some, but not all of the bias in the estimation + /// of the population standard deviation. + /// + /// Returns `None` if the variance is `None`, i.e., if there are fewer than + /// two samples. pub fn sample_std_dev(&self) -> Option { - if self.n_samples() > 1 { - self.mean().and_then(|mean| { - let sum_of_squares = self.sum_of_squares.to_f64()?; - let sum_of_samples = self.sum_of_samples.to_f64()?; - - let variance = (sum_of_squares - (sum_of_samples * mean)) - / (self.n_samples() as f64 - 1.0); - Some(variance.sqrt()) - }) - } else { - None + match self.sample_variance() { + Some(variance) => Some(variance.sqrt()), + None => None, } } @@ -796,28 +788,29 @@ where self.bins.get(index) } - /// Return the start time for this histogram + /// Return the start time for this histogram. pub fn start_time(&self) -> DateTime { self.start_time } + /// Set the start time for this histogram. pub fn set_start_time(&mut self, start_time: DateTime) { self.start_time = start_time; } /// Return the p50 quantile for the histogram. - pub fn p50q(&self) -> &Quantile { - &self.p50 + pub fn p50q(&self) -> Quantile { + self.p50 } /// Return the p90 quantile for the histogram. - pub fn p90q(&self) -> &Quantile { - &self.p90 + pub fn p90q(&self) -> Quantile { + self.p90 } /// Return the p99 quantile for the histogram. - pub fn p99q(&self) -> &Quantile { - &self.p99 + pub fn p99q(&self) -> Quantile { + self.p99 } /// Return the p50 estimate for the histogram. @@ -836,6 +829,52 @@ where } } +impl TryFrom<&[T]> for Bins +where + T: HistogramSupport, +{ + type Error = HistogramError; + + fn try_from(left_edges: &[T]) -> Result { + let mut items = left_edges.iter(); + let mut bins: Vec> = Vec::with_capacity(left_edges.len() + 1); + let mut current: T = *items.next().ok_or(HistogramError::EmptyBins)?; + ensure_finite(current)?; + let min: T = ::min_value(); + if current > min { + // Bin greater than the minimum was specified, insert a new one from `MIN..current`. + bins.push(Bin { range: BinRange::range(min, current), count: 0 }); + } else if current == min { + // An edge *at* the minimum was specified. Consume it, and insert a bin from + // `MIN..next`, if one exists. If one does not, or if this is the last item, the + // following loop will not be entered. + let next: T = + items.next().cloned().unwrap_or_else(::max_value); + bins.push(Bin { range: BinRange::range(min, next), count: 0 }); + current = next; + } + for &next in items { + if current < next { + ensure_finite(next)?; + bins.push(Bin { + range: BinRange::range(current, next), + count: 0, + }); + current = next; + } else if current >= next { + return Err(HistogramError::NonmonotonicBins); + } else { + return Err(HistogramError::NonFiniteValue); + } + } + if current < ::max_value() { + bins.push(Bin { range: BinRange::from(current), count: 0 }); + } + + Ok(Bins(bins)) + } +} + impl Histogram where T: HistogramSupport, @@ -1137,7 +1176,7 @@ where if value.is_finite() { Ok(()) } else { - Err(HistogramError::NonFiniteValue(format!("{:?}", value))) + Err(HistogramError::NonFiniteValue) } } @@ -1219,6 +1258,12 @@ mod tests { .sum::() / count as f64) .sqrt(); + let current_sample_std_dev = (samples[..=i] + .iter() + .map(|x| (*x as f64 - current_mean).powi(2)) + .sum::() + / (count - 1) as f64) + .sqrt(); assert_eq!( hist.n_samples(), count, @@ -1228,13 +1273,13 @@ mod tests { if count > 0 { assert_eq!( - hist.mean().unwrap(), + hist.mean(), current_mean, "Histogram should have a mean of {}", current_mean ); } else { - assert!(hist.mean().is_none()); + assert!(hist.mean().is_zero()); } if count > 1 { @@ -1244,8 +1289,15 @@ mod tests { "Histogram should have a sample standard deviation of {}", current_std_dev ); + assert_eq!( + hist.sample_std_dev().unwrap(), + current_sample_std_dev, + "Histogram should have a sample standard deviation of {}", + current_sample_std_dev + ); } else { assert!(hist.std_dev().is_none()); + assert!(hist.sample_std_dev().is_none()); } } @@ -1274,10 +1326,10 @@ mod tests { assert_eq!(p50, 1.0, "P50 should be 1.0, but found {}", p50); let p90 = hist.p90().unwrap(); - assert_eq!(p90, 1.0, "P90 should be 1.0, but found {}", p90); + assert_eq!(p90, 100.0, "P90 should be 100.0, but found {}", p90); let p99 = hist.p99().unwrap(); - assert_eq!(p99, 1.0, "P99 should be 1.0, but found {}", p99); + assert_eq!(p99, 100.0, "P99 should be 100.0, but found {}", p99); } #[test] @@ -1311,17 +1363,17 @@ mod tests { assert_eq!(counts, &[0, 1, 1, 0], "Paired-array counts are incorrect"); assert_eq!(hist.n_samples(), 2); - let rebuilt = Histogram::with( + let rebuilt = Histogram::from_parts( hist.start_time(), bins, counts, hist.min(), hist.max(), hist.sum_of_samples(), - hist.sum_of_squares(), - hist.p50.clone(), - hist.p90.clone(), - hist.p99.clone(), + hist.squared_mean(), + hist.p50, + hist.p90, + hist.p99, ) .unwrap(); assert_eq!( diff --git a/oximeter/oximeter/src/quantile.rs b/oximeter/oximeter/src/quantile.rs index 676360ec373..0e18f65fe66 100644 --- a/oximeter/oximeter/src/quantile.rs +++ b/oximeter/oximeter/src/quantile.rs @@ -1,26 +1,43 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +//! Data structure for expressing quantile estimation. +//! This is based on the P² heuristic algorithm for dynamic +//! calculation of the median and other quantiles. The estimates +//! are produced dynamically as the observations are generated. +//! The observations are not stored; therefore, the algorithm has +//! a very small and fixed storage requirement regardless of the +//! number of observations. +//! +//! Read for more. + +// Copyright 2024 Oxide Computer Company + use crate::traits::HistogramSupport; -use num::traits::Float; -use num::traits::ToPrimitive; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; -use std::cmp::min; -use std::ops::Sub; use thiserror::Error; -/// Errors related to constructing a `Quantile` instance or estimating the p-quantile. -#[derive(Debug, Clone, Error, JsonSchema, Serialize, Deserialize)] +const FILLED_MARKER_LEN: usize = 5; + +/// Errors related to constructing a `Quantile` instance or estimating the +/// p-quantile. +#[derive( + Debug, Clone, Error, JsonSchema, Serialize, Deserialize, PartialEq, +)] #[serde(tag = "type", content = "content", rename_all = "snake_case")] pub enum QuantileError { /// The p value must be in the range [0, 1]. #[error("The p value must be in the range [0, 1].")] InvalidPValue, /// Quantile estimation is not possible without samples. - #[error("Quantile estimation is not possible without samples.")] - EmptyQuantile, + #[error("Quantile estimation is not possible without any samples.")] + InsufficientSampleSize, /// A non-finite was encountered, either as a bin edge or a sample. - #[error("Samples must be finite values, found: {0:?}")] - NonFiniteValue(String), + #[error("Samples must be finite values, not Infinity or NaN.")] + NonFiniteValue, } /// Structure for estimating the p-quantile of a population. @@ -30,269 +47,394 @@ pub enum QuantileError { /// /// The algorithm consists of maintaining five markers: the /// minimum, the p/2-, p-, and (1 + p)/2 quantiles, and the maximum. -/// -/// Read for more. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] pub struct Quantile { + /// The p value for the quantile. + p: f64, /// The heights of the markers. - #[serde(rename = "marker_heights")] - pub marker_hghts: [f64; 5], + marker_heights: [f64; FILLED_MARKER_LEN], /// The positions of the markers. - #[serde(rename = "marker_positions")] - pub marker_pos: [i64; 5], + /// + /// We track sample size in the 5th position, as useful observations won't + /// start until we've filled the heights at the 6th sample anyway + /// This does deviate from the paper, but it's a more useful representation + /// that works according to the paper's algorithm. + marker_positions: [u64; FILLED_MARKER_LEN], /// The desired marker positions. - #[serde(rename = "desired_marker_positions")] - pub desired_marker_pos: [f64; 5], - /// The increment for the desired marker positions. - #[serde(rename = "desired_marker_increments")] - pub desired_marker_incrs: [f64; 5], + desired_marker_positions: [f64; FILLED_MARKER_LEN], } impl Quantile { /// Create a new `Quantile` instance. - pub fn new(p: u64) -> Result { - let p = p as f64 / 100.; + /// + /// Returns a result containing the `Quantile` instance or an error. + /// + /// # Errors + /// + /// Returns [`QuantileError::InvalidPValue`] if the p value is not in the + /// range [0, 1]. + /// + /// # Examples + /// + /// ``` + /// use oximeter::Quantile; + /// let q = Quantile::new(0.5).unwrap(); + /// + /// assert_eq!(q.p(), 0.5); + /// assert_eq!(q.len(), 0); + /// ``` + pub fn new(p: f64) -> Result { if p < 0. || p > 1. { return Err(QuantileError::InvalidPValue); } Ok(Self { - marker_hghts: [0.; 5], - marker_pos: [1, 2, 3, 4, 0], - desired_marker_pos: [1., 1. + 2. * p, 1. + 4. * p, 3. + 2. * p, 5.], - desired_marker_incrs: [0., p / 2., p, (1. + p) / 2., 1.], + p, + marker_heights: [0.; FILLED_MARKER_LEN], + // We start with a sample size of 0. + //marker_positions: [0, 1, 2, 3, 0], + marker_positions: [1, 2, 3, 4, 0], + // 1-indexed, which is like the paper, but + // used to keep track of the sample size without + // needing to do a separate count, use a Vec, + // or do any other kind of bookkeeping. + desired_marker_positions: [ + 1., + 1. + 2. * p, + 1. + 4. * p, + 3. + 2. * p, + 5., + ], }) } - /// Create a new `Quantile` instance from the given marker heights and - /// positions. - pub fn from( - marker_hghts: [f64; 5], - marker_pos: [i64; 5], - desired_marker_pos: [f64; 5], - desired_marker_incrs: [f64; 5], + /// Create a new `Quantile` instance from the given a p-value, marker + /// heights and positions. + /// + /// # Examples + /// ``` + /// use oximeter::Quantile; + /// let q = Quantile::from_parts( + /// 0.5, + /// [0., 1., 2., 3., 4.], + /// [1, 2, 3, 4, 5], + /// [1., 3., 5., 7., 9.], + /// ); + /// ``` + pub fn from_parts( + p: f64, + marker_heights: [f64; FILLED_MARKER_LEN], + marker_positions: [u64; FILLED_MARKER_LEN], + desired_marker_positions: [f64; FILLED_MARKER_LEN], ) -> Self { - Self { - marker_hghts, - marker_pos, - desired_marker_pos, - desired_marker_incrs, - } + Self { p, marker_heights, marker_positions, desired_marker_positions } } /// Construct a `Quantile` instance for the 50th/median percentile. pub fn p50() -> Self { - Self::new(50).unwrap() + Self::new(0.5).unwrap() } /// Construct a `Quantile` instance for the 90th percentile. pub fn p90() -> Self { - Self::new(90).unwrap() + Self::new(0.9).unwrap() } /// Construct a `Quantile` instance for the 95th percentile. pub fn p95() -> Self { - Self::new(95).unwrap() + Self::new(0.95).unwrap() } /// Construct a `Quantile` instance for the 99th percentile. pub fn p99() -> Self { - Self::new(99).unwrap() + Self::new(0.99).unwrap() } /// Get the p value as a float. - fn _p(&self) -> f64 { - self.desired_marker_incrs[2] + pub fn p(&self) -> f64 { + self.p } - /// Get the p value as an integer. - pub fn p(&self) -> u64 { - (self.desired_marker_incrs[2] * 100.0) as u64 + /// Return the sample size. + pub fn len(&self) -> u64 { + self.marker_positions[4] + } + + /// Determine if the number of samples in the population are empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Return the marker heights. + pub fn marker_heights(&self) -> [f64; FILLED_MARKER_LEN] { + self.marker_heights + } + + /// Return the marker positions. + pub fn marker_positions(&self) -> [u64; FILLED_MARKER_LEN] { + self.marker_positions + } + + /// Return the desired marker positions. + pub fn desired_marker_positions(&self) -> [f64; FILLED_MARKER_LEN] { + self.desired_marker_positions } /// Estimate the p-quantile of the population. /// - /// Returns an error if the sample is empty. + /// This is step B.4 in the P² algorithm. + /// + /// Returns a result containing the estimated p-quantile or an error. + /// + /// # Errors + /// + /// Returns [`QuantileError::InsufficientSampleSize`] if the sample size + /// is empty. + /// + /// # Examples + /// + /// ``` + /// use oximeter::Quantile; + /// let mut q = Quantile::new(0.5).unwrap(); + /// for o in 1..=100 { + /// q.append(o).unwrap(); + /// } + /// assert_eq!(q.estimate().unwrap(), 50.0); + /// ``` pub fn estimate(&self) -> Result { - // Return NaN if the sample is empty. if self.is_empty() { - return Err(QuantileError::EmptyQuantile); + return Err(QuantileError::InsufficientSampleSize); } - // Return the middle marker height if the sample size is at least 5. - if self.len() >= 5 { - return Ok(self.marker_hghts[2]); + if self.len() >= FILLED_MARKER_LEN as u64 { + return Ok(self.marker_heights[2]); } - let mut heights: [f64; 4] = [ - self.marker_hghts[0], - self.marker_hghts[1], - self.marker_hghts[2], - self.marker_hghts[3], - ]; - - let len = self.len() as usize; - float_ord::sort(&mut heights[..len]); - - let desired_index = (len as f64) * self._p() - 1.; - let mut index = desired_index.ceil(); - if desired_index == index && index >= 0. { - let index = index.round_ties_even() as usize; - if index < len - 1 { - // `marker_hghts[index]` and `marker_hghts[index + 1]` are - // equally valid estimates, by convention we take their average. - return Ok(0.5 * self.marker_hghts[index] - + 0.5 * self.marker_hghts[index + 1]); - } - } - index = index.max(0.); - let mut index = index.round_ties_even() as usize; - index = min(index, len - 1); - Ok(self.marker_hghts[index]) - } - - /// Return the sample size. - pub fn len(&self) -> u64 { - self.marker_pos[4] as u64 - } - - /// Determine whether the sample is empty. - pub fn is_empty(&self) -> bool { - self.len() == 0 + // Try to find an index in heights that is correlated with the p value + // when we have less than 5 samples, but more than 0. + let mut heights = self.marker_heights; + float_ord::sort(&mut heights); + let idx = (heights.len() as f64 - 1.) * self.p(); + return Ok(heights[idx.round() as usize]); } /// Append a value/observation to the population and adjust the heights. + /// + /// This comprises steps B.1, B.2, B.3 (adjust heights) in the P² algorithm, + /// including finding the cell k containing the input value and updating the + /// current and desired marker positions. + /// + /// Returns an empty result or an error. + /// + /// # Errors + /// + /// Returns [`QuantileError::NonFiniteValue`] if the value is not finite + /// when casting to a float. + /// + /// # Examples + /// + /// ``` + /// use oximeter::Quantile; + /// let mut q = Quantile::new(0.9).unwrap(); + /// q.append(10).unwrap(); + /// assert_eq!(q.len(), 1); + /// ``` pub fn append(&mut self, value: T) -> Result<(), QuantileError> where T: HistogramSupport, { if !value.is_finite() { - return Err(QuantileError::NonFiniteValue(format!("{:?}", value))); + return Err(QuantileError::NonFiniteValue); } - - // we've already checked that the value is finite. - let value = value.to_f64().unwrap(); - - // n[4] is the sample size. - if self.marker_pos[4] < 5 { - self.marker_hghts[self.marker_pos[4] as usize] = value; - self.marker_pos[4] += 1; - if self.marker_pos[4] == 5 { - float_ord::sort(&mut self.marker_hghts); + // We've already checked that the value is finite. + let value_f = value.to_f64().unwrap(); + + // if !self.is_filled { + if self.len() < FILLED_MARKER_LEN as u64 { + self.marker_heights[self.len() as usize] = value_f; + self.marker_positions[4] += 1; + if self.len() == FILLED_MARKER_LEN as u64 { + float_ord::sort(&mut self.marker_heights); + self.adaptive_init(); } return Ok(()); } - // Find cell k. - let mut k: usize; - if value < self.marker_hghts[0] { - self.marker_hghts[0] = value; - k = 0; - } else { - k = 4; - for i in 1..5 { - if value < self.marker_hghts[i] { - k = i; - break; - } + // Find the cell k containing the new value. + let k = match self.find_cell(value_f) { + Some(4) => { + self.marker_heights[4] = value_f; + 3 } - if self.marker_hghts[4] < value { - self.marker_hghts[4] = value; + Some(i) => i, + None => { + self.marker_heights[0] = value_f; + 0 } }; - // Increment all positions greater than k. - for i in k..5 { - self.marker_pos[i] += 1; - } - for i in 0..5 { - self.desired_marker_pos[i] += self.desired_marker_incrs[i]; + // Handle rounding issues as described in + // . + let count = self.len() as f64; + self.desired_marker_positions[1] = count * (self.p() / 2.) + 1.; + self.desired_marker_positions[2] = count * self.p() + 1.; + self.desired_marker_positions[3] = count * ((1. + self.p()) / 2.) + 1.; + self.desired_marker_positions[4] = count + 1.; + + for i in k + 1..FILLED_MARKER_LEN { + self.marker_positions[i] += 1; } - // Adjust height of markers. - for i in 1..4 { - // unwrap is safe because we know the exact marker positions as literals. - let d = self.desired_marker_pos[i] - - self.marker_pos[i].to_f64().unwrap(); - if d >= 1. && self.marker_pos[i + 1] - self.marker_pos[i] > 1 - || d <= -1. && self.marker_pos[i - 1] - self.marker_pos[i] < -1 - { - let d = Float::signum(d); - let q_new = self.parabolic(i, d); - if self.marker_hghts[i - 1] < q_new - && q_new < self.marker_hghts[i + 1] - { - self.marker_hghts[i] = q_new; - } else { - self.marker_hghts[i] = self.linear(i, d); - } - let delta = d.round_ties_even() as i64; - debug_assert_eq!(delta.abs(), 1); - self.marker_pos[i] += delta; + // Adjust height of markers adaptively to be more optimal for + // not just higher quantiles, but also lower ones. + // + // This is a deviation from the paper, taken from + // . + if self.p >= 0.5 { + for i in 1..4 { + self.adjust_heights(i) + } + } else { + for i in (1..4).rev() { + self.adjust_heights(i) } } Ok(()) } - /// Subtract another `Quantile` instance from this one. - pub fn sub(&self, other: &Quantile) -> Quantile { - /// Nested function to subtract elements of two arrays and return the - /// result as an array. - fn sub_arrays(arr1: &[T; 5], arr2: &[T; 5]) -> [T; 5] - where - T: Sub + Copy, - { - // Initialize with the first element of arr1 (or any default value). - let mut result = [arr1[0]; 5]; - for i in 0..5 { - result[i] = arr1[i] - arr2[i]; + /// Find the higher marker cell whose height is lower than the observation. + /// + /// Returns `None` if the value is less than the initial marker height. + fn find_cell(&mut self, value: f64) -> Option { + if value < self.marker_heights[0] { + None + } else { + let mut k = 0; + while k + 1 < FILLED_MARKER_LEN + && value >= self.marker_heights[k + 1] + { + k += 1; } - result + + Some(k) } + } + + /// Adjust the heights of the markers if necessary. + /// + /// Step B.3 in the P² algorithm. Should be used within a loop + /// after appending a value to the population. + fn adjust_heights(&mut self, i: usize) { + let d = + self.desired_marker_positions[i] - self.marker_positions[i] as f64; + + if (d >= 1. + && self.marker_positions[i + 1] > self.marker_positions[i] + 1) + || (d <= -1. + && self.marker_positions[i - 1] < self.marker_positions[i]) + { + let d_signum = d.signum(); + let q_prime = self.parabolic(i, d_signum); + if self.marker_heights[i - 1] < q_prime + && q_prime < self.marker_heights[i + 1] + { + self.marker_heights[i] = q_prime; + } else { + let q_prime = self.linear(i, d_signum); + self.marker_heights[i] = q_prime; + } - Quantile { - marker_hghts: sub_arrays(&self.marker_hghts, &other.marker_hghts), - marker_pos: sub_arrays(&self.marker_pos, &other.marker_pos), - desired_marker_pos: sub_arrays( - &self.desired_marker_pos, - &other.desired_marker_pos, - ), - desired_marker_incrs: sub_arrays( - &self.desired_marker_incrs, - &other.desired_marker_incrs, - ), + // Update marker positions based on the sign of d. + if d_signum < 0. { + self.marker_positions[i] -= 1; + } else { + self.marker_positions[i] += 1; + } } } + /// An implementation to adaptively initialize the marker heights and + /// positions, particularly useful for extreme quantiles (e.g., 0.99) + /// when estimating on a small sample size. + /// + /// Read + /// for more. + fn adaptive_init(&mut self) { + self.desired_marker_positions[1..FILLED_MARKER_LEN] + .copy_from_slice(&self.marker_heights[1..FILLED_MARKER_LEN]); + + self.marker_positions[1] = (1. + 2. * self.p()).round() as u64; + self.marker_positions[2] = (1. + 4. * self.p()).round() as u64; + self.marker_positions[3] = (3. + 2. * self.p()).round() as u64; + self.marker_heights[1] = self.desired_marker_positions + [self.marker_positions[1] as usize - 1]; + self.marker_heights[2] = self.desired_marker_positions + [self.marker_positions[2] as usize - 1]; + self.marker_heights[3] = self.desired_marker_positions + [self.marker_positions[3] as usize - 1]; + } + /// Parabolic prediction for marker height. - fn parabolic(&self, i: usize, d: f64) -> f64 { - let term1 = - d / (self.marker_pos[i + 1] - self.marker_pos[i - 1]) as f64; - let term2 = ((self.marker_pos[i] - self.marker_pos[i - 1]) as f64 + d) - * (self.marker_hghts[i + 1] - self.marker_hghts[i]) - / (self.marker_pos[i + 1] - self.marker_pos[i]) as f64; - let term3 = ((self.marker_pos[i + 1] - self.marker_pos[i]) as f64 - d) - * (self.marker_hghts[i] - self.marker_hghts[i - 1]) - / (self.marker_pos[i] - self.marker_pos[i - 1]) as f64; - - self.marker_hghts[i] + term1 * (term2 + term3) + fn parabolic(&self, i: usize, d_signum: f64) -> f64 { + let pos_diff1 = (self.marker_positions[i + 1] as i64 + - self.marker_positions[i - 1] as i64) + as f64; + + let pos_diff2 = (self.marker_positions[i + 1] as i64 + - self.marker_positions[i] as i64) as f64; + + let pos_diff3 = (self.marker_positions[i] as i64 + - self.marker_positions[i - 1] as i64) + as f64; + + let term1 = d_signum / pos_diff1; + let term2 = ((self.marker_positions[i] - self.marker_positions[i - 1]) + as f64 + + d_signum) + * (self.marker_heights[i + 1] - self.marker_heights[i]) + / pos_diff2; + let term3 = ((self.marker_positions[i + 1] - self.marker_positions[i]) + as f64 + - d_signum) + * (self.marker_heights[i] - self.marker_heights[i - 1]) + / pos_diff3; + + self.marker_heights[i] + term1 * (term2 + term3) } /// Linear prediction for marker height. - fn linear(&self, i: usize, d: f64) -> f64 { - let index = if d < 0. { i - 1 } else { i + 1 }; - self.marker_hghts[i] - + d * (self.marker_hghts[index] - self.marker_hghts[i]) - / (self.marker_pos[index] - self.marker_pos[i]) as f64 + fn linear(&self, i: usize, d_signum: f64) -> f64 { + let idx = if d_signum < 0. { i - 1 } else { i + 1 }; + self.marker_heights[i] + + d_signum * (self.marker_heights[idx] - self.marker_heights[i]) + / (self.marker_positions[idx] as i64 + - self.marker_positions[i] as i64) as f64 } } #[cfg(test)] mod tests { use super::*; - use oximeter::test_util::assert_almost_eq; + use approx::assert_relative_eq; + use rand::{Rng, SeedableRng}; + use rand_distr::{Distribution, Normal}; + + fn test_quantile_impl( + p: f64, + observations: u64, + assert_on: Option, + ) -> Quantile { + let mut q = Quantile::new(p).unwrap(); + for o in 1..=observations { + q.append(o).unwrap(); + } + assert_eq!(q.p(), p); + assert_eq!(q.estimate().unwrap(), assert_on.unwrap_or(p * 100.)); + q + } + /// Example observations from the P² paper. #[test] fn test_float_observations() { let observations = [ @@ -303,91 +445,124 @@ mod tests { for &o in observations.iter() { q.append(o).unwrap(); } - assert_eq!(q.marker_pos, [1, 6, 10, 16, 20]); - assert_eq!(q.desired_marker_pos, [1., 5.75, 10.50, 15.25, 20.0]); - assert_eq!(q.len(), 20); - assert_eq!(q.p(), 50); - assert_almost_eq!(q.estimate().unwrap(), 4.2462394088036435, 2e-15); + assert_eq!(q.marker_positions, [1, 6, 10, 16, 20]); + assert_eq!(q.desired_marker_positions, [1., 5.75, 10.50, 15.25, 20.0]); + assert_eq!(q.p(), 0.5); + assert_relative_eq!(q.estimate().unwrap(), 4.2462394088036435,); + } + + #[test] + fn test_rounding() { + let mut rng = rand::rngs::StdRng::seed_from_u64(42); + let mut estimator = Quantile::new(0.6).unwrap(); + + for _ in 0..100 { + let x: f64 = rng.gen(); + estimator.append(x).unwrap(); + } + + assert_relative_eq!( + estimator.estimate().unwrap(), + 0.552428024067269, + epsilon = f64::EPSILON + ); } #[test] fn test_integer_observations() { let observations = 1..=100; - let mut q = Quantile::new(30).unwrap(); + let mut q = Quantile::new(0.3).unwrap(); for o in observations { q.append(o).unwrap(); } - - assert_eq!(q.marker_pos, [1, 15, 30, 65, 100]); + assert_eq!(q.marker_positions, [1, 15, 30, 65, 100]); assert_eq!( - q.desired_marker_pos, - [ - 1.0, - 15.850000000000026, - 30.70000000000005, - 65.34999999999992, - 100.0 - ] + q.desired_marker_positions, + [1.0, 15.85, 30.7, 65.35000000000001, 100.0] ); - assert_eq!(q.len(), 100); - assert_eq!(q.p(), 30); + + assert_eq!(q.p(), 0.3); assert_eq!(q.estimate().unwrap(), 30.0); } #[test] - fn test_p50() { - let observations = 1..=100; - let mut q = Quantile::p50(); - for o in observations { - q.append(o).unwrap(); - } - assert_eq!(q.p(), 50); - assert_eq!(q.estimate().unwrap(), 50.0); + fn test_empty_observations() { + let q = Quantile::p50(); + assert_eq!( + q.estimate().err().unwrap(), + QuantileError::InsufficientSampleSize + ); } #[test] - fn test_p90() { - let observations = 1..=100; - let mut q = Quantile::p90(); - for o in observations { + fn test_non_filled_observations() { + let mut q = Quantile::p99(); + let observations = [-10., 0., 1., 10.]; + for &o in observations.iter() { q.append(o).unwrap(); } - assert_eq!(q.p(), 90); - assert_eq!(q.estimate().unwrap(), 90.0); + assert_eq!(q.estimate().unwrap(), 10.); } #[test] - fn test_p95() { - let observations = 1..=100; - let mut q = Quantile::p95(); - for o in observations { - q.append(o).unwrap(); - } - assert_eq!(q.p(), 95); - assert_eq!(q.estimate().unwrap(), 95.0); + fn test_default_percentiles() { + test_quantile_impl(0.5, 100, None); + test_quantile_impl(0.9, 100, None); + test_quantile_impl(0.95, 100, None); + test_quantile_impl(0.99, 100, Some(97.)); } #[test] - fn test_p99() { - let observations = 1..=100; - let mut q = Quantile::p99(); - for o in observations { - q.append(o).unwrap(); - } - assert_eq!(q.p(), 99); - assert_eq!(q.estimate().unwrap(), 97.0); + fn test_invalid_p_value() { + assert_eq!( + Quantile::new(1.01).err().unwrap(), + QuantileError::InvalidPValue + ); + assert_eq!( + Quantile::new(f64::MAX).err().unwrap(), + QuantileError::InvalidPValue + ); } #[test] - fn test_empty_sample() { - let q = Quantile::p50(); - assert!(q.is_empty()); - assert!(q.estimate().is_err()); + fn test_find_cells() { + let mut q = test_quantile_impl(0.5, 5, Some(3.)); + assert_eq!(q.find_cell(0.), None); + assert_eq!(q.find_cell(7.), Some(4)); + assert_eq!(q.find_cell(4.), Some(3)); + assert_eq!(q.find_cell(3.5), Some(2)); } + /// Emulates baseline test in a basic Python implementation of the P² + /// algorithm: + /// . #[test] - fn test_invalid_p_value() { - assert!(Quantile::new(101).is_err()); - assert!(Quantile::new(u64::MAX).is_err()); + fn test_against_baseline_normal_distribution() { + let mu = 500.; + let sigma = 100.; + let size = 1000; + let p = 0.9; + + let normal = Normal::new(mu, sigma); + let mut observations = (0..size) + .map(|_| normal.unwrap().sample(&mut rand::thread_rng())) + .collect::>(); + float_ord::sort(&mut observations); + let idx = ((f64::from(size) - 1.) * p) as usize; + + let base_p_est = observations[idx]; + + let mut q = Quantile::new(p).unwrap(); + for o in observations.iter() { + q.append(*o).unwrap(); + } + let p_est = q.estimate().unwrap(); + + println!("Base: {}, Est: {}", base_p_est, p_est); + assert!( + (base_p_est - p_est).abs() < 10.0, + "Difference {} is not less than 10", + (base_p_est - p_est).abs() + ); } } diff --git a/oximeter/oximeter/src/test_util.rs b/oximeter/oximeter/src/test_util.rs index 76734edc021..56992623d7b 100644 --- a/oximeter/oximeter/src/test_util.rs +++ b/oximeter/oximeter/src/test_util.rs @@ -113,29 +113,6 @@ pub fn generate_test_samples( samples } -/// Assert that two numbers are almost equal to each other. -/// -/// On panic, this macro will print the values of the expressions with their -/// debug representations. -#[macro_export] -macro_rules! assert_almost_eq { - ($a:expr, $b:expr, $prec:expr) => { - let diff = ($a - $b).abs(); - assert!( - diff <= $prec, - "assertion failed: `abs(left - right) = {:.1e} < {:e}`, \ - (left: `{}`, right: `{}`)", - diff, - $prec, - $a, - $b - ); - }; -} - -/// Assert that two numbers are almost equal to each other. -pub use assert_almost_eq; - #[cfg(test)] mod tests { use super::*;