学习使用 Jedis 在 JSON 文档中存储、读取和搜索数据
上次更新 2024 年 4 月 26 日
目标
Redis 可以管理 JSON 文档,除了索引 Redis 哈希表之外,JSON 文档还可以被索引和搜索。本文档提供了一个使用 Jedis 存储、索引和搜索会话数据的完整示例。
解决方案
在本文件中详细介绍的示例中,我们将继续以以下格式存储会话数据
[
{
"lastAccessedTime":1713903362,
"creationTime":1713903362,
"location":"34.638,31.79",
"visited":[
"www.redis.io",
"www.wikipedia.com",
"www.mortensi.com"
],
"cart":[
{
"quantity":1,
"price":1990.99,
"id":"hp-2341"
},
{
"quantity":2,
"price":19.99,
"id":"case-9993"
}
]
}
]
我们还将探讨如何创建索引来索引会话的不同部分。让我们开始并连接到 Redis,如下所示
HostAndPort node = HostAndPort.from("localhost:6379");
JedisClientConfig clientConfig = DefaultJedisClientConfig.builder()
.resp3()
.build();
UnifiedJedis client = new UnifiedJedis(node, clientConfig);
学习如何使用 Jedis 客户端库在使用 Maven 构建的 Java 项目中连接到 Redis
我们正在创建一个索引;让我们删除最终的索引和所有相关文档。
client.ftDropIndexDD("session_idx");
如果你想保留数据并删除索引,请使用命令
ftDropIndex
现在,我们可以通过选择需要索引的字段来定义索引。
Schema schema = new Schema()
.addGeoField("$.location").as("location")
.addTagField("$.cart[*].id").as("item_id")
.addNumericField("$.cart[*].price").as("price")
.addTagField("$.visited[*]").as("visited")
.addNumericField("$.lastAccessedTime").as("updated")
.addNumericField("$.creationTime").as("created");
// Defining the index, it could be HASH too
IndexDefinition def = new IndexDefinition(Type.JSON).setPrefixes(new String[] {"session:"});
// Creating the index
client.ftCreate("session_idx", IndexOptions.defaultOptions().setDefinition(def), schema);
现在,让我们添加一些元数据,如会话创建和更新时间戳,以及用户的位置,以 (经度,纬度) 的形式表示。了解有关 Redis 中索引的更多信息。
JSONObject jsonObject = new JSONObject();
jsonObject.put("lastAccessedTime", System.currentTimeMillis() / 1000L);
jsonObject.put("creationTime", System.currentTimeMillis() / 1000L);
jsonObject.put("location", "34.638,31.79");
client.jsonSet("session:1", jsonObject);
我们还可以存储已访问 URL 的数组
client.jsonSet("session:1", new Path2("visited"), new ArrayList<>());
List<String> visited = new ArrayList<String>();
visited.add("www.redis.io");
visited.add("www.wikipedia.com");
visited.add("www.mortensi.com");
client.jsonSetWithEscape("session:1", new Path2("visited"), visited);
现在,我们为该用户存储一个包含几个商品的购物车。
// Shopping cart item
JSONObject laptop = new JSONObject();
laptop.put("id", "hp-2341");
laptop.put("price", 1990.99);
laptop.put("quantity", 1);
// Another shopping cart item
JSONObject laptopCase = new JSONObject();
laptopCase.put("id", "case-9993");
laptopCase.put("price", 19.99);
laptopCase.put("quantity", 2);
// Storing items in the shopping cart
client.jsonSet("session:1", new Path2("cart"), new ArrayList<>());
client.jsonArrAppend("session:1", new Path2("cart"), laptop);
client.jsonArrAppend("session:1", new Path2("cart"), laptopCase);
让我们创建第二个会话来演示如何执行跨会话搜索操作。
// Creating another session
JSONObject jsonObject2 = new JSONObject();
jsonObject2.put("lastAccessedTime", System.currentTimeMillis() / 1000L);
jsonObject2.put("creationTime", System.currentTimeMillis() / 1000L);
jsonObject2.put("location", "34.638,31.79");
client.jsonSet("session:2", jsonObject2);
// Shopping cart item
JSONObject book = new JSONObject();
book.put("id", "sking-2435");
book.put("price", 14.90);
book.put("quantity", 1);
client.jsonSet("session:2", new Path2("cart"), new ArrayList<>());
client.jsonArrAppend("session:2", new Path2("cart"), book);
现在检索我们的数据。在屏幕上打印整个会话
System.out.println(client.jsonGet("session:1"));
读取会话的一部分,在本例中仅为购物车
System.out.println(client.jsonGet("session:1", new Path2("$.cart")));
你也可以在会话中搜索特定商品(通过 ID)并返回价格。搜索语法遵循 JSONPath 语法。
System.out.println(client.jsonGet("session:1", new Path2("$.cart[?(@.id==\"hp-2341\")].price")));
最后,让我们使用我们创建的 session_idx
索引并执行跨会话搜索以检索那些商品价格在 10 到 30 个“单位”之间的会话。
Query q = new Query().addFilter(new Query.NumericFilter("price", 10, 30)).setSortBy("price", true).setNoContent();
SearchResult res = client.ftSearch("session_idx", q);
System.out.println("Number of results: " + res.getTotalResults());
List<Document> docs = res.getDocuments();
for (Document doc : docs) {
System.out.println("Found session: " + doc.getId());
}
搜索将检索以下结果,因为两个会话都包含价格范围内的商品。
Number of results: 2
Found session: session:2
Found session: session:1