datasketches-cpp
Loading...
Searching...
No Matches
frequent_items_sketch_impl.hpp
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#ifndef FREQUENT_ITEMS_SKETCH_IMPL_HPP_
21#define FREQUENT_ITEMS_SKETCH_IMPL_HPP_
22
23#include <cstring>
24#include <limits>
25#include <sstream>
26#include <stdexcept>
27
28#include "memory_operations.hpp"
29
30namespace datasketches {
31
32// clang++ seems to require this declaration for CMAKE_BUILD_TYPE='Debug"
33template<typename T, typename W, typename H, typename E, typename A>
34const uint8_t frequent_items_sketch<T, W, H, E, A>::LG_MIN_MAP_SIZE;
35
36template<typename T, typename W, typename H, typename E, typename A>
37frequent_items_sketch<T, W, H, E, A>::frequent_items_sketch(uint8_t lg_max_map_size, uint8_t lg_start_map_size,
38 const E& equal, const A& allocator):
39total_weight(0),
40offset(0),
41map(
42 std::max(lg_start_map_size, frequent_items_sketch::LG_MIN_MAP_SIZE),
43 std::max(lg_max_map_size, frequent_items_sketch::LG_MIN_MAP_SIZE),
44 equal,
45 allocator
46)
47{
48 if (lg_start_map_size > lg_max_map_size) { throw std::invalid_argument("starting size must not be greater than maximum size"); }
49}
50
51template<typename T, typename W, typename H, typename E, typename A>
52void frequent_items_sketch<T, W, H, E, A>::update(const T& item, W weight) {
53 check_weight(weight);
54 if (weight == 0) { return; }
55 total_weight += weight;
56 offset += map.adjust_or_insert(item, weight);
57}
58
59template<typename T, typename W, typename H, typename E, typename A>
61 check_weight(weight);
62 if (weight == 0) { return; }
63 total_weight += weight;
64 offset += map.adjust_or_insert(std::move(item), weight);
65}
66
67template<typename T, typename W, typename H, typename E, typename A>
69 if (other.is_empty()) { return; }
70 const W merged_total_weight = total_weight + other.get_total_weight(); // for correction at the end
71 for (auto it: other.map) {
72 update(it.first, it.second);
73 }
74 offset += other.offset;
75 total_weight = merged_total_weight;
76}
77
78template<typename T, typename W, typename H, typename E, typename A>
80 if (other.is_empty()) { return; }
81 const W merged_total_weight = total_weight + other.get_total_weight(); // for correction at the end
82 for (auto it: other.map) {
83 update(std::move(it.first), it.second);
84 }
85 offset += other.offset;
86 total_weight = merged_total_weight;
87}
88
89template<typename T, typename W, typename H, typename E, typename A>
91 map = reverse_purge_hash_map<T, W, H, E, A>(LG_MIN_MAP_SIZE, map.get_lg_max_size(), map.get_equal(), map.get_allocator());
92 total_weight = 0;
93 offset = 0;
94}
95
96template<typename T, typename W, typename H, typename E, typename A>
98 // a purge may clear all counters while offset and total_weight remain non-zero;
99 // emptiness must mean "no observations", not "no retained items"
100 return total_weight == 0;
101}
102
103template<typename T, typename W, typename H, typename E, typename A>
105 return map.get_num_active();
106}
107
108template<typename T, typename W, typename H, typename E, typename A>
110 return total_weight;
111}
112
113template<typename T, typename W, typename H, typename E, typename A>
115 // if item is tracked estimate = weight + offset, otherwise 0
116 const W weight = map.get(item);
117 if (weight > 0) { return weight + offset; }
118 return 0;
119}
120
121template<typename T, typename W, typename H, typename E, typename A>
123 return map.get(item);
124}
125
126template<typename T, typename W, typename H, typename E, typename A>
128 return map.get(item) + offset;
129}
130
131template<typename T, typename W, typename H, typename E, typename A>
135
136template<typename T, typename W, typename H, typename E, typename A>
138 return EPSILON_FACTOR / (1 << map.get_lg_max_size());
139}
140
141template<typename T, typename W, typename H, typename E, typename A>
143 return EPSILON_FACTOR / (1 << lg_max_map_size);
144}
145
146template<typename T, typename W, typename H, typename E, typename A>
147double frequent_items_sketch<T, W, H, E, A>::get_apriori_error(uint8_t lg_max_map_size, W estimated_total_weight) {
148 return get_epsilon(lg_max_map_size) * estimated_total_weight;
149}
150
151
152template<typename T, typename W, typename H, typename E, typename A>
156
157template<typename T, typename W, typename H, typename E, typename A>
159 vector_row items(map.get_allocator());
160 for (auto it: map) {
161 const W lb = it.second;
162 const W ub = it.second + offset;
163 if ((err_type == NO_FALSE_NEGATIVES && ub > threshold) || (err_type == NO_FALSE_POSITIVES && lb > threshold)) {
164 items.push_back(row(&it.first, it.second, offset));
165 }
166 }
167 // sort by estimate in descending order
168 std::sort(items.begin(), items.end(), [](row a, row b){ return a.get_estimate() > b.get_estimate(); });
169 return items;
170}
171
172template<typename T, typename W, typename H, typename E, typename A>
173template<typename SerDe>
174void frequent_items_sketch<T, W, H, E, A>::serialize(std::ostream& os, const SerDe& sd) const {
175 const uint8_t preamble_longs = is_empty() ? PREAMBLE_LONGS_EMPTY : PREAMBLE_LONGS_NONEMPTY;
176 write(os, preamble_longs);
177 const uint8_t serial_version = SERIAL_VERSION;
178 write(os, serial_version);
179 const uint8_t family = FAMILY_ID;
180 write(os, family);
181 const uint8_t lg_max_size = map.get_lg_max_size();
182 write(os, lg_max_size);
183 const uint8_t lg_cur_size = map.get_lg_cur_size();
184 write(os, lg_cur_size);
185 const uint8_t flags_byte(
186 (is_empty() ? 1 << flags::IS_EMPTY_1 : 0)
187 | (is_empty() ? 1 << flags::IS_EMPTY_2 : 0)
188 );
189 write(os, flags_byte);
190 const uint16_t unused16 = 0;
191 write(os, unused16);
192 if (!is_empty()) {
193 const uint32_t num_items = map.get_num_active();
194 write(os, num_items);
195 const uint32_t unused32 = 0;
196 write(os, unused32);
197 write(os, total_weight);
198 write(os, offset);
199
200 // copy active items and their weights to use batch serialization
201 using AllocW = typename std::allocator_traits<A>::template rebind_alloc<W>;
202 AllocW aw(map.get_allocator());
203 W* weights = aw.allocate(num_items);
204 A alloc(map.get_allocator());
205 T* items = alloc.allocate(num_items);
206 uint32_t i = 0;
207 for (auto it: map) {
208 new (&items[i]) T(it.first);
209 weights[i++] = it.second;
210 }
211 write(os, weights, sizeof(W) * num_items);
212 aw.deallocate(weights, num_items);
213 sd.serialize(os, items, num_items);
214 for (i = 0; i < num_items; i++) items[i].~T();
215 alloc.deallocate(items, num_items);
216 }
217}
218
219template<typename T, typename W, typename H, typename E, typename A>
220template<typename SerDe>
222 if (is_empty()) { return PREAMBLE_LONGS_EMPTY * sizeof(uint64_t); }
223 size_t size = PREAMBLE_LONGS_NONEMPTY * sizeof(uint64_t) + map.get_num_active() * sizeof(W);
224 for (auto it: map) size += sd.size_of_item(it.first);
225 return size;
226}
227
228template<typename T, typename W, typename H, typename E, typename A>
229template<typename SerDe>
230auto frequent_items_sketch<T, W, H, E, A>::serialize(unsigned header_size_bytes, const SerDe& sd) const -> vector_bytes {
231 const size_t size = header_size_bytes + get_serialized_size_bytes(sd);
232 vector_bytes bytes(size, 0, map.get_allocator());
233 uint8_t* ptr = bytes.data() + header_size_bytes;
234 uint8_t* end_ptr = ptr + size;
235
236 const uint8_t preamble_longs = is_empty() ? PREAMBLE_LONGS_EMPTY : PREAMBLE_LONGS_NONEMPTY;
237 ptr += copy_to_mem(preamble_longs, ptr);
238 const uint8_t serial_version = SERIAL_VERSION;
239 ptr += copy_to_mem(serial_version, ptr);
240 const uint8_t family = FAMILY_ID;
241 ptr += copy_to_mem(family, ptr);
242 const uint8_t lg_max_size = map.get_lg_max_size();
243 ptr += copy_to_mem(lg_max_size, ptr);
244 const uint8_t lg_cur_size = map.get_lg_cur_size();
245 ptr += copy_to_mem(lg_cur_size, ptr);
246 const uint8_t flags_byte(
247 (is_empty() ? 1 << flags::IS_EMPTY_1 : 0)
248 | (is_empty() ? 1 << flags::IS_EMPTY_2 : 0)
249 );
250 ptr += copy_to_mem(flags_byte, ptr);
251 ptr += sizeof(uint16_t); // unused
252 if (!is_empty()) {
253 const uint32_t num_items = map.get_num_active();
254 ptr += copy_to_mem(num_items, ptr);
255 ptr += sizeof(uint32_t); // unused
256 ptr += copy_to_mem(total_weight, ptr);
257 ptr += copy_to_mem(offset, ptr);
258
259 // copy active items and their weights to use batch serialization
260 using AllocW = typename std::allocator_traits<A>::template rebind_alloc<W>;
261 AllocW aw(map.get_allocator());
262 W* weights = aw.allocate(num_items);
263 A alloc(map.get_allocator());
264 T* items = alloc.allocate(num_items);
265 uint32_t i = 0;
266 for (auto it: map) {
267 new (&items[i]) T(it.first);
268 weights[i++] = it.second;
269 }
270 ptr += copy_to_mem(weights, ptr, sizeof(W) * num_items);
271 aw.deallocate(weights, num_items);
272 const size_t bytes_remaining = end_ptr - ptr;
273 ptr += sd.serialize(ptr, bytes_remaining, items, num_items);
274 for (i = 0; i < num_items; i++) items[i].~T();
275 alloc.deallocate(items, num_items);
276 }
277 return bytes;
278}
279
280template<typename T, typename W, typename H, typename E, typename A>
281class frequent_items_sketch<T, W, H, E, A>::items_deleter {
282public:
283 items_deleter(uint32_t num, bool destroy, const A& allocator):
284 allocator_(allocator), num_(num), destroy_(destroy) {}
285 void set_destroy(bool destroy) { destroy_ = destroy; }
286 void operator() (T* ptr) {
287 if (ptr != nullptr) {
288 if (destroy_) {
289 for (uint32_t i = 0; i < num_; ++i) ptr[i].~T();
290 }
291 allocator_.deallocate(ptr, num_);
292 }
293 }
294private:
295 A allocator_;
296 uint32_t num_;
297 bool destroy_;
298};
299
300template<typename T, typename W, typename H, typename E, typename A>
301template<typename SerDe>
303 const SerDe& sd, const E& equal, const A& allocator) {
304 const auto preamble_longs = read<uint8_t>(is);
305 const auto serial_version = read<uint8_t>(is);
306 const auto family_id = read<uint8_t>(is);
307 const auto lg_max_size = read<uint8_t>(is);
308 const auto lg_cur_size = read<uint8_t>(is);
309 const auto flags_byte = read<uint8_t>(is);
310 read<uint16_t>(is); // unused
311
312 check_preamble_longs(preamble_longs, flags_byte);
313 const bool is_empty = preamble_longs == PREAMBLE_LONGS_EMPTY;
314 check_serial_version(serial_version);
315 check_family_id(family_id);
316 check_size(lg_cur_size, lg_max_size);
317
318 frequent_items_sketch sketch(lg_max_size, lg_cur_size, equal, allocator);
319 if (!is_empty) {
320 const auto num_items = read<uint32_t>(is);
321 read<uint32_t>(is); // unused
322 const auto total_weight = read<W>(is);
323 const auto offset = read<W>(is);
324 check_total_weight(total_weight);
325
326 // batch deserialization with intermediate array of items and weights
327 using AllocW = typename std::allocator_traits<A>::template rebind_alloc<W>;
328 std::vector<W, AllocW> weights(num_items, 0, allocator);
329 read(is, weights.data(), sizeof(W) * num_items);
330 A alloc(allocator);
331 std::unique_ptr<T, items_deleter> items(alloc.allocate(num_items), items_deleter(num_items, false, alloc));
332 sd.deserialize(is, items.get(), num_items);
333 items.get_deleter().set_destroy(true); // serde did not throw, so the items must be constructed
334 for (uint32_t i = 0; i < num_items; i++) {
335 sketch.update(std::move(items.get()[i]), weights[i]);
336 }
337 sketch.total_weight = total_weight;
338 sketch.offset = offset;
339 }
340 if (!is.good()) { throw std::runtime_error("error reading from std::istream"); }
341 return sketch;
342}
343
344template<typename T, typename W, typename H, typename E, typename A>
345template<typename SerDe>
347 const SerDe& sd, const E& equal, const A& allocator) {
348 ensure_minimum_memory(size, 8);
349 const char* ptr = static_cast<const char*>(bytes);
350 const char* base = static_cast<const char*>(bytes);
351 uint8_t preamble_longs;
352 ptr += copy_from_mem(ptr, preamble_longs);
353 uint8_t serial_version;
354 ptr += copy_from_mem(ptr, serial_version);
355 uint8_t family_id;
356 ptr += copy_from_mem(ptr, family_id);
357 uint8_t lg_max_size;
358 ptr += copy_from_mem(ptr, lg_max_size);
359 uint8_t lg_cur_size;
360 ptr += copy_from_mem(ptr, lg_cur_size);
361 uint8_t flags_byte;
362 ptr += copy_from_mem(ptr, flags_byte);
363 ptr += sizeof(uint16_t); // unused
364
365 check_preamble_longs(preamble_longs, flags_byte);
366 const bool is_empty = preamble_longs == PREAMBLE_LONGS_EMPTY;
367 check_serial_version(serial_version);
368 check_family_id(family_id);
369 check_size(lg_cur_size, lg_max_size);
370 ensure_minimum_memory(size, preamble_longs * sizeof(uint64_t));
371
372 frequent_items_sketch sketch(lg_max_size, lg_cur_size, equal, allocator);
373 if (!is_empty) {
374 uint32_t num_items;
375 ptr += copy_from_mem(ptr, num_items);
376 ptr += sizeof(uint32_t); // unused
377 W total_weight;
378 ptr += copy_from_mem(ptr, total_weight);
379 W offset;
380 ptr += copy_from_mem(ptr, offset);
381 check_total_weight(total_weight);
382
383 ensure_minimum_memory(size, ptr - base + (sizeof(W) * num_items));
384 // batch deserialization with intermediate array of items and weights
385 using AllocW = typename std::allocator_traits<A>::template rebind_alloc<W>;
386 std::vector<W, AllocW> weights(num_items, 0, allocator);
387 ptr += copy_from_mem(ptr, weights.data(), sizeof(W) * num_items);
388 A alloc(allocator);
389 std::unique_ptr<T, items_deleter> items(alloc.allocate(num_items), items_deleter(num_items, false, alloc));
390 const size_t bytes_remaining = size - (ptr - base);
391 ptr += sd.deserialize(ptr, bytes_remaining, items.get(), num_items);
392 items.get_deleter().set_destroy(true); // serde did not throw, so the items must be constructed
393 for (uint32_t i = 0; i < num_items; i++) {
394 sketch.update(std::move(items.get()[i]), weights[i]);
395 }
396
397 sketch.total_weight = total_weight;
398 sketch.offset = offset;
399 }
400 return sketch;
401}
402
403template<typename T, typename W, typename H, typename E, typename A>
404void frequent_items_sketch<T, W, H, E, A>::check_preamble_longs(uint8_t preamble_longs, uint8_t flags_byte) {
405 if (preamble_longs != PREAMBLE_LONGS_EMPTY && preamble_longs != PREAMBLE_LONGS_NONEMPTY) {
406 throw std::invalid_argument("Possible corruption: preamble longs must be " + std::to_string(PREAMBLE_LONGS_EMPTY)
407 + " or " + std::to_string(PREAMBLE_LONGS_NONEMPTY) + ": " + std::to_string(preamble_longs));
408 }
409 const bool empty_flag = (flags_byte & ((1 << flags::IS_EMPTY_1) | (1 << flags::IS_EMPTY_2))) != 0;
410 if (empty_flag != (preamble_longs == PREAMBLE_LONGS_EMPTY)) {
411 throw std::invalid_argument("Possible corruption: empty flag does not match preamble longs: flags "
412 + std::to_string(flags_byte) + ", preamble longs " + std::to_string(preamble_longs));
413 }
414}
415
416template<typename T, typename W, typename H, typename E, typename A>
417void frequent_items_sketch<T, W, H, E, A>::check_total_weight(W total_weight) {
418 // written as !(x > 0) to also reject NaN
419 if (!(total_weight > 0)) {
420 throw std::invalid_argument("Possible corruption: total weight of a non-empty sketch must be positive");
421 }
422}
423
424template<typename T, typename W, typename H, typename E, typename A>
425void frequent_items_sketch<T, W, H, E, A>::check_serial_version(uint8_t serial_version) {
426 if (serial_version != SERIAL_VERSION) {
427 throw std::invalid_argument("Possible corruption: serial version must be " + std::to_string(SERIAL_VERSION) + ": " + std::to_string(serial_version));
428 }
429}
430
431template<typename T, typename W, typename H, typename E, typename A>
432void frequent_items_sketch<T, W, H, E, A>::check_family_id(uint8_t family_id) {
433 if (family_id != FAMILY_ID) {
434 throw std::invalid_argument("Possible corruption: family ID must be " + std::to_string(FAMILY_ID) + ": " + std::to_string(family_id));
435 }
436}
437
438template<typename T, typename W, typename H, typename E, typename A>
439void frequent_items_sketch<T, W, H, E, A>::check_size(uint8_t lg_cur_size, uint8_t lg_max_size) {
440 if (lg_cur_size > lg_max_size) {
441 throw std::invalid_argument("Possible corruption: expected lg_cur_size <= lg_max_size: " + std::to_string(lg_cur_size) + " <= " + std::to_string(lg_max_size));
442 }
443 if (lg_cur_size < LG_MIN_MAP_SIZE) {
444 throw std::invalid_argument("Possible corruption: lg_cur_size must not be less than " + std::to_string(LG_MIN_MAP_SIZE) + ": " + std::to_string(lg_cur_size));
445 }
446}
447
448template<typename T, typename W, typename H, typename E, typename A>
449string<A> frequent_items_sketch<T, W, H, E, A>::to_string(bool print_items) const {
450 // Using a temporary stream for implementation here does not comply with AllocatorAwareContainer requirements.
451 // The stream does not support passing an allocator instance, and alternatives are complicated.
452 std::ostringstream os;
453 os << "### Frequent items sketch summary:" << std::endl;
454 os << " lg cur map size : " << (int) map.get_lg_cur_size() << std::endl;
455 os << " lg max map size : " << (int) map.get_lg_max_size() << std::endl;
456 os << " num active items : " << get_num_active_items() << std::endl;
457 os << " total weight : " << get_total_weight() << std::endl;
458 os << " max error : " << get_maximum_error() << std::endl;
459 os << "### End sketch summary" << std::endl;
460 if (print_items) {
461 vector_row items;
462 for (auto it: map) {
463 items.push_back(row(&it.first, it.second, offset));
464 }
465 // sort by estimate in descending order
466 std::sort(items.begin(), items.end(), [](row a, row b){ return a.get_estimate() > b.get_estimate(); });
467 os << "### Items in descending order by estimate" << std::endl;
468 os << " item, estimate, lower bound, upper bound" << std::endl;
469 for (auto it: items) {
470 os << " " << it.get_item() << ", " << it.get_estimate() << ", "
471 << it.get_lower_bound() << ", " << it.get_upper_bound() << std::endl;
472 }
473 os << "### End items" << std::endl;
474 }
475 return string<A>(os.str().c_str(), map.get_allocator());
476}
477
478// version for integral signed type
479template<typename T, typename W, typename H, typename E, typename A>
480template<typename WW, typename std::enable_if<std::is_integral<WW>::value && std::is_signed<WW>::value, int>::type>
481void frequent_items_sketch<T, W, H, E, A>::check_weight(WW weight) {
482 if (weight < 0) {
483 throw std::invalid_argument("weight must be non-negative");
484 }
485}
486
487// version for integral unsigned type - no-op
488template<typename T, typename W, typename H, typename E, typename A>
489template<typename WW, typename std::enable_if<std::is_integral<WW>::value && std::is_unsigned<WW>::value, int>::type>
490void frequent_items_sketch<T, W, H, E, A>::check_weight(WW) {}
491
492// version for floating point type
493template<typename T, typename W, typename H, typename E, typename A>
494template<typename WW, typename std::enable_if<std::is_floating_point<WW>::value, int>::type>
495void frequent_items_sketch<T, W, H, E, A>::check_weight(WW weight) {
496 if (weight < 0) {
497 throw std::invalid_argument("weight must be non-negative");
498 }
499 if (std::isnan(weight)) {
500 throw std::invalid_argument("weight must be a valid number");
501 }
502 if (std::isinf(weight)) {
503 throw std::invalid_argument("weight must be finite");
504 }
505}
506
507}
508
509#endif
Row in the output from get_frequent_items.
Definition frequent_items_sketch.hpp:355
Frequent Items sketch.
Definition frequent_items_sketch.hpp:60
frequent_items_sketch(uint8_t lg_max_map_size, uint8_t lg_start_map_size=LG_MIN_MAP_SIZE, const E &equal=E(), const A &allocator=A())
Construct this sketch with parameters lg_max_map_size and lg_start_map_size.
Definition frequent_items_sketch_impl.hpp:37
W get_upper_bound(const T &item) const
Returns the guaranteed upper bound weight (frequency) of the given item.
Definition frequent_items_sketch_impl.hpp:127
void merge(const frequent_items_sketch &other)
This function merges the other sketch into this one.
Definition frequent_items_sketch_impl.hpp:68
void serialize(std::ostream &os, const SerDe &sd=SerDe()) const
This method serializes the sketch into a given stream in a binary form.
Definition frequent_items_sketch_impl.hpp:174
vector_row get_frequent_items(frequent_items_error_type err_type) const
Returns an array of rows that include frequent items, estimates, upper and lower bounds given an erro...
Definition frequent_items_sketch_impl.hpp:153
bool is_empty() const
A sketch is empty if it has not been updated with any positive weight.
Definition frequent_items_sketch_impl.hpp:97
string< A > to_string(bool print_items=false) const
Returns a human readable summary of this sketch.
Definition frequent_items_sketch_impl.hpp:449
void update(const T &item, W weight=1)
Update this sketch with an item and a positive weight (frequency count).
Definition frequent_items_sketch_impl.hpp:52
static double get_apriori_error(uint8_t lg_max_map_size, W estimated_total_weight)
Returns the estimated a priori error given the max_map_size for the sketch and the estimated_total_st...
Definition frequent_items_sketch_impl.hpp:147
W get_total_weight() const
Returns the sum of the weights (frequencies) in the stream seen so far by the sketch.
Definition frequent_items_sketch_impl.hpp:109
double get_epsilon() const
Returns epsilon value of this sketch.
Definition frequent_items_sketch_impl.hpp:137
size_t get_serialized_size_bytes(const SerDe &sd=SerDe()) const
Computes size needed to serialize the current state of the sketch.
Definition frequent_items_sketch_impl.hpp:221
W get_maximum_error() const
Definition frequent_items_sketch_impl.hpp:132
W get_estimate(const T &item) const
Returns the estimate of the weight (frequency) of the given item.
Definition frequent_items_sketch_impl.hpp:114
static frequent_items_sketch deserialize(std::istream &is, const SerDe &sd=SerDe(), const E &equal=E(), const A &allocator=A())
This method deserializes a sketch from a given stream.
void reset()
Resets this sketch to the empty state, as if newly constructed.
Definition frequent_items_sketch_impl.hpp:90
W get_lower_bound(const T &item) const
Returns the guaranteed lower bound weight (frequency) of the given item.
Definition frequent_items_sketch_impl.hpp:122
uint32_t get_num_active_items() const
Definition frequent_items_sketch_impl.hpp:104
DataSketches namespace.
Definition binomial_bounds.hpp:38
frequent_items_error_type
Frequent items error type.
Definition frequent_items_sketch.hpp:36
@ NO_FALSE_NEGATIVES
include an item in the result list if get_upper_bound(item) > threshold
Definition frequent_items_sketch.hpp:38
@ NO_FALSE_POSITIVES
include an item in the result list if get_lower_bound(item) > threshold
Definition frequent_items_sketch.hpp:37