0
点赞
收藏
分享

微信扫一扫

Redis SCAN:实现key的模糊匹配的科学方法

sin信仰 2023-09-15 阅读 33

目录
scan基本介绍
shell使用scan
最基本的scan
带匹配模式和count的scan
java中使用hscan
scan基本介绍
在使用redis的时候,我们经常涉及到这样的需求:模糊搜索key,即找出满足特定匹配模式的所有key。但是,如果使用像keys和hkyes这样的方法的话,当key的数量特别多时,效率会很慢,而且对线上的redis查询影响较大,非常不推荐这样的做法。
比较好的方法是scan这样的方法:
scan:对所有数据类型的key生效;
sscan:针对Set数据类型的key;
hscan:针对Hash的key;
zscan:针对有序Set的key。
scan可以当成一种带有cursor(游标、下标)的迭代器,即每次scan之后,都会返回一个cursor,下次的scan基于上次扫描结束的位置继续扫描。
shell使用scan
scan返回的是key
最基本的scan
redis 127.0.0.1:6379> scan 0
1) "17"
2)  1) "key:12"
    2) "key:8"
    3) "key:4"
    4) "key:14"
    5) "key:16"
    6) "key:17"
    7) "key:15"
    8) "key:10"
    9) "key:3"
   10) "key:7"
   11) "key:1"
redis 127.0.0.1:6379> scan 17
1) "0"
2) 1) "key:5"
   2) "key:18"
   3) "key:0"
   4) "key:2"
   5) "key:19"
   6) "key:13"
   7) "key:6"
   8) "key:9"
   9) "key:11"

带匹配模式和count的scan
通过设置MATCH,来设计特定的匹配模式,基于glob-style pattern
通过设置COUNT,规定每次scan的数量,默认为10
redis 127.0.0.1:6379> scan 0 MATCH *11*
1) "288"
2) 1) "key:911"
redis 127.0.0.1:6379> scan 288 MATCH *11*
1) "224"
2) (empty list or set)
redis 127.0.0.1:6379> scan 224 MATCH *11*
1) "80"
2) (empty list or set)
redis 127.0.0.1:6379> scan 80 MATCH *11*
1) "176"
2) (empty list or set)
redis 127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000
1) "0"
2)  1) "key:611"
    2) "key:711"
    3) "key:118"
    4) "key:117"
    5) "key:311"
    6) "key:112"
    7) "key:111"
    8) "key:110"
    9) "key:113"
   10) "key:211"
   11) "key:411"
   12) "key:115"
   13) "key:116"
   14) "key:114"
   15) "key:119"
   16) "key:811"
   17) "key:511"
   18) "key:11"
redis 127.0.0.1:6379>

java中使用hscan
以hscan为例,其他的scan方法基本一致。
import java.io.IOException;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;

public class ScanDemo {

    public static void main(String[] args) throws IOException {
        ScanDemo scanDemo = new ScanDemo();
        scanDemo.hScan();

    }

    /**
     * redis的hashmap数据结构的hscan功能
     * @throws IOException
     */
    public static void hScan() throws IOException {
        // 添加redis集群的节点
        Set<HostAndPort> hosts = new HashSet<HostAndPort>();
        hosts.add(new HostAndPort("192.1.6.147", 22420));

        // 创建redis客户端连接
        JedisCluster client = new JedisCluster(hosts);
        // 要进行scan的数据的key
        String key = "hash-test";
        // hscan配置的实例
        ScanParams params = new ScanParams();
        // 匹配模式,只匹配以test开头的field
        params.match("test*");
        // 一次扫描100条数据
        params.count(100);

        // 第一次cursor设置为0,
        String cursor = "0";
        ScanResult<Entry<byte[], byte[]>> scans = client.hscan(key.getBytes(), cursor.getBytes());
        for (Entry<byte[], byte[]> entry: scans.getResult()) {
            System.out.println(new String(entry.getKey()));
            System.out.println(new String(entry.getValue()));
        }
        cursor = scans.getStringCursor();

        // 当cursor为0时,即结束一轮的扫描
        while (!cursor.equals("0")) {
            scans = client.hscan(key.getBytes(), cursor.getBytes());
            for (Entry<byte[], byte[]> entry: scans.getResult()) {
                System.out.println(new String(entry.getKey()));
                System.out.println(new String(entry.getValue()));
            }
            cursor = scans.getStringCursor();
        }

        client.close();
    }

    /**
     * 单节点的redis连接
     * @param args
     */
    public static void redisLocal(String[] args) {
        //连接本地的 Redis 服务
        Jedis client = new Jedis("localhost");
        System.out.println("连接成功");
        //查看服务是否运行
        System.out.println("服务正在运行: "+ client.ping());

        client.close();
    }

}

Maven依赖
<dependency>
      <groupId>redis.clients</groupId>
       <artifactId>jedis</artifactId>
       <version>2.9.0</version>
 </dependency>

举报

相关推荐

0 条评论