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本身存的也都是热点缓存。如果你查询的条件是不经常会执行的,那么说实话,你这么操作的意义也不大。

发布了62 篇原创文章 · 获赞 80 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/weixin_30342639/article/details/99951699