Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | 3x 3x 3x 3x 3x 3x 175x 175x 175x 3x 3x 172x 172x 160x 160x 12x 5x 5x 7x 7x 7x 172x 172x 184x 184x 16x 168x 157x 11x 7x 172x 172x | import type { Context, AttributeValue, FeatureKey, BucketBy } from "@featurevisor/types";
import { Logger } from "./logger";
import { getValueFromContext } from "./conditions";
import { MurmurHashV3 } from "./murmurhash";
export type BucketKey = string;
export type BucketValue = number; // 0 to 100,000 (100% * 1000 to include three decimal places in same integer)
/**
* Generic hashing
*/
const HASH_SEED = 1;
const MAX_HASH_VALUE = Math.pow(2, 32);
export const MAX_BUCKETED_NUMBER = 100000; // 100% * 1000 to include three decimal places in the same integer value
export function getBucketedNumber(bucketKey: string): BucketValue {
const hashValue = MurmurHashV3(bucketKey, HASH_SEED);
const ratio = hashValue / MAX_HASH_VALUE;
return Math.floor(ratio * MAX_BUCKETED_NUMBER);
}
/**
* Bucket key
*/
const DEFAULT_BUCKET_KEY_SEPARATOR = ".";
export interface GetBucketKeyOptions {
featureKey: FeatureKey;
bucketBy: BucketBy;
context: Context;
logger: Logger;
}
export function getBucketKey(options: GetBucketKeyOptions): BucketKey {
const {
featureKey,
bucketBy,
context,
logger,
} = options;
let type;
let attributeKeys;
if (typeof bucketBy === "string") {
type = "plain";
attributeKeys = [bucketBy];
} else if (Array.isArray(bucketBy)) {
type = "and";
attributeKeys = bucketBy;
} else if (typeof bucketBy === "object" && Array.isArray(bucketBy.or)) {
type = "or";
attributeKeys = bucketBy.or;
} else E{
logger.error("invalid bucketBy", { featureKey, bucketBy });
throw new Error("invalid bucketBy");
}
const bucketKey: AttributeValue[] = [];
attributeKeys.forEach((attributeKey) => {
const attributeValue = getValueFromContext(context, attributeKey);
if (typeof attributeValue === "undefined") {
return;
}
if (type === "plain" || type === "and") {
bucketKey.push(attributeValue);
} else {
// or
if (bucketKey.length === 0) {
bucketKey.push(attributeValue);
}
}
});
bucketKey.push(featureKey);
return bucketKey.join(DEFAULT_BUCKET_KEY_SEPARATOR);
}
|