当前位置: 首页 > 工具软件 > RedisJSON > 使用案例 >

RedisJson和RedisSearch探究(一)

艾宁
2023-12-01

目录

1. RedisJson

1.1.  简介

1.2.  基本使用

1.2.1 数据添加

1.2.2 数据获取

1.2.3 字符串数据增加

1.2.4 布尔类型的值切换

1.2.5 数字增加

1.2.6 数组添加

1.2.6 其他命令

1.3.  Java操作RedisJson

1.3.1 配置环境:

 1.3.2 定义pojo

1.3.3 写个controller


RedisJson突然大火,号称性能吊打ES和mongo。趁机小小研究了一下。

RedisJson官网: RedisJSON - Use Redis as a JSON Store | Redis

1. RedisJson

1.1.  简介

RedisJson和RedisSearch都是Redis的一个模块,它提供了Json格式的存储结构。redis本身也可以用string或者hash等类型存储json,但是RedisJson提供了不一样的体验。它可以更方便的处理json,并且也有更高的效率。

可以通过docker,非常方便的安装RedisJson(默认最新版本):

docker pull redislabs/rejson

然后运行docker run就可以了。

docker run -d -p 6379:6379 --name redis-rejson redislabs/rejson:latest

可以通过module list查看当前的module:

[root@bogon friso]# docker exec -it f4fe2ec23644 sh
# redis-cli
127.0.0.1:6379> module list
1) 1) "name"
   2) "ReJSON"
   3) "ver"
   4) (integer) 20004

RedisJson存储Json的时候,会按照树的结构存储,这也很好理解,因为json本身就是一棵树。而对于存储的各个节点的添加和查找,遵循了JsonPath规则,可以在这个链接进行查阅:

JSONPath - XPath for JSON

1.2.  基本使用

1.2.1 数据添加

命令: JSON.SET <key> <path> <json> [NX | XX]

 实例:

JSON.SET myDoc $ '{"user":{"name":"John Smith","tag":"foo,bar","hp":1000, "dmg":150}}'

需要说明的是,此处$指的是在哪个路径下添加Json。上述例子说明是在$下添加的,如果想在user路径下再添加json,可以这么写。

JSON.SET myDoc $.user.job '{"type":"teacher","place":"beijing"}'

效果如下:

"{\"user\":{\"name\":\"John Smith\",\"tag\":\"foo,bar\",\"hp\":1000,\"dmg\":150,\"job\":{\"type\":\"teacher\",\"place\":\"beijing\"}}}"

当然,也可以通过这个命令,进行数据更新。

JSON.SET myDoc $.user.job '{"type":"doctor","place":"tianjin"}'

以下实例,如无特别说明,都会基于myDoc这个可以进行操作。

1.2.2 数据获取

命令:

JSON.GET <key>
         [INDENT indentation-string]
         [NEWLINE line-break-string]
         [SPACE space-string]
         [path ...]

实例:

127.0.0.1:6379> JSON.GET myDoc
"{\"user\":{\"name\":\"John Smith\",\"tag\":\"foo,bar\",\"hp\":1000,\"dmg\":150,\"job\":{\"type\":\"teacher\",\"place\":\"beijing\"}}}"

 参数说明:

INDENT:指的是嵌套级别的缩进字符串

NEWLINE :设置在每行末尾打印的字符串

SPACE:设置放在键和值之间的字符串 

INDENT实例:

127.0.0.1:6379> JSON.GET myDoc indent "\t"
"{\t\"user\":{\t\t\"name\":\"John Smith\",\t\t\"tag\":\"foo,bar\",\t\t\"hp\":1000,\t\t\"dmg\":150,\t\t\"job\":{\t\t\t\"type\":\"doctor\",\t\t\t\"place\":\"tianjin\"\t\t}\t}}"

可以对比来看,和没有设置indent,每个缩进层次加了不同的“\t”。比如user所在层,加了一个“\t”,name所在层加了两个"\t",等等。格式化看一下:

{
    \t"user": {
        \t\t"name": "John Smith",
        \t\t"tag": "foo,bar",
        \t\t"hp": 1000,
        \t\t"dmg": 150,
        \t\t"job": {
            \t\t\t"type": "doctor",
            \t\t\t"place": "tianjin"
        \t\t}
    \t}
}

NEWLINE 实例:

127.0.0.1:6379> JSON.GET myDoc newline "\n"
"{\n\"user\":{\n\"name\":\"John Smith\",\n\"tag\":\"foo,bar\",\n\"hp\":1000,\n\"dmg\":150,\n\"job\":{\n\"type\":\"doctor\",\n\"place\":\"tianjin\"\n}\n}\n}"

这么看的话,可能不太明白,格式化一下就很清晰了:

{\n
    "user": {\n
        "name": "John Smith",\n
        "tag": "foo,bar",\n
        "hp": 1000,\n
        "dmg": 150,\n
        "job": {\n
            "type": "doctor",\n
            "place": "tianjin"\n
        }\n
    }\n
}

直观上可以这么理解,INDENT指的是在每行头加字符,NEWLINE 是在行尾加字符。

SPACE实例:

127.0.0.1:6379> JSON.GET myDoc space "\n"
"{\"user\":\n{\"name\":\n\"John Smith\",\"tag\":\n\"foo,bar\",\"hp\":\n1000,\"dmg\":\n150,\"job\":\n{\"type\":\n\"doctor\",\"place\":\n\"tianjin\"}}}"

就是在键与值之间加的字符。同样格式化看一下:

{
    "user": \n{
        "name": \n"John Smith",
        "tag": \n"foo,bar",
        "hp": \n1000,
        "dmg": \n150,
        "job": \n{
            "type": \n"doctor",
            "place": \n"tianjin"
        }
    }
}

