# Probabilistic data types

```json metadata
{
  "title": "Probabilistic data types",
  "description": "Learn how to use HyperLogLog approximate cardinality with redis-rs.",
  "categories": ["docs","develop","stack","oss","rs","rc","oss","kubernetes","clients"],
  "tableOfContents": {"sections":[{"id":"set-cardinality","title":"Set cardinality"},{"id":"more-information","title":"More information"}]}

,
  "codeExamples": [{"codetabsId":"home_prob_dts-stephyperloglog","description":"Set cardinality: Estimate distinct item count using HyperLogLog with minimal memory usage","difficulty":"beginner","id":"hyperloglog","languages":[{"clientId":"redis-rs","clientName":"redis-rs","id":"Rust-Sync","langId":"rust","panelId":"panel_Rust-Sync_home_prob_dts-stephyperloglog"},{"clientId":"redis-rs","clientName":"redis-rs","id":"Rust-Async","langId":"rust","panelId":"panel_Rust-Async_home_prob_dts-stephyperloglog"}]}]
}
```## Code Examples Legend

The code examples below show how to perform the same operations in different programming languages and client libraries:

- **Redis CLI**: Command-line interface for Redis
- **C# (Synchronous)**: StackExchange.Redis synchronous client
- **C# (Asynchronous)**: StackExchange.Redis asynchronous client
- **Go**: go-redis client
- **Java (Synchronous - Jedis)**: Jedis synchronous client
- **Java (Asynchronous - Lettuce)**: Lettuce asynchronous client
- **Java (Reactive - Lettuce)**: Lettuce reactive/streaming client
- **JavaScript (Node.js)**: node-redis client
- **PHP**: Predis client
- **Python**: redis-py client
- **Rust (Synchronous)**: redis-rs synchronous client
- **Rust (Asynchronous)**: redis-rs asynchronous client

Each code example demonstrates the same basic operation across different languages. The specific syntax and patterns vary based on the language and client library, but the underlying Redis commands and behavior remain consistent.

---


