Redis中选择查询的一种实现方案

        在使用关系型数据库时,我们可以使用带where的SQL来进行选择查询。比如一个需求是查询大于25岁的人:

SELECT
    id,
    name,
    sex,
    age,
    address 
FROM
    Person 
WHERE
    age > 25

        但是在Redis中并不能使用SQL,也就不能进行选择查询。最普通的办法是将所有的数据都查出来,再在Java中进行过滤,如下所示:

@Override
public void test1() {
    Map<String, Person> map = new HashMap<>();

    String uuid1 = UUID.randomUUID().toString();
    Person p1 = new Person(uuid1, "z1", "m", 24, "123");
    map.put(uuid1, p1);
    String uuid2 = UUID.randomUUID().toString();
    Person p2 = new Person(uuid2, "q2", "m", 30, "456");
    map.put(uuid2, p2);
    String uuid3 = UUID.randomUUID().toString();
    Person p3 = new Person(uuid3, "s3", "f", 26, "789");
    map.put(uuid3, p3);
    String uuid4 = UUID.randomUUID().toString();
    Person p4 = new Person(uuid4, "l4", "m", 19, "101");
    map.put(uuid4, p4);
    String uuid5 = UUID.randomUUID().toString();
    Person p5 = new Person(uuid5, "z5", "f", 35, "112");
    map.put(uuid5, p5);

    redisTemplate.opsForHash().putAll("PERSON", map);
    Set<Person> set = new HashSet<>();
    Map<Object, Object> entries = redisTemplate.opsForHash().entries("PERSON");
    for (Map.Entry<Object, Object> entry : entries.entrySet()) {
        Person person = (Person) entry.getValue();
        if (person != null && person.getAge() != null && person.getAge() > 25) {
            set.add(person);
        }
    }

    for (Person p : set) {
        System.out.println(p);
    }
}

        如上所示,这里模拟了5条Person数据,并使用哈希结构存在Redis中,key是uuid,value是具体的Person。最后需要将所有哈希的值都取出来再遍历进行筛选。这里只是模拟了5条数据,但如果是100万、1000万乃至更多条数据呢?如果将这么大数据量的数据全都取出来,内存也会受不了。所以说这种方案是不可取的。

        这里提供一种实现方案的思路,也很简单,就是在插入数据的时候将符合查询条件的数据也一并插入进另一个set集合中。放在这里的需求就是不仅需要将所有数据都插入到map中,还要将大于25岁的数据的uuid放在一个新的set中。其实也就是以空间换时间的思路,插入一些冗余数据,以此来提高查询效率。如下所示:

@Override
public void test2() {
    final String AGE_AFTER_25 = "AGE_AFTER_25";
    final String MAN = "MAN";
    Map<String, Person> map = new HashMap<>();

    String uuid1 = UUID.randomUUID().toString();
    Person p1 = new Person(uuid1, "z1", "m", 24, "123");
    map.put(uuid1, p1);
    redisTemplate.opsForSet().add(MAN, uuid1);

    String uuid2 = UUID.randomUUID().toString();
    Person p2 = new Person(uuid2, "q2", "m", 30, "456");
    map.put(uuid2, p2);
    redisTemplate.opsForSet().add(AGE_AFTER_25, uuid2);
    redisTemplate.opsForSet().add(MAN, uuid2);

    String uuid3 = UUID.randomUUID().toString();
    Person p3 = new Person(uuid3, "s3", "f", 26, "789");
    map.put(uuid3, p3);
    redisTemplate.opsForSet().add(AGE_AFTER_25, uuid3);

    String uuid4 = UUID.randomUUID().toString();
    Person p4 = new Person(uuid4, "l4", "m", 19, "101");
    map.put(uuid4, p4);
    redisTemplate.opsForSet().add(MAN, uuid4);

    String uuid5 = UUID.randomUUID().toString();
    Person p5 = new Person(uuid5, "z5", "f", 35, "112");
    map.put(uuid5, p5);
    redisTemplate.opsForSet().add(AGE_AFTER_25, uuid5);

    redisTemplate.opsForHash().putAll("PERSON", map);

    System.out.println("年龄大于25岁的人:");
    Set<Object> members = redisTemplate.opsForSet().members(AGE_AFTER_25);
    List<Object> person1 = redisTemplate.opsForHash().multiGet("PERSON", members);
    for (Object p : person1) {
        System.out.println(p);
    }

    System.out.println("年龄大于25岁的男人:");
    Set<Object> intersect = redisTemplate.opsForSet().intersect(AGE_AFTER_25, MAN);
    List<Object> person2 = redisTemplate.opsForHash().multiGet("PERSON", intersect);
    for (Object p : person2) {
        System.out.println(p);
    }
}

        如上所示,在5条数据执行map.put方法后,会将符合条件的数据插入到Redis中。也就是将大于25岁的uuid放入到AGE_AFTER_25这个set中,将是男人的uuid放入到MAN这个set中。最后通过在map中查询key是AGE_AFTER_25的数据返回即可。

        最后演示了一个组合条件查询的情况,即查找年龄大于25岁的男人这个需求。其实也就是将AGE_AFTER_25和MAN这两个集合取交集的结果。Redis中的set也支持交集、差集、并集这些操作,我们可以善加利用。这样的话就不需要将所有数据都取出来,而改为按需查询来实现。

        当然这里的范围查询的条件一定是热点查询,Redis本身存的也都是热点缓存。如果你查询的条件是不经常会执行的,那么说实话,你这么操作的意义也不大。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值