R7.04.2 · dive 2
The analytics are bit arithmetic.
Once flags are bits, the analytics are bit arithmetic. BITCOUNT answers "how many are
set"; BITOP combines bitmaps with AND / OR / XOR / NOT; BITPOS finds the first set or
unset bit.
None of them enumerate the entities. A segment question becomes one BITOP
followed by one BITCOUNT, over the bits, in the engine — which is what makes bitmaps an
analytics encoding rather than only a flag store. Select a range; the readout runs the population count over
the bits below.
users:active. Select a range; the readout reports
the population count over it.BITCOUNT users:active over offsets 0–15 counts the set bits — six of them.BITCOUNT — the population count
bitmap-patterns.md.txt · count the set bitsBITCOUNT key counts the set bits in the string — the number of flagged entities. The optional
start/end restrict it to a byte range, or a bit range with the BIT
modifier:
BITCOUNT users:active # count every set bit BITCOUNT users:active 0 0 # set bits in byte 0 BITCOUNT users:active 0 0 BIT # set bits in bit 0 (the BIT range form)
The work is a popcount, which the engine does in hardware-sized steps over the string, so counting a
million-flag bitmap is one fast scan, not a million reads. BITCOUNT is the size of any cohort,
window, or flag set: daily active users, online users, holders of a feature — each is the count of one
bitmap.
BITCOUNT is the size of a set of flags, computed as a popcount over the bits — the
whole-bitmap count, or a byte/bit range.
BITOP — combine bitmaps into a cohort
bitmap-patterns.md.txt · AND / OR / XOR / NOTBITOP writes a new bitmap from a bitwise operation over one or more inputs — a cohort is one
BITOP plus a BITCOUNT. Select an operation; the result row is computed from the two
input rows, bit by bit:
premium and mobile over
offsets 0–11; select an operation and the result is computed bitwise.premium is set at {1, 3, 4, 7, 9}; mobile at {3, 4, 6, 9, 10} — pick AND, OR,
XOR, or NOT to see the result bitmap and its count.SETBIT users:premium 12345 1 SETBIT users:mobile 12345 1 BITOP AND cohort:premium_mobile users:premium users:mobile BITCOUNT cohort:premium_mobile # premium AND mobile BITOP NOT users:not_mobile users:mobile # complement, then BITOP AND cohort:premium_desktop users:premium users:not_mobile # premium AND NOT mobile
Every attribute is a bitmap; every segment is a boolean expression over them. The result bitmap is the same
size as its inputs and can itself feed another BITOP — cohorts compose. BITOP is
O(N) in the length of the longest input string, so the cost is the size of the largest bitmap,
and very large ones are sharded by id range.
A cohort is a boolean expression over attribute bitmaps: BITOP AND/OR/XOR/NOT writes the
result, BITCOUNT sizes it, and the result composes into the next expression.
BITPOS — the first set or unset bit
bitmap-patterns.md.txt · locate an edgeBITPOS key bit returns the offset of the first bit equal to bit (0 or 1), optionally
within a range:
BITPOS users:active 1 # offset of the first set bit → first active id BITPOS users:active 0 # offset of the first unset bit → first free slot BITPOS users:active 1 100 200 # within a byte range
It answers "the first active entity" or "the first free slot" without scanning client-side — useful for allocating the next id in a dense space, or finding where a run of activity begins.
BITPOS locates the first set or unset bit — the first active id, or the first free
slot — in the engine, not in a client loop.
The Bloom-filter alternative — and the contrast
bitmap-patterns.md.txt · exact vs approximateA bitmap can stand in for a Bloom filter: hash an item to k positions with k hashes and set them; membership is
"all k bits set". If any is 0 the item is definitely absent; if all are 1 it is probably present, with false
positives whose rate depends on the bitmap size and k. That is the same accuracy-for-memory trade R7.03 teaches
as a first-class structure — and where a real Bloom filter belongs, the module commands BF.*
size it and choose the hashes for you.
The contrast is the point. Bitmaps as taught here are exact: BITCOUNT over a flag
set is the true count (no estimate), and GETBIT is a definite yes/no for a known offset. You reach
for the probabilistic structures of R7.03 only when the cardinality is so large that even one bit per entity is
too much, and a bounded error rate is acceptable.
BITCOUNT is an exact popcount; BITOP AND/OR/XOR/NOT composes cohorts;
BITPOS finds the first set/unset bit — all over the bits, in the engine.
A standalone core-Valkey example. These are exact answers; R7.03's HyperLogLog and Bloom filters are the approximate counterparts you reach for when exact storage is too expensive.
Bitmaps turn a flag store into an analytics one: BITCOUNT for the size of a set,
BITOP to compose cohorts, BITPOS to find an edge — exactly, and without enumerating
entities. The approximate versions are a deliberate trade (R7.03), not the default.
Notes on ValkeyBITOP destkey op key [key ...] is O(N) in the
length of the longest input string and writes a result the size of that input; BITCOUNT is a
population count with an optional BYTE/BIT range modifier —
valkey.io/commands/bitop.
The approximate counterpart
When exact storage is too expensive, the probabilistic data structures trade a bounded error for fixed memory — HyperLogLog for cardinality, Bloom filters for membership. Bitmap analytics are the exact baseline they depart from.
daily-active patterns
BITOP over a series of daily bitmaps is where the analytics earn their keep: WAU, MAU, and
retention cohorts. The next dive:
daily-active patterns.
References
sources · relatedSources
- Valkey — BITCOUNT — population count over the whole String or a byte/bit range.
- Valkey — BITOP — AND / OR / XOR / NOT across bitmaps into a result bitmap; O(N) in the longest input.
- Valkey — BITPOS — the offset of the first set or unset bit.
- Redis — Bitmaps — the bitmap data-type overview.
Related in this course
- R7.04 · Bitmapsthe module hub
- R7.04.1 · 1-bit flags
SETBIT/GETBIT, the offset is the id - R7.04.3 · daily-active patterns
BITOPover daily bitmaps for windows and cohorts - R7.03 · Probabilistic data structuresthe approximate counterpart to exact bitmap analytics