@tanstack/db-ivm 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +3 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/operators/index.d.cts +1 -0
- package/dist/cjs/operators/orderBy.cjs +8 -19
- package/dist/cjs/operators/orderBy.cjs.map +1 -1
- package/dist/cjs/operators/orderBy.d.cts +6 -2
- package/dist/cjs/operators/orderByBTree.d.cts +1 -1
- package/dist/cjs/operators/tap.cjs +46 -0
- package/dist/cjs/operators/tap.cjs.map +1 -0
- package/dist/cjs/operators/tap.d.cts +18 -0
- package/dist/cjs/operators/topKWithFractionalIndex.cjs +49 -22
- package/dist/cjs/operators/topKWithFractionalIndex.cjs.map +1 -1
- package/dist/cjs/operators/topKWithFractionalIndex.d.cts +13 -14
- package/dist/cjs/operators/topKWithFractionalIndexBTree.d.cts +5 -5
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/operators/index.d.ts +1 -0
- package/dist/esm/operators/orderBy.d.ts +6 -2
- package/dist/esm/operators/orderBy.js +8 -19
- package/dist/esm/operators/orderBy.js.map +1 -1
- package/dist/esm/operators/orderByBTree.d.ts +1 -1
- package/dist/esm/operators/tap.d.ts +18 -0
- package/dist/esm/operators/tap.js +46 -0
- package/dist/esm/operators/tap.js.map +1 -0
- package/dist/esm/operators/topKWithFractionalIndex.d.ts +13 -14
- package/dist/esm/operators/topKWithFractionalIndex.js +49 -22
- package/dist/esm/operators/topKWithFractionalIndex.js.map +1 -1
- package/dist/esm/operators/topKWithFractionalIndexBTree.d.ts +5 -5
- package/package.json +1 -1
- package/src/operators/index.ts +1 -0
- package/src/operators/orderBy.ts +19 -31
- package/src/operators/tap.ts +53 -0
- package/src/operators/topKWithFractionalIndex.ts +83 -59
- package/src/operators/topKWithFractionalIndexBTree.ts +21 -19
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { DifferenceStreamWriter, LinearUnaryOperator } from "../graph.js"
|
|
2
|
+
import { StreamBuilder } from "../d2.js"
|
|
3
|
+
import type { IStreamBuilder, PipedOperator } from "../types.js"
|
|
4
|
+
import type { DifferenceStreamReader } from "../graph.js"
|
|
5
|
+
import type { MultiSet } from "../multiset.js"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Operator that applies a function to each element in the input stream
|
|
9
|
+
*/
|
|
10
|
+
export class TapOperator<T> extends LinearUnaryOperator<T, T> {
|
|
11
|
+
#f: (data: T) => void
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
id: number,
|
|
15
|
+
inputA: DifferenceStreamReader<T>,
|
|
16
|
+
output: DifferenceStreamWriter<T>,
|
|
17
|
+
f: (data: T) => void
|
|
18
|
+
) {
|
|
19
|
+
super(id, inputA, output)
|
|
20
|
+
this.#f = f
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
inner(collection: MultiSet<T>): MultiSet<T> {
|
|
24
|
+
return collection.map((data) => {
|
|
25
|
+
this.#f(data)
|
|
26
|
+
return data
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Invokes a function for each element in the input stream.
|
|
33
|
+
* This operator doesn't modify the stream and is used to perform side effects.
|
|
34
|
+
* @param f - The function to invoke on each element
|
|
35
|
+
* @returns The input stream
|
|
36
|
+
*/
|
|
37
|
+
export function tap<T>(f: (data: T) => void): PipedOperator<T, T> {
|
|
38
|
+
return (stream: IStreamBuilder<T>): IStreamBuilder<T> => {
|
|
39
|
+
const output = new StreamBuilder<T>(
|
|
40
|
+
stream.graph,
|
|
41
|
+
new DifferenceStreamWriter<T>()
|
|
42
|
+
)
|
|
43
|
+
const operator = new TapOperator<T>(
|
|
44
|
+
stream.graph.getNextOperatorId(),
|
|
45
|
+
stream.connectReader(),
|
|
46
|
+
output.writer,
|
|
47
|
+
f
|
|
48
|
+
)
|
|
49
|
+
stream.graph.addOperator(operator)
|
|
50
|
+
stream.graph.addStream(output.connectReader())
|
|
51
|
+
return output
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -2,14 +2,14 @@ import { generateKeyBetween } from "fractional-indexing"
|
|
|
2
2
|
import { DifferenceStreamWriter, UnaryOperator } from "../graph.js"
|
|
3
3
|
import { StreamBuilder } from "../d2.js"
|
|
4
4
|
import { MultiSet } from "../multiset.js"
|
|
5
|
-
import { Index } from "../indexes.js"
|
|
6
5
|
import { binarySearch, globalObjectIdGenerator } from "../utils.js"
|
|
7
6
|
import type { DifferenceStreamReader } from "../graph.js"
|
|
8
|
-
import type { IStreamBuilder,
|
|
7
|
+
import type { IStreamBuilder, PipedOperator } from "../types.js"
|
|
9
8
|
|
|
10
9
|
export interface TopKWithFractionalIndexOptions {
|
|
11
10
|
limit?: number
|
|
12
11
|
offset?: number
|
|
12
|
+
setSizeCallback?: (getSize: () => number) => void
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export type TopKChanges<V> = {
|
|
@@ -24,6 +24,7 @@ export type TopKChanges<V> = {
|
|
|
24
24
|
* and returns changes to the topK.
|
|
25
25
|
*/
|
|
26
26
|
export interface TopK<V> {
|
|
27
|
+
size: number
|
|
27
28
|
insert: (value: V) => TopKChanges<V>
|
|
28
29
|
delete: (value: V) => TopKChanges<V>
|
|
29
30
|
}
|
|
@@ -50,6 +51,13 @@ class TopKArray<V> implements TopK<V> {
|
|
|
50
51
|
this.#comparator = comparator
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
get size(): number {
|
|
55
|
+
const offset = this.#topKStart
|
|
56
|
+
const limit = this.#topKEnd - this.#topKStart
|
|
57
|
+
const available = this.#sortedValues.length - offset
|
|
58
|
+
return Math.max(0, Math.min(limit, available))
|
|
59
|
+
}
|
|
60
|
+
|
|
53
61
|
insert(value: V): TopKChanges<V> {
|
|
54
62
|
const result: TopKChanges<V> = { moveIn: null, moveOut: null }
|
|
55
63
|
|
|
@@ -158,31 +166,36 @@ class TopKArray<V> implements TopK<V> {
|
|
|
158
166
|
* This operator maintains fractional indices for sorted elements
|
|
159
167
|
* and only updates indices when elements move position
|
|
160
168
|
*/
|
|
161
|
-
export class TopKWithFractionalIndexOperator<K,
|
|
162
|
-
[K,
|
|
163
|
-
[K, IndexedValue<
|
|
169
|
+
export class TopKWithFractionalIndexOperator<K, T> extends UnaryOperator<
|
|
170
|
+
[K, T],
|
|
171
|
+
[K, IndexedValue<T>]
|
|
164
172
|
> {
|
|
165
|
-
#index
|
|
173
|
+
#index: Map<K, number> = new Map() // maps keys to their multiplicity
|
|
166
174
|
|
|
167
175
|
/**
|
|
168
176
|
* topK data structure that supports insertions and deletions
|
|
169
177
|
* and returns changes to the topK.
|
|
170
178
|
*/
|
|
171
|
-
#topK: TopK<TaggedValue<
|
|
179
|
+
#topK: TopK<TaggedValue<K, T>>
|
|
180
|
+
|
|
181
|
+
#limit: number
|
|
172
182
|
|
|
173
183
|
constructor(
|
|
174
184
|
id: number,
|
|
175
|
-
inputA: DifferenceStreamReader<[K,
|
|
176
|
-
output: DifferenceStreamWriter<[K,
|
|
177
|
-
comparator: (a:
|
|
185
|
+
inputA: DifferenceStreamReader<[K, T]>,
|
|
186
|
+
output: DifferenceStreamWriter<[K, IndexedValue<T>]>,
|
|
187
|
+
comparator: (a: T, b: T) => number,
|
|
178
188
|
options: TopKWithFractionalIndexOptions
|
|
179
189
|
) {
|
|
180
190
|
super(id, inputA, output)
|
|
181
|
-
|
|
191
|
+
this.#limit = options.limit ?? Infinity
|
|
182
192
|
const offset = options.offset ?? 0
|
|
183
|
-
const compareTaggedValues = (
|
|
193
|
+
const compareTaggedValues = (
|
|
194
|
+
a: TaggedValue<K, T>,
|
|
195
|
+
b: TaggedValue<K, T>
|
|
196
|
+
) => {
|
|
184
197
|
// First compare on the value
|
|
185
|
-
const valueComparison = comparator(
|
|
198
|
+
const valueComparison = comparator(getVal(a), getVal(b))
|
|
186
199
|
if (valueComparison !== 0) {
|
|
187
200
|
return valueComparison
|
|
188
201
|
}
|
|
@@ -191,19 +204,20 @@ export class TopKWithFractionalIndexOperator<K, V1> extends UnaryOperator<
|
|
|
191
204
|
const tieBreakerB = getTag(b)
|
|
192
205
|
return tieBreakerA - tieBreakerB
|
|
193
206
|
}
|
|
194
|
-
this.#topK = this.createTopK(offset, limit, compareTaggedValues)
|
|
207
|
+
this.#topK = this.createTopK(offset, this.#limit, compareTaggedValues)
|
|
208
|
+
options.setSizeCallback?.(() => this.#topK.size)
|
|
195
209
|
}
|
|
196
210
|
|
|
197
211
|
protected createTopK(
|
|
198
212
|
offset: number,
|
|
199
213
|
limit: number,
|
|
200
|
-
comparator: (a: TaggedValue<
|
|
201
|
-
): TopK<TaggedValue<
|
|
214
|
+
comparator: (a: TaggedValue<K, T>, b: TaggedValue<K, T>) => number
|
|
215
|
+
): TopK<TaggedValue<K, T>> {
|
|
202
216
|
return new TopKArray(offset, limit, comparator)
|
|
203
217
|
}
|
|
204
218
|
|
|
205
219
|
run(): void {
|
|
206
|
-
const result: Array<[[K,
|
|
220
|
+
const result: Array<[[K, IndexedValue<T>], number]> = []
|
|
207
221
|
for (const message of this.inputMessages()) {
|
|
208
222
|
for (const [item, multiplicity] of message.getInner()) {
|
|
209
223
|
const [key, value] = item
|
|
@@ -218,27 +232,25 @@ export class TopKWithFractionalIndexOperator<K, V1> extends UnaryOperator<
|
|
|
218
232
|
|
|
219
233
|
processElement(
|
|
220
234
|
key: K,
|
|
221
|
-
value:
|
|
235
|
+
value: T,
|
|
222
236
|
multiplicity: number,
|
|
223
|
-
result: Array<[[K,
|
|
237
|
+
result: Array<[[K, IndexedValue<T>], number]>
|
|
224
238
|
): void {
|
|
225
|
-
const oldMultiplicity = this
|
|
226
|
-
this.#index.addValue(key, [value, multiplicity])
|
|
227
|
-
const newMultiplicity = this.#index.getMultiplicity(key, value)
|
|
239
|
+
const { oldMultiplicity, newMultiplicity } = this.addKey(key, multiplicity)
|
|
228
240
|
|
|
229
|
-
let res: TopKChanges<TaggedValue<
|
|
241
|
+
let res: TopKChanges<TaggedValue<K, T>> = {
|
|
230
242
|
moveIn: null,
|
|
231
243
|
moveOut: null,
|
|
232
244
|
}
|
|
233
245
|
if (oldMultiplicity <= 0 && newMultiplicity > 0) {
|
|
234
246
|
// The value was invisible but should now be visible
|
|
235
247
|
// Need to insert it into the array of sorted values
|
|
236
|
-
const taggedValue = tagValue(value)
|
|
248
|
+
const taggedValue = tagValue(key, value)
|
|
237
249
|
res = this.#topK.insert(taggedValue)
|
|
238
250
|
} else if (oldMultiplicity > 0 && newMultiplicity <= 0) {
|
|
239
251
|
// The value was visible but should now be invisible
|
|
240
252
|
// Need to remove it from the array of sorted values
|
|
241
|
-
const taggedValue = tagValue(value)
|
|
253
|
+
const taggedValue = tagValue(key, value)
|
|
242
254
|
res = this.#topK.delete(taggedValue)
|
|
243
255
|
} else {
|
|
244
256
|
// The value was invisible and it remains invisible
|
|
@@ -247,26 +259,45 @@ export class TopKWithFractionalIndexOperator<K, V1> extends UnaryOperator<
|
|
|
247
259
|
}
|
|
248
260
|
|
|
249
261
|
if (res.moveIn) {
|
|
250
|
-
const
|
|
251
|
-
|
|
262
|
+
const index = getIndex(res.moveIn)
|
|
263
|
+
const taggedValue = getValue(res.moveIn)
|
|
264
|
+
const k = getKey(taggedValue)
|
|
265
|
+
const val = getVal(taggedValue)
|
|
266
|
+
result.push([[k, [val, index]], 1])
|
|
252
267
|
}
|
|
253
268
|
|
|
254
269
|
if (res.moveOut) {
|
|
255
|
-
const
|
|
256
|
-
|
|
270
|
+
const index = getIndex(res.moveOut)
|
|
271
|
+
const taggedValue = getValue(res.moveOut)
|
|
272
|
+
const k = getKey(taggedValue)
|
|
273
|
+
const val = getVal(taggedValue)
|
|
274
|
+
result.push([[k, [val, index]], -1])
|
|
257
275
|
}
|
|
258
276
|
|
|
259
277
|
return
|
|
260
278
|
}
|
|
279
|
+
|
|
280
|
+
private getMultiplicity(key: K): number {
|
|
281
|
+
return this.#index.get(key) ?? 0
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
private addKey(
|
|
285
|
+
key: K,
|
|
286
|
+
multiplicity: number
|
|
287
|
+
): { oldMultiplicity: number; newMultiplicity: number } {
|
|
288
|
+
const oldMultiplicity = this.getMultiplicity(key)
|
|
289
|
+
const newMultiplicity = oldMultiplicity + multiplicity
|
|
290
|
+
if (newMultiplicity === 0) {
|
|
291
|
+
this.#index.delete(key)
|
|
292
|
+
} else {
|
|
293
|
+
this.#index.set(key, newMultiplicity)
|
|
294
|
+
}
|
|
295
|
+
return { oldMultiplicity, newMultiplicity }
|
|
296
|
+
}
|
|
261
297
|
}
|
|
262
298
|
|
|
263
299
|
/**
|
|
264
300
|
* Limits the number of results based on a comparator, with optional offset.
|
|
265
|
-
* This works on a keyed stream, where the key is the first element of the tuple.
|
|
266
|
-
* The ordering is within a key group, i.e. elements are sorted within a key group
|
|
267
|
-
* and the limit + offset is applied to that sorted group.
|
|
268
|
-
* To order the entire stream, key by the same value for all elements such as null.
|
|
269
|
-
*
|
|
270
301
|
* Uses fractional indexing to minimize the number of changes when elements move positions.
|
|
271
302
|
* Each element is assigned a fractional index that is lexicographically sortable.
|
|
272
303
|
* When elements move, only the indices of the moved elements are updated, not all elements.
|
|
@@ -275,26 +306,22 @@ export class TopKWithFractionalIndexOperator<K, V1> extends UnaryOperator<
|
|
|
275
306
|
* @param options - An optional object containing limit and offset properties
|
|
276
307
|
* @returns A piped operator that orders the elements and limits the number of results
|
|
277
308
|
*/
|
|
278
|
-
export function topKWithFractionalIndex<
|
|
279
|
-
|
|
280
|
-
V1Type extends T extends KeyValue<KType, infer V> ? V : never,
|
|
281
|
-
T,
|
|
282
|
-
>(
|
|
283
|
-
comparator: (a: V1Type, b: V1Type) => number,
|
|
309
|
+
export function topKWithFractionalIndex<KType, T>(
|
|
310
|
+
comparator: (a: T, b: T) => number,
|
|
284
311
|
options?: TopKWithFractionalIndexOptions
|
|
285
|
-
): PipedOperator<
|
|
312
|
+
): PipedOperator<[KType, T], [KType, IndexedValue<T>]> {
|
|
286
313
|
const opts = options || {}
|
|
287
314
|
|
|
288
315
|
return (
|
|
289
|
-
stream: IStreamBuilder<T>
|
|
290
|
-
): IStreamBuilder<
|
|
291
|
-
const output = new StreamBuilder<
|
|
316
|
+
stream: IStreamBuilder<[KType, T]>
|
|
317
|
+
): IStreamBuilder<[KType, IndexedValue<T>]> => {
|
|
318
|
+
const output = new StreamBuilder<[KType, IndexedValue<T>]>(
|
|
292
319
|
stream.graph,
|
|
293
|
-
new DifferenceStreamWriter<
|
|
320
|
+
new DifferenceStreamWriter<[KType, IndexedValue<T>]>()
|
|
294
321
|
)
|
|
295
|
-
const operator = new TopKWithFractionalIndexOperator<KType,
|
|
322
|
+
const operator = new TopKWithFractionalIndexOperator<KType, T>(
|
|
296
323
|
stream.graph.getNextOperatorId(),
|
|
297
|
-
stream.connectReader()
|
|
324
|
+
stream.connectReader(),
|
|
298
325
|
output.writer,
|
|
299
326
|
comparator,
|
|
300
327
|
opts
|
|
@@ -324,24 +351,21 @@ export function getIndex<V>(indexedVal: IndexedValue<V>): FractionalIndex {
|
|
|
324
351
|
return indexedVal[1]
|
|
325
352
|
}
|
|
326
353
|
|
|
327
|
-
function mapValue<V, W>(
|
|
328
|
-
indexedVal: IndexedValue<V>,
|
|
329
|
-
f: (value: V) => W
|
|
330
|
-
): IndexedValue<W> {
|
|
331
|
-
return [f(getValue(indexedVal)), getIndex(indexedVal)]
|
|
332
|
-
}
|
|
333
|
-
|
|
334
354
|
export type Tag = number
|
|
335
|
-
export type TaggedValue<V> = [V, Tag]
|
|
355
|
+
export type TaggedValue<K, V> = [K, V, Tag]
|
|
336
356
|
|
|
337
|
-
function tagValue<V>(value: V): TaggedValue<V> {
|
|
338
|
-
return [value, globalObjectIdGenerator.getId(
|
|
357
|
+
function tagValue<K, V>(key: K, value: V): TaggedValue<K, V> {
|
|
358
|
+
return [key, value, globalObjectIdGenerator.getId(key)]
|
|
339
359
|
}
|
|
340
360
|
|
|
341
|
-
function
|
|
361
|
+
function getKey<K, V>(tieBreakerTaggedValue: TaggedValue<K, V>): K {
|
|
342
362
|
return tieBreakerTaggedValue[0]
|
|
343
363
|
}
|
|
344
364
|
|
|
345
|
-
function
|
|
365
|
+
function getVal<K, V>(tieBreakerTaggedValue: TaggedValue<K, V>): V {
|
|
346
366
|
return tieBreakerTaggedValue[1]
|
|
347
367
|
}
|
|
368
|
+
|
|
369
|
+
function getTag<K, V>(tieBreakerTaggedValue: TaggedValue<K, V>): Tag {
|
|
370
|
+
return tieBreakerTaggedValue[2]
|
|
371
|
+
}
|
|
@@ -7,8 +7,7 @@ import {
|
|
|
7
7
|
getValue,
|
|
8
8
|
indexedValue,
|
|
9
9
|
} from "./topKWithFractionalIndex.js"
|
|
10
|
-
import type { IStreamBuilder,
|
|
11
|
-
import type { DifferenceStreamReader } from "../graph.js"
|
|
10
|
+
import type { IStreamBuilder, PipedOperator } from "../types.js"
|
|
12
11
|
import type {
|
|
13
12
|
IndexedValue,
|
|
14
13
|
TaggedValue,
|
|
@@ -76,6 +75,13 @@ class TopKTree<V> implements TopK<V> {
|
|
|
76
75
|
this.#tree = new BTree(undefined, comparator)
|
|
77
76
|
}
|
|
78
77
|
|
|
78
|
+
get size(): number {
|
|
79
|
+
const offset = this.#topKStart
|
|
80
|
+
const limit = this.#topKEnd - this.#topKStart
|
|
81
|
+
const available = this.#tree.size - offset
|
|
82
|
+
return Math.max(0, Math.min(limit, available))
|
|
83
|
+
}
|
|
84
|
+
|
|
79
85
|
/**
|
|
80
86
|
* Insert a *new* value.
|
|
81
87
|
* Ignores the value if it is already present.
|
|
@@ -238,13 +244,13 @@ class TopKTree<V> implements TopK<V> {
|
|
|
238
244
|
*/
|
|
239
245
|
export class TopKWithFractionalIndexBTreeOperator<
|
|
240
246
|
K,
|
|
241
|
-
|
|
242
|
-
> extends TopKWithFractionalIndexOperator<K,
|
|
247
|
+
T,
|
|
248
|
+
> extends TopKWithFractionalIndexOperator<K, T> {
|
|
243
249
|
protected override createTopK(
|
|
244
250
|
offset: number,
|
|
245
251
|
limit: number,
|
|
246
|
-
comparator: (a: TaggedValue<
|
|
247
|
-
): TopK<TaggedValue<
|
|
252
|
+
comparator: (a: TaggedValue<K, T>, b: TaggedValue<K, T>) => number
|
|
253
|
+
): TopK<TaggedValue<K, T>> {
|
|
248
254
|
if (BTree === undefined) {
|
|
249
255
|
throw new Error(
|
|
250
256
|
`B+ tree not loaded. You need to call loadBTree() before using TopKWithFractionalIndexBTreeOperator.`
|
|
@@ -269,14 +275,10 @@ export class TopKWithFractionalIndexBTreeOperator<
|
|
|
269
275
|
* @param options - An optional object containing limit and offset properties
|
|
270
276
|
* @returns A piped operator that orders the elements and limits the number of results
|
|
271
277
|
*/
|
|
272
|
-
export function topKWithFractionalIndexBTree<
|
|
273
|
-
|
|
274
|
-
V1Type extends T extends KeyValue<KType, infer V> ? V : never,
|
|
275
|
-
T,
|
|
276
|
-
>(
|
|
277
|
-
comparator: (a: V1Type, b: V1Type) => number,
|
|
278
|
+
export function topKWithFractionalIndexBTree<KType, T>(
|
|
279
|
+
comparator: (a: T, b: T) => number,
|
|
278
280
|
options?: TopKWithFractionalIndexOptions
|
|
279
|
-
): PipedOperator<
|
|
281
|
+
): PipedOperator<[KType, T], [KType, IndexedValue<T>]> {
|
|
280
282
|
const opts = options || {}
|
|
281
283
|
|
|
282
284
|
if (BTree === undefined) {
|
|
@@ -286,15 +288,15 @@ export function topKWithFractionalIndexBTree<
|
|
|
286
288
|
}
|
|
287
289
|
|
|
288
290
|
return (
|
|
289
|
-
stream: IStreamBuilder<T>
|
|
290
|
-
): IStreamBuilder<
|
|
291
|
-
const output = new StreamBuilder<
|
|
291
|
+
stream: IStreamBuilder<[KType, T]>
|
|
292
|
+
): IStreamBuilder<[KType, IndexedValue<T>]> => {
|
|
293
|
+
const output = new StreamBuilder<[KType, IndexedValue<T>]>(
|
|
292
294
|
stream.graph,
|
|
293
|
-
new DifferenceStreamWriter<
|
|
295
|
+
new DifferenceStreamWriter<[KType, IndexedValue<T>]>()
|
|
294
296
|
)
|
|
295
|
-
const operator = new
|
|
297
|
+
const operator = new TopKWithFractionalIndexBTreeOperator<KType, T>(
|
|
296
298
|
stream.graph.getNextOperatorId(),
|
|
297
|
-
stream.connectReader()
|
|
299
|
+
stream.connectReader(),
|
|
298
300
|
output.writer,
|
|
299
301
|
comparator,
|
|
300
302
|
opts
|