Redis 位域
Redis位域简介
Redis 位字段允许您设置、递增和获取任意位长度的整数值。 例如,您可以操作从无符号1位整数到有符号63位整数的任何内容。
这些值使用二进制编码的Redis字符串存储。 位字段支持原子读、写和增量操作,使其成为管理计数器和类似数值的良好选择。
基本命令
BITFIELD
原子性地设置、增加和读取一个或多个值。BITFIELD_RO
是BITFIELD
的只读版本。
Example
假设你想为各种自行车维护两个指标:当前价格和随时间变化的拥有者数量。你可以为每辆自行车使用一个32位宽的位域来表示这些计数器。
- 自行车1最初成本为1,000(偏移量0处的计数器),并且从未有过所有者。出售后,它现在被视为二手,价格立即下降以反映其新状况,并且现在有了一个所有者(偏移量1)。经过相当长的时间,这辆自行车成为经典。原所有者以盈利出售,因此价格上涨,所有者数量也增加。最后,您可以查看自行车的当前价格和所有者数量。
> BITFIELD bike:1:stats SET u32 #0 1000
1) (integer) 0
> BITFIELD bike:1:stats INCRBY u32 #0 -50 INCRBY u32 #1 1
1) (integer) 950
2) (integer) 1
> BITFIELD bike:1:stats INCRBY u32 #0 500 INCRBY u32 #1 1
1) (integer) 1450
2) (integer) 2
> BITFIELD bike:1:stats GET u32 #0 GET u32 #1
1) (integer) 1450
2) (integer) 2
Are you tired of using redis-cli? Try Redis Insight - the developer GUI for Redis.
"""
Code samples for Bitfield doc pages:
https://redis.io/docs/latest/develop/data-types/bitfields/
"""
import redis
r = redis.Redis(decode_responses=True)
bf = r.bitfield("bike:1:stats")
res1 = bf.set("u32", "#0", 1000).execute()
print(res1) # >>> [0]
res2 = bf.incrby("u32", "#0", -50).incrby("u32", "#1", 1).execute()
print(res2) # >>> [950, 1]
res3 = bf.incrby("u32", "#0", 500).incrby("u32", "#1", 1).execute()
print(res3) # >>> [1450, 2]
res4 = bf.get("u32", "#0").get("u32", "#1").execute()
print(res4) # >>> [1450, 2]
import assert from 'assert';
import { createClient } from 'redis';
const client = createClient();
await client.connect();
let res1 = await client.bitField("bike:1:stats", [{
operation: 'SET',
encoding: 'u32',
offset: '#0',
value: 1000
}]);
console.log(res1); // >>> [0]
let res2 = await client.bitField('bike:1:stats', [
{
operation: 'INCRBY',
encoding: 'u32',
offset: '#0',
increment: -50
},
{
operation: 'INCRBY',
encoding: 'u32',
offset: '#1',
increment: 1
}
]);
console.log(res2); // >>> [950, 1]
let res3 = await client.bitField('bike:1:stats', [
{
operation: 'INCRBY',
encoding: 'u32',
offset: '#0',
increment: 500
},
{
operation: 'INCRBY',
encoding: 'u32',
offset: '#1',
increment: 1
}
]);
console.log(res3); // >>> [1450, 2]
let res4 = await client.bitField('bike:1:stats', [
{
operation: 'GET',
encoding: 'u32',
offset: '#0'
},
{
operation: 'GET',
encoding: 'u32',
offset: '#1'
}
]);
console.log(res4); // >>> [1450, 2]
import redis.clients.jedis.UnifiedJedis;
public class BitfieldExample {
public void run() {
UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");
List<Long> res1 = jedis.bitfield("bike:1:stats", "SET", "u32", "#0", "1000");
System.out.println(res1); // >>> [0]
List<Long> res2 = jedis.bitfield("bike:1:stats", "INCRBY", "u32", "#0", "-50", "INCRBY", "u32", "#1", "1");
System.out.println(res2); // >>> [950, 1]
List<Long> res3 = jedis.bitfield("bike:1:stats", "INCRBY", "u32", "#0", "500", "INCRBY", "u32", "#1", "1");
System.out.println(res3); // >>> [1450, 2]
List<Long> res4 = jedis.bitfield("bike:1:stats", "GET", "u32", "#0", "GET", "u32", "#1");
System.out.println(res4); // >>> [1450, 2]
// Tests for 'bf' step.
jedis.close();
}
}
package example_commands_test
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
func ExampleClient_bf() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password docs
DB: 0, // use default DB
})
res1, err := rdb.BitField(ctx, "bike:1:stats",
"set", "u32", "#0", "1000",
).Result()
if err != nil {
panic(err)
}
fmt.Println(res1) // >>> [0]
res2, err := rdb.BitField(ctx,
"bike:1:stats",
"incrby", "u32", "#0", "-50",
"incrby", "u32", "#1", "1",
).Result()
if err != nil {
panic(err)
}
fmt.Println(res2) // >>> [950 1]
res3, err := rdb.BitField(ctx,
"bike:1:stats",
"incrby", "u32", "#0", "500",
"incrby", "u32", "#1", "1",
).Result()
if err != nil {
panic(err)
}
fmt.Println(res3) // >>> [1450 2]
res4, err := rdb.BitField(ctx, "bike:1:stats",
"get", "u32", "#0",
"get", "u32", "#1",
).Result()
if err != nil {
panic(err)
}
fmt.Println(res4) // >>> [1450 2]
}
性能
BITFIELD
是 O(n),其中 n 是访问的计数器数量。