From fdaf50a1db4dc6f22d81c993bbe7d06ded05f769 Mon Sep 17 00:00:00 2001 From: Antonio Guilherme Ferreira Viggiano Date: Tue, 28 Jul 2026 11:43:31 +0000 Subject: [PATCH 1/2] Document native Roaring bitmaps --- content/commands/object-encoding.md | 9 +- content/commands/type.md | 2 +- content/develop/data-types/strings/bitmaps.md | 132 +++++++++++++++++- 3 files changed, 135 insertions(+), 8 deletions(-) diff --git a/content/commands/object-encoding.md b/content/commands/object-encoding.md index ac0ed9bb2b..efd56096a3 100644 --- a/content/commands/object-encoding.md +++ b/content/commands/object-encoding.md @@ -98,7 +98,14 @@ Redis objects can be encoded in different ways: - `stream`, encoded as a radix tree of listpacks. -All the specially encoded types are automatically converted to the general type once you perform an operation that makes it impossible for Redis to retain the space saving encoding. +* Native bitmaps are encoded as: + + - `bitmap-roaring`, a compressed Roaring bitmap encoding. See + [Roaring-compressed bitmaps]({{< relref "/develop/data-types/strings/bitmaps#roaring-compressed-bitmaps" >}}). + +Collection types that have both compact and general encodings are automatically +converted to the general encoding once you perform an operation that makes it +impossible for Redis to retain the compact encoding. ## Redis Software and Redis Cloud compatibility diff --git a/content/commands/type.md b/content/commands/type.md index 80fef3727e..2b041514af 100644 --- a/content/commands/type.md +++ b/content/commands/type.md @@ -47,7 +47,7 @@ title: TYPE --- Returns the string representation of the type of the value stored at `key`. The different types that can be returned are: `string`, `list`, `set`, `zset`, -`hash`, `stream`, and `vectorset`. +`hash`, `stream`, `bitmap`, and `vectorset`. ## Required arguments diff --git a/content/develop/data-types/strings/bitmaps.md b/content/develop/data-types/strings/bitmaps.md index fb5f945f7d..16703736d2 100644 --- a/content/develop/data-types/strings/bitmaps.md +++ b/content/develop/data-types/strings/bitmaps.md @@ -21,12 +21,20 @@ weight: 20 {{< command-group group="bitmap" title="Bitmap/bitfield command summary" show_link=true >}} -Bitmaps are not an actual data type, but a set of bit-oriented operations -defined on the String type which is treated like a bit vector. -Since strings are binary safe blobs and their maximum length is 512 MB, -they are suitable to set up to 2^32 different bits. +Redis can store bitmaps in two representations: -You can perform bitwise operations on one or more strings. +* By default, a bitmap is a set of bit-oriented operations defined on a + string, which is treated like a bit vector. +* When enabled, Redis can instead store a bitmap as a distinct, native + `bitmap` type with the `bitmap-roaring` compressed encoding. + +Both representations support the same bitmap commands. With the default +512 MB `proto-max-bulk-len`, they can address up to 2^32 different bits. +Native bitmaps are not strings, so generic string commands don't operate on +them. See [Roaring-compressed bitmaps](#roaring-compressed-bitmaps) before +enabling the native representation. + +You can perform bitwise operations on one or more bitmaps. Some examples of bitmap use cases include: * Efficient set representations for cases where the members of a set correspond to the integers 0-N. @@ -265,6 +273,113 @@ Set a bit in the destination key to 1 if it is set in exactly one of the source # Hex value: 0xa5 = 0b10100101 {{< /clients-example >}} +## Roaring-compressed bitmaps + +A string-backed bitmap allocates bytes through the highest addressed bit. This +is efficient for dense bitmaps, but a small number of set bits spread across a +large range can leave most of the string filled with zeros. + +A native Roaring bitmap stores set-bit positions in compressed containers while +preserving the same logical byte length and bitmap command behavior. This can +reduce memory use for sparse bitmaps, such as membership or event indexes over +a large integer ID space. Long runs of set bits can also compress well. Small +bitmaps and irregular dense bitmaps can use as much or more memory than strings +because compressed containers have their own metadata. Compare +[`MEMORY USAGE`]({{< relref "/commands/memory-usage" >}}) and command latency +with representative data before enabling Roaring bitmaps for a workload. + +### Enable Roaring bitmap creation + +The `bitmap-default-roaring` configuration parameter is `no` by default. Set it +to `yes` in your Redis configuration file, or enable it at runtime with +[`CONFIG SET`]({{< relref "/commands/config-set" >}}): + +{{< clients-example set="bitmap_tutorial" step="roaring" description="Compressed storage: Enable native Roaring creation for sparse bitmaps when you don't need to access their raw bytes with string commands" difficulty="intermediate" buildsUpon="ping" runnable="false" try_it="false" >}} +> CONFIG SET bitmap-default-roaring yes +OK +> SETBIT events:2026-07 1000000 1 +(integer) 0 +> TYPE events:2026-07 +bitmap +> OBJECT ENCODING events:2026-07 +"bitmap-roaring" +> BITCOUNT events:2026-07 +(integer) 1 +> GET events:2026-07 +(error) WRONGTYPE Operation against a key holding the wrong kind of value +{{< /clients-example >}} + +Changing the configuration does not immediately convert existing keys: + +* With `bitmap-default-roaring no`, [`SETBIT`]({{< relref "/commands/setbit" >}}) + and write forms of [`BITFIELD`]({{< relref "/commands/bitfield" >}}) create + string-backed bitmaps. Existing native bitmaps remain native and continue to + accept bitmap commands. +* With `bitmap-default-roaring yes`, those commands create missing keys as + native bitmaps. A write to an existing string converts the complete string + to a native bitmap before applying the write. The conversion preserves its + bits, logical length, expiration, and key metadata. +* Read-only bitmap commands don't convert a string. [`SET`]({{< relref + "/commands/set" >}}) also continues to create a string, regardless of this + setting. +* [`BITOP`]({{< relref "/commands/bitop" >}}) stores a non-empty result as a + native destination when the setting is `yes`. When the setting is `no`, its + destination is native if at least one source is native; an operation with + only string sources produces a string destination. + +There is no command that converts a native bitmap back to a string while +preserving its contents. `SET` can replace a native bitmap with a new string +value, as it can replace any other Redis type. + +### Command and type compatibility + +[`SETBIT`]({{< relref "/commands/setbit" >}}), +[`GETBIT`]({{< relref "/commands/getbit" >}}), +[`BITCOUNT`]({{< relref "/commands/bitcount" >}}), +[`BITPOS`]({{< relref "/commands/bitpos" >}}), +[`BITOP`]({{< relref "/commands/bitop" >}}), +[`BITFIELD`]({{< relref "/commands/bitfield" >}}), and +[`BITFIELD_RO`]({{< relref "/commands/bitfield_ro" >}}) work with both +representations and keep their existing reply and range semantics. Setting a +zero bit beyond the current logical end extends either representation, and +bits between the old and new ends read as zero. + +The representations are intentionally visible to clients: + +* [`TYPE`]({{< relref "/commands/type" >}}) returns `string` for a string-backed + bitmap and `bitmap` for a native one. +* [`OBJECT ENCODING`]({{< relref "/commands/object-encoding" >}}) returns + `bitmap-roaring` for a native bitmap. +* Generic string commands such as [`GET`]({{< relref "/commands/get" >}}), + [`STRLEN`]({{< relref "/commands/strlen" >}}), + [`GETRANGE`]({{< relref "/commands/getrange" >}}), and + [`APPEND`]({{< relref "/commands/append" >}}) return a wrong-type error for a + native bitmap. Applications that read or modify bitmap bytes with string + commands should keep using the default string representation. + +Both representations limit accepted bit offsets according to +`proto-max-bulk-len`. An existing bitmap can have a longer logical length if it +was created or loaded while that limit was higher. [`BITOP`]({{< relref +"/commands/bitop" >}}) operates on the complete logical length of such a +source. In particular, `BITOP NOT` can allocate a dense result of that length, +so account for its memory cost before lowering the limit. + +### Persistence and replication + +RDB snapshots, [`DUMP`]({{< relref "/commands/dump" >}}) and +[`RESTORE`]({{< relref "/commands/restore" >}}), AOF rewrites, and replication +preserve the native bitmap type. When a write creates or converts a native +bitmap because `bitmap-default-roaring` is `yes`, Redis propagates an explicit +serialized value so replicas produce the same type even if their local setting +differs. As a result, the first write that converts a large string can add more +data to the replication stream or incremental AOF than the write command alone. + +{{< warning >}} +Before enabling Roaring bitmap creation on a primary, upgrade all replicas and +any Redis server that will load its RDB, DUMP payloads, or AOF. Older versions +don't understand the native bitmap persistence format. +{{< /warning >}} + ## Split bitmaps into multiple keys Bitmaps are trivial to split into multiple keys, for example for @@ -277,7 +392,12 @@ the Nth bit to address inside the key with `bit-number MOD M`. ## Performance [`SETBIT`]({{< relref "/commands/setbit" >}}) and [`GETBIT`]({{< relref "/commands/getbit" >}}) are O(1). -[`BITOP`]({{< relref "/commands/bitop" >}}) is O(n), where _n_ is the length of the longest string in the comparison. +[`BITOP`]({{< relref "/commands/bitop" >}}) is O(n), where _n_ is the logical +length of the longest source bitmap. +For Roaring bitmaps, actual CPU and memory costs also depend on the distribution +of set bits and the resulting compressed containers. In particular, `BITOP NOT` +can turn a sparse bitmap into a dense result. Benchmark representative data and +operations when choosing a representation. ## Learn more From c02b80f037b7d6a421b7ec7aedc23fe85b1b104b Mon Sep 17 00:00:00 2001 From: Antonio Guilherme Ferreira Viggiano Date: Tue, 28 Jul 2026 14:57:35 +0000 Subject: [PATCH 2/2] Keep Roaring details in bitmap guide --- content/commands/object-encoding.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/content/commands/object-encoding.md b/content/commands/object-encoding.md index efd56096a3..ac0ed9bb2b 100644 --- a/content/commands/object-encoding.md +++ b/content/commands/object-encoding.md @@ -98,14 +98,7 @@ Redis objects can be encoded in different ways: - `stream`, encoded as a radix tree of listpacks. -* Native bitmaps are encoded as: - - - `bitmap-roaring`, a compressed Roaring bitmap encoding. See - [Roaring-compressed bitmaps]({{< relref "/develop/data-types/strings/bitmaps#roaring-compressed-bitmaps" >}}). - -Collection types that have both compact and general encodings are automatically -converted to the general encoding once you perform an operation that makes it -impossible for Redis to retain the compact encoding. +All the specially encoded types are automatically converted to the general type once you perform an operation that makes it impossible for Redis to retain the space saving encoding. ## Redis Software and Redis Cloud compatibility