这三种字符的添加,看起来如丝般顺滑,不过这个是在什么场景下会用到呢?

1.2.3 字符串数据增加

命令:

JSON.STRAPPEND <key> [path] <json-string>

实例:

JSON.STRAPPEND myDoc $.user.name '" TOM"'

查看结果:

127.0.0.1:6379> JSON.GET myDoc
"{\"user\":{\"name\":\"John Smith TOM\",\"tag\":\"foo,bar\",\"hp\":1000,\"dmg\":150,\"job\":{\"type\":\"doctor\",\"place\":\"tianjin\"}}}"

可以看到,在路径$.user.name的值多了个“ TOM”。官网给的例子是基于路径".."的,可以将key中名字相同的键的值都更改了,可以在官网查看。

1.2.4 布尔类型的值切换

命令:

JSON.TOGGLE <key> <path>

实例:

先添加一个bool类型:JSON.SET myDoc $.user.male 'true'

toggle之:JSON.TOGGLE myDoc $.user.male

查看结果:

添加bool类型后的结果:

127.0.0.1:6379> JSON.GET myDoc
"{\"user\":{\"name\":\"John Smith TOM\",\"tag\":\"foo,bar\",\"hp\":1000,\"dmg\":150,\"job\":{\"type\":\"doctor\",\"place\":\"tianjin\"},\"male\":true}}"

toggle后的结果:

127.0.0.1:6379> JSON.GET myDoc
"{\"user\":{\"name\":\"John Smith TOM\",\"tag\":\"foo,bar\",\"hp\":1000,\"dmg\":150,\"job\":{\"type\":\"doctor\",\"place\":\"tianjin\"},\"male\":false}}"

1.2.5 数字增加

命令:

JSON.NUMINCRBY <key> <path> <number>

实例:

JSON.NUMINCRBY myDoc $.user.hp 235

查看结果:

127.0.0.1:6379> JSON.GET myDoc
"{\"user\":{\"name\":\"John Smith TOM\",\"tag\":\"foo,bar\",\"hp\":1235,\"dmg\":150,\"job\":{\"type\":\"doctor\",\"place\":\"tianjin\"},\"male\":false}}"

1.2.6 数组添加

命令:

JSON.ARRAPPEND <key> <path> <json> [json ...]

实例:

先创建有json数组的key值:

127.0.0.1:6379> json.get doc6
"{\"a\":[1],\"nested\":{\"a\":[1,2]},\"nested2\":{\"a\":42}}"

增加数组元素:

127.0.0.1:6379> JSON.ARRAPPEND doc6 $..a 3 4

查看结果:

127.0.0.1:6379> json.get doc6
"{\"a\":[1,3,4],\"nested\":{\"a\":[1,2,3,4]},\"nested2\":{\"a\":42}}"

可以发现,所有键值为a的数组,都多了3,4 。

1.2.6 其他命令

命令太多,我没有每个都试一遍,具体可以参见官网“commands”章节。

1.3.  Java操作RedisJson

目前有好几个库,都可以支持RedisJson的操作,我选择的是Jedis。具体client支持,可以直接看git:https://github.com/RediSearch/RediSearch

1.3.1 配置环境:

使用springboot搭建。在dependency中引入jedis就可以了。

配置pom文件,添加

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.0.1</version>
</dependency>

配置application.yml

server:
    port: 8081

spring:
    application:
        name: redisStream
        version: v1.0
    jackson:
        date-format: yyyy-MM-dd HH:mm:ss
        time-zone: GMT+8

    redis:
        database: 1
        host: 192.168.46.75
        port: 6379
        jedis:
            pool:
                max-active: 20

配置jedis:

package com.redisStream.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.*;
import redis.clients.jedis.providers.PooledConnectionProvider;

/**
 * @author qzh
 * 创建时间:2022/1/27 10:00
 */
@Configuration
public class UnifiedJedisPoolAutoConfig {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port:6379}")
    private Integer port;

     @Bean
    public UnifiedJedis unifiedJedis() {
        HostAndPort config = new HostAndPort(host, 6379);
        PooledConnectionProvider provider = new PooledConnectionProvider(config);
        UnifiedJedis unifiedJedis = new UnifiedJedis(provider);
        return unifiedJedis;
    }
}

 1.3.2 定义pojo

package com.redisStream.pojo;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class NewKeyInfo {

    private String key;
    private String value;

}

1.3.3 写个controller

package com.redisStream.controller;

import com.alibaba.fastjson.JSON;
import com.redisStream.pojo.NewKeyInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import redis.clients.jedis.CommandArguments;
import redis.clients.jedis.Protocol;
import redis.clients.jedis.UnifiedJedis;
import redis.clients.jedis.commands.ProtocolCommand;
import redis.clients.jedis.json.JsonSetParams;
import redis.clients.jedis.search.Document;
import redis.clients.jedis.search.Query;
import redis.clients.jedis.search.SearchResult;

import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

@RestController
public class ChineseController {

    private static final Logger log = LoggerFactory.getLogger(ChineseController.class);


    @Autowired
    private UnifiedJedis jedis;

    private String key_prefix = "ch:";

    @PostMapping("/add")
    public String add(@RequestBody NewKeyInfo newKeyInfo) throws Exception{

        log.info("start to set value");
        redisJsonUtils.setJson(key_prefix + newKeyInfo.getKey(), JSON.toJSONString(newKeyInfo));
        log.info("start to read value");
        return JSON.toJSONString(jedis.jsonGet(key_prefix + newKeyInfo.getCountryName()));

    }
}

这个实例只显示了简单的set和get操作,在set成功后,会通过get命令将结果返回。

下次讨论RedisSearch。

 类似资料: