Skip to content

Commit

Permalink
Add support for T-Digest (#2214)
Browse files Browse the repository at this point in the history
* wip

* close #2216 - add support for TDIGEST.MERGESTORE and make compression optional on TDIGEST.CREATE

* fix some tdigest commands, use bloom edge docker

* fix index.ts

* 2.4-RC2 (v2.4.1)

* fix some commands and tests

* clean code
  • Loading branch information
leibale authored Nov 1, 2022
1 parent 1c6d74f commit be90e62
Show file tree
Hide file tree
Showing 33 changed files with 794 additions and 20 deletions.
18 changes: 10 additions & 8 deletions packages/bloom/lib/commands/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import Bloom from './bloom';
import CountMinSketch from './count-min-sketch';
import Cuckoo from './cuckoo';
import TopK from './top-k';
import bf from './bloom';
import cms from './count-min-sketch';
import cf from './cuckoo';
import tDigest from './t-digest';
import topK from './top-k';

export default {
bf: Bloom,
cms: CountMinSketch,
cf: Cuckoo,
topK: TopK
bf,
cms,
cf,
tDigest,
topK
};
21 changes: 21 additions & 0 deletions packages/bloom/lib/commands/t-digest/ADD.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './ADD';

describe('TDIGEST.ADD', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', [1, 2]),
['TDIGEST.ADD', 'key', '1', '2']
);
});

testUtils.testWithClient('client.tDigest.add', async client => {
const [ , reply ] = await Promise.all([
client.tDigest.create('key'),
client.tDigest.add('key', [1])
]);

assert.equal(reply, 'OK');
}, GLOBAL.SERVERS.OPEN);
});
17 changes: 17 additions & 0 deletions packages/bloom/lib/commands/t-digest/ADD.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';

export const FIRST_KEY_INDEX = 1;

export function transformArguments(
key: RedisCommandArgument,
values: Array<number>
): RedisCommandArguments {
const args = ['TDIGEST.ADD', key];
for (const item of values) {
args.push(item.toString());
}

return args;
}

export declare function transformReply(): 'OK';
21 changes: 21 additions & 0 deletions packages/bloom/lib/commands/t-digest/BYRANK.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './BYRANK';

describe('TDIGEST.BYRANK', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', [1, 2]),
['TDIGEST.BYRANK', 'key', '1', '2']
);
});

testUtils.testWithClient('client.tDigest.byRank', async client => {
const [ , reply ] = await Promise.all([
client.tDigest.create('key'),
client.tDigest.byRank('key', [1])
]);

assert.deepEqual(reply, [NaN]);
}, GLOBAL.SERVERS.OPEN);
});
19 changes: 19 additions & 0 deletions packages/bloom/lib/commands/t-digest/BYRANK.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';

export const FIRST_KEY_INDEX = 1;

export const IS_READ_ONLY = true;

export function transformArguments(
key: RedisCommandArgument,
ranks: Array<number>
): RedisCommandArguments {
const args = ['TDIGEST.BYRANK', key];
for (const rank of ranks) {
args.push(rank.toString());
}

return args;
}

export { transformDoublesReply as transformReply } from '.';
21 changes: 21 additions & 0 deletions packages/bloom/lib/commands/t-digest/BYREVRANK.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './BYREVRANK';

describe('TDIGEST.BYREVRANK', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', [1, 2]),
['TDIGEST.BYREVRANK', 'key', '1', '2']
);
});

testUtils.testWithClient('client.tDigest.byRevRank', async client => {
const [ , reply ] = await Promise.all([
client.tDigest.create('key'),
client.tDigest.byRevRank('key', [1])
]);

assert.deepEqual(reply, [NaN]);
}, GLOBAL.SERVERS.OPEN);
});
19 changes: 19 additions & 0 deletions packages/bloom/lib/commands/t-digest/BYREVRANK.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';

export const FIRST_KEY_INDEX = 1;

export const IS_READ_ONLY = true;

export function transformArguments(
key: RedisCommandArgument,
ranks: Array<number>
): RedisCommandArguments {
const args = ['TDIGEST.BYREVRANK', key];
for (const rank of ranks) {
args.push(rank.toString());
}

return args;
}

export { transformDoublesReply as transformReply } from '.';
21 changes: 21 additions & 0 deletions packages/bloom/lib/commands/t-digest/CDF.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './CDF';

describe('TDIGEST.CDF', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', [1, 2]),
['TDIGEST.CDF', 'key', '1', '2']
);
});

