Skip to content

Commit 2312bbb

Browse files
committed
refactor(jedis): migrate to Jedis 7.2 API with RedisClient
Replace all deprecated Jedis classes with the new unified Jedis 7.2 API: - Upgrade Jedis dependency from 7.0.0 to 7.2.0 - Replace JedisPool/JedisPooled with RedisClient.create() - Replace JedisSentinelPool with RedisSentinelClient.builder() - Remove JedisPoolConfig dependency from RedisConnectionConfig - Update SearchIndex to use unified getUnifiedJedis() method - Update VCR infrastructure (VCRContext, VCRRegistry, VCRCassetteStore) - Update all test base classes to use RedisClient - Update LangChain4J stores and documentation examples - Update demo applications (rag-multimodal, standalone) The new Jedis 7.2 API provides: - RedisClient for standalone connections - RedisSentinelClient for HA deployments - RedisClusterClient for cluster mode - All extend UnifiedJedis for backwards compatibility This removes deprecation warnings and modernizes the codebase to use the recommended Jedis connection patterns.
1 parent 0ecf709 commit 2312bbb

27 files changed

+254
-426
lines changed

core/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ plugins {
88
description = "RedisVL - Vector Library for Java"
99

1010
dependencies {
11-
// Redis client
12-
api("redis.clients:jedis:7.0.0")
11+
// Redis client - upgraded to 7.2.0 for new RedisClient/RedisSentinelClient API
12+
api("redis.clients:jedis:7.2.0")
1313

1414
// JSON processing
1515
implementation("com.fasterxml.jackson.core:jackson-databind:2.18.2")

core/src/main/java/com/redis/vl/index/SearchIndex.java

Lines changed: 17 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import javax.annotation.Nonnull;
2121
import lombok.Getter;
2222
import lombok.extern.slf4j.Slf4j;
23-
import redis.clients.jedis.Jedis;
23+
import redis.clients.jedis.RedisClient;
2424
import redis.clients.jedis.UnifiedJedis;
2525
import redis.clients.jedis.search.FTCreateParams;
2626
import redis.clients.jedis.search.FTSearchParams;
@@ -48,7 +48,6 @@ public final class SearchIndex {
4848
private final IndexSchema schema;
4949

5050
private final BaseStorage storage;
51-
private Jedis client;
5251
private UnifiedJedis unifiedClient;
5352
@Getter private boolean validateOnLoad = false;
5453

@@ -91,40 +90,6 @@ public SearchIndex(IndexSchema schema, boolean validateOnLoad) {
9190
}
9291
this.connectionManager = null;
9392
this.schema = schema;
94-
this.client = null;
95-
this.unifiedClient = null;
96-
this.validateOnLoad = validateOnLoad;
97-
this.storage = initializeStorage(schema);
98-
}
99-
100-
/**
101-
* Create a SearchIndex with schema and Jedis client
102-
*
103-
* @param schema Index schema definition
104-
* @param client Jedis client for Redis operations
105-
*/
106-
public SearchIndex(IndexSchema schema, Jedis client) {
107-
this(schema, client, false);
108-
}
109-
110-
/**
111-
* Create a SearchIndex with schema, Jedis client, and validateOnLoad option
112-
*
113-
* @param schema Index schema definition
114-
* @param client Jedis client for Redis operations
115-
* @param validateOnLoad Whether to validate documents on load
116-
*/
117-
public SearchIndex(IndexSchema schema, Jedis client, boolean validateOnLoad) {
118-
if (schema == null) {
119-
throw new IllegalArgumentException("Must provide a valid IndexSchema object");
120-
}
121-
if (client == null) {
122-
throw new IllegalArgumentException("Jedis client cannot be null");
123-
}
124-
this.connectionManager = null;
125-
this.schema = schema;
126-
// Store the client - this is the expected usage pattern for this library
127-
this.client = client;
12893
this.unifiedClient = null;
12994
this.validateOnLoad = validateOnLoad;
13095
this.storage = initializeStorage(schema);
@@ -156,10 +121,9 @@ public SearchIndex(IndexSchema schema, String redisUrl, boolean validateOnLoad)
156121
}
157122
this.connectionManager = null;
158123
this.schema = schema;
159-
this.client = null;
160124
this.validateOnLoad = validateOnLoad;
161-
// Create UnifiedJedis from URL
162-
this.unifiedClient = new UnifiedJedis(redisUrl);
125+
// Create RedisClient (extends UnifiedJedis) from URL - Jedis 7.2+ API
126+
this.unifiedClient = RedisClient.create(redisUrl);
163127
this.storage = initializeStorage(schema);
164128
}
165129

@@ -189,7 +153,6 @@ public SearchIndex(IndexSchema schema, UnifiedJedis unifiedClient, boolean valid
189153
}
190154
this.connectionManager = null;
191155
this.schema = schema;
192-
this.client = null;
193156
this.validateOnLoad = validateOnLoad;
194157
// Store the client - this is the expected usage pattern for this library
195158
this.unifiedClient = unifiedClient;
@@ -439,24 +402,19 @@ public static SearchIndex fromExisting(String indexName, UnifiedJedis client) {
439402
return new SearchIndex(schema, client);
440403
}
441404

442-
/** Get Jedis connection from either connectionManager or direct client */
443-
private Jedis getJedis() {
444-
if (client != null) {
445-
return client;
446-
} else if (connectionManager != null) {
447-
return connectionManager.getJedis();
448-
} else {
449-
throw new IllegalStateException("No Redis connection available for document operations");
450-
}
451-
}
452-
453-
/** Get UnifiedJedis for RediSearch operations */
405+
/**
406+
* Get UnifiedJedis for Redis operations.
407+
*
408+
* <p>Returns the client from either the direct unifiedClient field or from the connectionManager.
409+
*/
454410
private UnifiedJedis getUnifiedJedis() {
455411
if (unifiedClient != null) {
456412
return unifiedClient;
413+
} else if (connectionManager != null) {
414+
return connectionManager.getClient();
457415
} else {
458416
throw new IllegalStateException(
459-
"RediSearch operations require UnifiedJedis client. Please use SearchIndex(schema, unifiedJedis) constructor.");
417+
"No Redis connection available. Use SearchIndex(schema, unifiedJedis) or SearchIndex(connectionManager, schema) constructor.");
460418
}
461419
}
462420

