UNPKG

sketches-js-hassy

Version:

TypeScript implementation of DDSketch, a distributed quantile sketch algorithm

207 lines (206 loc) 8.03 kB
"use strict"; /* * Unless explicitly stated otherwise all files in this repository are licensed * under the Apache 2.0 license (see LICENSE). * This product includes software developed at Datadog (https://www.datadoghq.com/). * Copyright 2020 Datadog, Inc. */ var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.DDSketch = void 0; var store_1 = require("./store"); var mapping_1 = require("./mapping"); var compiled_1 = require("./proto/compiled"); var DEFAULT_RELATIVE_ACCURACY = 0.01; /** Base class for DDSketch*/ var BaseDDSketch = /** @class */ (function () { function BaseDDSketch(_a) { var mapping = _a.mapping, store = _a.store, negativeStore = _a.negativeStore, zeroCount = _a.zeroCount, _b = _a.min, min = _b === void 0 ? Infinity : _b, _c = _a.max, max = _c === void 0 ? -Infinity : _c, _d = _a.sum, sum = _d === void 0 ? 0 : _d; this.mapping = mapping; this.store = store; this.negativeStore = negativeStore; this.zeroCount = zeroCount; this.count = this.negativeStore.count + this.zeroCount + this.store.count; this.min = min; this.max = max; this.sum = sum; } /** * Add a value to the sketch * * @param value The value to be added * @param weight The amount to weight the value (default 1.0) * * @throws Error if `weight` is 0 or negative */ BaseDDSketch.prototype.accept = function (value, weight) { if (weight === void 0) { weight = 1; } if (weight <= 0) { throw Error('Weight must be a positive number'); } if (value > this.mapping.minPossible) { var key = this.mapping.key(value); this.store.add(key, weight); } else if (value < -this.mapping.minPossible) { var key = this.mapping.key(-value); this.negativeStore.add(key, weight); } else { this.zeroCount += weight; } /* Keep track of summary stats */ this.count += weight; this.sum += value * weight; if (value < this.min) { this.min = value; } if (value > this.max) { this.max = value; } }; /** * Retrieve a value from the sketch at the quantile * * @param quantile A number between `0` and `1` (inclusive) */ BaseDDSketch.prototype.getValueAtQuantile = function (quantile) { if (quantile < 0 || quantile > 1 || this.count === 0) { return NaN; } var rank = quantile * (this.count - 1); var quantileValue = 0; if (rank < this.negativeStore.count) { var reversedRank = this.negativeStore.count - rank - 1; var key = this.negativeStore.keyAtRank(reversedRank, false); quantileValue = -this.mapping.value(key); } else if (rank < this.zeroCount + this.negativeStore.count) { return 0; } else { var key = this.store.keyAtRank(rank - this.zeroCount - this.negativeStore.count); quantileValue = this.mapping.value(key); } return quantileValue; }; /** * Merge the contents of the parameter `sketch` into this sketch * * @param sketch The sketch to merge into the caller sketch * @throws Error if the sketches were initialized with different `relativeAccuracy` values */ BaseDDSketch.prototype.merge = function (sketch) { if (!this.mergeable(sketch)) { throw new Error('Cannot merge two DDSketches with different `relativeAccuracy` parameters'); } if (sketch.count === 0) { return; } if (this.count === 0) { this._copy(sketch); return; } this.store.merge(sketch.store); /* Merge summary stats */ this.count += sketch.count; this.sum += sketch.sum; if (sketch.min < this.min) { this.min = sketch.min; } if (sketch.max > this.max) { this.max = sketch.max; } }; /** * Determine whether two sketches can be merged * * @param sketch The sketch to be merged into the caller sketch */ BaseDDSketch.prototype.mergeable = function (sketch) { return this.mapping.gamma === sketch.mapping.gamma; }; /** * Helper method to copy the contents of the parameter `store` into this store * @see DDSketch.merge to merge two sketches safely * * @param store The store to be copied into the caller store */ BaseDDSketch.prototype._copy = function (sketch) { this.store.copy(sketch.store); this.negativeStore.copy(sketch.negativeStore); this.zeroCount = sketch.zeroCount; this.min = sketch.min; this.max = sketch.max; this.count = sketch.count; this.sum = sketch.sum; }; /** Serialize a DDSketch to protobuf format */ BaseDDSketch.prototype.toProto = function () { var message = compiled_1.DDSketch.create({ mapping: this.mapping.toProto(), positiveValues: this.store.toProto(), negativeValues: this.negativeStore.toProto(), zeroCount: this.zeroCount, min: this.min, max: this.max, sum: this.sum }); return compiled_1.DDSketch.encode(message).finish(); }; /** * Deserialize a DDSketch from protobuf data * * @param buffer Byte array containing DDSketch in protobuf format (from DDSketch.toProto) */ BaseDDSketch.fromProto = function (buffer) { var decoded = compiled_1.DDSketch.decode(buffer); var mapping = mapping_1.KeyMapping.fromProto(decoded.mapping); var store = store_1.DenseStore.fromProto(decoded.positiveValues); var negativeStore = store_1.DenseStore.fromProto(decoded.negativeValues); var zeroCount = decoded.zeroCount; var min = decoded.min; var max = decoded.max; var sum = decoded.sum; return new BaseDDSketch({ mapping: mapping, store: store, negativeStore: negativeStore, zeroCount: zeroCount, min: min, max: max, sum: sum }); }; return BaseDDSketch; }()); var defaultConfig = { relativeAccuracy: DEFAULT_RELATIVE_ACCURACY }; /** A quantile sketch with relative-error guarantees */ var DDSketch = /** @class */ (function (_super) { __extends(DDSketch, _super); /** * Initialize a new DDSketch * * @param relativeAccuracy The accuracy guarantee of the sketch (default 0.01) */ function DDSketch(_a) { var _b = _a === void 0 ? defaultConfig : _a, _c = _b.relativeAccuracy, relativeAccuracy = _c === void 0 ? DEFAULT_RELATIVE_ACCURACY : _c; var _this = this; var mapping = new mapping_1.LogarithmicMapping(relativeAccuracy); var store = new store_1.DenseStore(); var negativeStore = new store_1.DenseStore(); _this = _super.call(this, { mapping: mapping, store: store, negativeStore: negativeStore, zeroCount: 0, min: Infinity, max: -Infinity, sum: 0 }) || this; return _this; } return DDSketch; }(BaseDDSketch)); exports.DDSketch = DDSketch;