testUtils.testWithClient('client.tDigest.cdf', async client => {
const [ , reply ] = await Promise.all([
client.tDigest.create('key'),
client.tDigest.cdf('key', [1])
]);

assert.deepEqual(reply, [NaN]);
}, GLOBAL.SERVERS.OPEN);
});
19 changes: 19 additions & 0 deletions packages/bloom/lib/commands/t-digest/CDF.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';

export const FIRST_KEY_INDEX = 1;

export const IS_READ_ONLY = true;

export function transformArguments(
key: RedisCommandArgument,
values: Array<number>
): RedisCommandArguments {
const args = ['TDIGEST.CDF', key];
for (const item of values) {
args.push(item.toString());
}

return args;
}

export { transformDoublesReply as transformReply } from '.';
30 changes: 30 additions & 0 deletions packages/bloom/lib/commands/t-digest/CREATE.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './CREATE';

describe('TDIGEST.CREATE', () => {
describe('transformArguments', () => {
it('without options', () => {
assert.deepEqual(
transformArguments('key'),
['TDIGEST.CREATE', 'key']
);
});

it('with COMPRESSION', () => {
assert.deepEqual(
transformArguments('key', {
COMPRESSION: 100
}),
['TDIGEST.CREATE', 'key', 'COMPRESSION', '100']
);
});
});

testUtils.testWithClient('client.tDigest.create', async client => {
assert.equal(
await client.tDigest.create('key'),
'OK'
);
}, GLOBAL.SERVERS.OPEN);
});
16 changes: 16 additions & 0 deletions packages/bloom/lib/commands/t-digest/CREATE.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { CompressionOption, pushCompressionArgument } from '.';

export const FIRST_KEY_INDEX = 1;

export function transformArguments(
key: RedisCommandArgument,
options?: CompressionOption
): RedisCommandArguments {
return pushCompressionArgument(
['TDIGEST.CREATE', key],
options
);
}

export declare function transformReply(): 'OK';
25 changes: 25 additions & 0 deletions packages/bloom/lib/commands/t-digest/INFO.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './INFO';

describe('TDIGEST.INFO', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key'),
['TDIGEST.INFO', 'key']
);
});

testUtils.testWithClient('client.tDigest.info', async client => {
await client.tDigest.create('key');

const info = await client.tDigest.info('key');
assert(typeof info.capacity, 'number');
assert(typeof info.mergedNodes, 'number');
assert(typeof info.unmergedNodes, 'number');
assert(typeof info.mergedWeight, 'number');
assert(typeof info.unmergedWeight, 'number');
assert(typeof info.totalCompression, 'number');
assert(typeof info.totalCompression, 'number');
}, GLOBAL.SERVERS.OPEN);
});
51 changes: 51 additions & 0 deletions packages/bloom/lib/commands/t-digest/INFO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';

export const FIRST_KEY_INDEX = 1;

export const IS_READ_ONLY = true;

export function transformArguments(key: RedisCommandArgument): RedisCommandArguments {
return [
'TDIGEST.INFO',
key
];
}

type InfoRawReply = [
'Compression',
number,
'Capacity',
number,
'Merged nodes',
number,
'Unmerged nodes',
number,
'Merged weight',
string,
'Unmerged weight',
string,
'Total compressions',
number
];

interface InfoReply {
comperssion: number;
capacity: number;
mergedNodes: number;
unmergedNodes: number;
mergedWeight: number;
unmergedWeight: number;
totalCompression: number;
}

export function transformReply(reply: InfoRawReply): InfoReply {
return {
comperssion: reply[1],
capacity: reply[3],
mergedNodes: reply[5],
unmergedNodes: reply[7],
mergedWeight: Number(reply[9]),
unmergedWeight: Number(reply[11]),
totalCompression: reply[13]
};
}
21 changes: 21 additions & 0 deletions packages/bloom/lib/commands/t-digest/MAX.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments, transformReply } from './MAX';

describe('TDIGEST.MAX', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key'),
['TDIGEST.MAX', 'key']
);
});

testUtils.testWithClient('client.tDigest.max', async client => {
const [ , reply ] = await Promise.all([
client.tDigest.create('key'),
client.tDigest.max('key')
]);

assert.deepEqual(reply, NaN);
}, GLOBAL.SERVERS.OPEN);
});
14 changes: 14 additions & 0 deletions packages/bloom/lib/commands/t-digest/MAX.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';

export const FIRST_KEY_INDEX = 1;

export const IS_READ_ONLY = true;

export function transformArguments(key: RedisCommandArgument): RedisCommandArguments {
return [
'TDIGEST.MAX',
key
];
}

export { transformDoubleReply as transformReply } from '.';
Loading

0 comments on commit be90e62

Please sign in to comment.