@@ -762,60 +720,8 @@ public String addDocument(String docId, Map<String, Object> document) {
762720
Map<String, Object> processedDocument = preprocessDocument(document);
763721
// Always validate document against schema when adding directly
764722
validateDocument(processedDocument);
765-
// Use UnifiedJedis if available for consistency
766-
if (unifiedClient != null) {
767-
return addDocumentWithUnified(docId, processedDocument);
768-
}
769-
770-
Jedis jedis = getJedis();
771-
try {
772-
if (getStorageType() == IndexSchema.StorageType.JSON) {
773-
// For JSON storage, use RedisJSON commands
774-
775-
// Use JSON.SET command - Jedis doesn't have jsonSet, need UnifiedJedis
776-
throw new IllegalStateException(
777-
"JSON storage requires UnifiedJedis client. Use SearchIndex(schema, unifiedJedis) constructor.");
778-
} else {
779-
// For HASH storage - handle vectors specially
780-
for (Map.Entry<String, Object> entry : processedDocument.entrySet()) {
781-
String key = entry.getKey();
782-
Object value = entry.getValue();
783-
784-
BaseField field = (schema != null) ? schema.getField(key) : null;
785-
if (field instanceof VectorField && value != null) {
786-
// Store vectors as binary data
787-
byte[] vectorBytes = null;
788-
if (value instanceof byte[]) {
789-
// Already in byte array format
790-
vectorBytes = (byte[]) value;
791-
} else if (value instanceof float[]) {
792-
vectorBytes = ArrayUtils.floatArrayToBytes((float[]) value);
793-
} else if (value instanceof double[]) {
794-
float[] floats = ArrayUtils.doubleArrayToFloats((double[]) value);
795-
vectorBytes = ArrayUtils.floatArrayToBytes(floats);
796-
}
797-
if (vectorBytes != null) {
798-
jedis.hset(
799-
docId.getBytes(StandardCharsets.UTF_8),
800-
key.getBytes(StandardCharsets.UTF_8),
801-
vectorBytes);
802-
}
803-
} else if (value != null) {
804-
// Store other fields as strings
805-
jedis.hset(docId, key, value.toString());
806-
}
807-
}
808-
}
809-
810-
return docId;
811-
} catch (Exception e) {
812-
throw new RuntimeException("Failed to add document: " + e.getMessage(), e);
813-
} finally {
814-
// Close connection if we don't have a persistent client
815-
if (client == null && connectionManager != null) {
816-
jedis.close();
817-
}
818-
}
723+
// Use the unified method for all document operations
724+
return addDocumentWithUnified(docId, processedDocument);
819725
}
820726