Redis supports several
[probabilistic data types](https://redis.io/docs/latest/develop/data-types/probabilistic)
that let you calculate values approximately rather than exactly.
The `redis-rs` high-level command traits include support for
[HyperLogLog](https://redis.io/docs/latest/develop/data-types/probabilistic/hyperloglogs)
cardinality estimation.


This page covers HyperLogLog because `redis-rs` provides high-level
`pfadd`, `pfcount`, and `pfmerge` methods. Other probabilistic data types,
such as Bloom filters, Count-min sketch, t-digest, and Top-K, can still be
called with low-level Redis commands, but they don't currently have dedicated
high-level `redis-rs` methods.


## Set cardinality

A HyperLogLog object calculates the approximate cardinality of a set. As you add
items, the HyperLogLog tracks the number of distinct set members, but it doesn't
let you retrieve those members or test whether a specific item was added.

You can also merge two or more HyperLogLogs to find the approximate cardinality
of the [union](https://en.wikipedia.org/wiki/Union_(set_theory)) of the sets
they represent.

Set cardinality: Estimate distinct item count using HyperLogLog with minimal memory usage

**Difficulty:** Beginner

**Available in:** C#, Go, Java (Synchronous - Jedis), PHP, Python, Rust (Asynchronous), Rust (Synchronous)

##### C#

```csharp
        bool res10 = db.HyperLogLogAdd(
            "group:1",
            ["andy", "cameron", "david"]
        );
        Console.WriteLine(res10); // >>> true

        long res11 = db.HyperLogLogLength("group:1");
        Console.WriteLine(res11); // >>> 3

        bool res12 = db.HyperLogLogAdd(
            "group:2",
            ["kaitlyn", "michelle", "paolo", "rachel"]
        );
        Console.WriteLine(res12); // >>> true

        long res13 = db.HyperLogLogLength("group:2");
        Console.WriteLine(res13); // >>> 4

        db.HyperLogLogMerge(
            "both_groups",
            "group:1", "group:2"
        );

        long res14 = db.HyperLogLogLength("both_groups");
        Console.WriteLine(res14); // >>> 7
```

##### Go

```go
	res10, err := rdb.PFAdd(
		ctx,
		"group:1",
		"andy", "cameron", "david",
	).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res10) // >>> 1

	res11, err := rdb.PFCount(ctx, "group:1").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res11) // >>> 3

	res12, err := rdb.PFAdd(ctx,
		"group:2",
		"kaitlyn", "michelle", "paolo", "rachel",
	).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res12) // >>> 1

	res13, err := rdb.PFCount(ctx, "group:2").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res13) // >>> 4

	res14, err := rdb.PFMerge(
		ctx,
		"both_groups",
		"group:1", "group:2",
	).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res14) // >>> OK

	res15, err := rdb.PFCount(ctx, "both_groups").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res15) // >>> 7
```

##### Java (Synchronous - Jedis)

```java
        long res10 = jedis.pfadd("group:1", "andy", "cameron", "david");
        System.out.println(res10);  // >>> 1

        long res11 = jedis.pfcount("group:1");
        System.out.println(res11);  // >>> 3

        long res12 = jedis.pfadd(
            "group:2",
            "kaitlyn", "michelle", "paolo", "rachel"
        );
        System.out.println(res12);  // >>> 1

        long res13 = jedis.pfcount("group:2");
        System.out.println(res13);  // >>> 4

        String res14 = jedis.pfmerge("both_groups", "group:1", "group:2");
        System.out.println(res14);  // >>> OK

        long res15 = jedis.pfcount("both_groups");
        System.out.println(res15);  // >>> 7
```

##### PHP

```php
$r->del('group:1', 'group:2', 'both_groups');

$r->pfadd('group:1', ['andy', 'cameron', 'david']);
$group1 = $r->pfcount('group:1');
echo $group1, PHP_EOL;
// >>> 3

$r->pfadd('group:2', ['kaitlyn', 'michelle', 'paolo', 'rachel']);
$group2 = $r->pfcount('group:2');
echo $group2, PHP_EOL;
// >>> 4

$r->pfmerge('both_groups', 'group:1', 'group:2');
$bothGroups = $r->pfcount('both_groups');
echo $bothGroups, PHP_EOL;
// >>> 7
```

##### Python

```python
res10 = r.pfadd("group:1", "andy", "cameron", "david")
print(res10)  # >>> 1

res11 = r.pfcount("group:1")
print(res11)  # >>> 3

res12 = r.pfadd("group:2", "kaitlyn", "michelle", "paolo", "rachel")
print(res12)  # >>> 1

res13 = r.pfcount("group:2")
print(res13)  # >>> 4

res14 = r.pfmerge("both_groups", "group:1", "group:2")
print(res14)  # >>> True

res15 = r.pfcount("both_groups")
print(res15)  # >>> 7
```

##### Rust (Asynchronous)

```rust
        let group1_added: bool = r
            .pfadd("group:1", &["andy", "cameron", "david"])
            .await
            .expect("Failed to add items to group:1");
        println!("{group1_added}"); // >>> true

        let group1: usize = r.pfcount("group:1").await.expect("Failed to count group:1");
        println!("{group1}"); // >>> 3

        let group2_added: bool = r
            .pfadd("group:2", &["kaitlyn", "michelle", "paolo", "rachel"])
            .await
            .expect("Failed to add items to group:2");
        println!("{group2_added}"); // >>> true

        let group2: usize = r.pfcount("group:2").await.expect("Failed to count group:2");
        println!("{group2}"); // >>> 4

        let _: () = r
            .pfmerge("both_groups", &["group:1", "group:2"])
            .await
            .expect("Failed to merge HyperLogLogs");
        println!("OK"); // >>> OK

        let both_groups: usize = r
            .pfcount("both_groups")
            .await
            .expect("Failed to count both_groups");
        println!("{both_groups}"); // >>> 7

```

##### Rust (Synchronous)

```rust
        let group1_added: bool = r
            .pfadd("group:1", &["andy", "cameron", "david"])
            .expect("Failed to add items to group:1");
        println!("{group1_added}"); // >>> true

        let group1: usize = r.pfcount("group:1").expect("Failed to count group:1");
        println!("{group1}"); // >>> 3

        let group2_added: bool = r
            .pfadd("group:2", &["kaitlyn", "michelle", "paolo", "rachel"])
            .expect("Failed to add items to group:2");
        println!("{group2_added}"); // >>> true

        let group2: usize = r.pfcount("group:2").expect("Failed to count group:2");
        println!("{group2}"); // >>> 4

        let _: () = r
            .pfmerge("both_groups", &["group:1", "group:2"])
            .expect("Failed to merge HyperLogLogs");
        println!("OK"); // >>> OK

        let both_groups: usize = r
            .pfcount("both_groups")
            .expect("Failed to count both_groups");
        println!("{both_groups}"); // >>> 7

```



The main benefit that HyperLogLogs offer is their very low memory usage. They
can count up to 2^64 items with less than 1% standard error using a maximum
12KB of memory.

## More information

See the following pages to learn more:

- [HyperLogLog](https://redis.io/docs/latest/develop/data-types/probabilistic/hyperloglogs)
- [`redis-rs` command trait](https://docs.rs/redis/latest/redis/trait.Commands.html)
- [`redis-rs` async command trait](https://docs.rs/redis/latest/redis/trait.AsyncCommands.html)