821727
private String addDocumentWithUnified(String docId, Map<String, Object> document) {
@@ -838,8 +744,8 @@ private String addDocumentWithUnified(String docId, Map<String, Object> document
838744
// Use JSON.SET command to store the document as an object
839745
// Path2.ROOT_PATH is the root JSON path "$"
840746
String result =
841-
unifiedClient.jsonSetWithEscape(
842-
docId, redis.clients.jedis.json.Path2.ROOT_PATH, jsonDocument);
747+
getUnifiedJedis()
748+
.jsonSetWithEscape(docId, redis.clients.jedis.json.Path2.ROOT_PATH, jsonDocument);
843749
log.debug("Stored JSON document {}: {}", docId, result);
844750
} else {
845751
// For HASH storage - handle vectors specially
@@ -874,11 +780,11 @@ private String addDocumentWithUnified(String docId, Map<String, Object> document
874780

875781
// Store binary fields
876782
if (!binaryFields.isEmpty()) {
877-
unifiedClient.hset(docId.getBytes(StandardCharsets.UTF_8), binaryFields);
783+
getUnifiedJedis().hset(docId.getBytes(StandardCharsets.UTF_8), binaryFields);
878784
}
879785
// Store string fields
880786
if (!stringFields.isEmpty()) {
881-
unifiedClient.hset(docId, stringFields);
787+
getUnifiedJedis().hset(docId, stringFields);
882788
}
883789
}
884790

core/src/main/java/com/redis/vl/langchain4j/RedisVLChatMemoryStore.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*
2323
* <pre>{@code
2424
* // Create chat memory store
25-
* UnifiedJedis jedis = new JedisPooled("localhost", 6379);
25+
* UnifiedJedis jedis = RedisClient.create("localhost", 6379);
2626
* ChatMemoryStore memoryStore = new RedisVLChatMemoryStore(jedis);
2727
*
2828
* // Use with LangChain4J chat memory

core/src/main/java/com/redis/vl/langchain4j/RedisVLDocumentStore.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*
2323
* <pre>{@code
2424
* // Create document store
25-
* UnifiedJedis jedis = new JedisPooled("localhost", 6379);
25+
* UnifiedJedis jedis = RedisClient.create("localhost", 6379);
2626
* RedisVLDocumentStore store = new RedisVLDocumentStore(jedis, "docs:");
2727
*
2828
* // Store a document

core/src/main/java/com/redis/vl/redis/RedisConnectionConfig.java

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
import lombok.Builder;
44
import lombok.Getter;
5-
import redis.clients.jedis.JedisPoolConfig;
65

7-
/** Configuration for Redis connections. */
6+
/**
7+
* Configuration for Redis connections.
8+
*
9+
* <p>Used with {@link RedisConnectionManager} to configure connection parameters.
10+
*/
811
@Getter
912
@Builder
1013
public class RedisConnectionConfig {
@@ -89,20 +92,4 @@ public static RedisConnectionConfig fromUri(String uri) {
8992
public static RedisConnectionConfig fromHostPort(String host, int port) {
9093
return RedisConnectionConfig.builder().host(host).port(port).build();
9194
}
92-
93-
/**
94-
* Create a JedisPoolConfig from this configuration.
95-
*
96-
* @return JedisPoolConfig with settings from this configuration
97-
*/
98-
public JedisPoolConfig toJedisPoolConfig() {
99-
JedisPoolConfig config = new JedisPoolConfig();
100-
config.setMaxTotal(maxTotal);
101-
config.setMaxIdle(maxIdle);
102-
config.setMinIdle(minIdle);
103-
config.setTestOnBorrow(testOnBorrow);
104-
config.setTestOnReturn(testOnReturn);
105-
config.setTestWhileIdle(testWhileIdle);
106-
return config;
107-
}
10895
}

0 commit comments

Comments
 (0)