Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.util.Map;
import java.util.Random;

import redis.clients.jedis.JedisPool;
import redis.clients.jedis.RedisClient;

/**
* Synthesize a small batch of users with realistic-looking features
Expand Down Expand Up @@ -78,8 +78,8 @@ public static void main(String[] args) {
}
}

try (JedisPool pool = new JedisPool(redisHost, redisPort)) {
FeatureStore store = new FeatureStore(pool, keyPrefix, ttlSeconds,
try (RedisClient jedis = RedisClient.create(redisHost, redisPort)) {
FeatureStore store = new FeatureStore(jedis, keyPrefix, ttlSeconds,
FeatureStore.DEFAULT_STREAMING_TTL_SECONDS);
Map<String, Map<String, Object>> rows = synthesizeUsers(count, seed);
int loaded = store.bulkLoad(rows, ttlSeconds);
Expand Down
17 changes: 10 additions & 7 deletions content/develop/use-cases/feature-store/java-jedis/DemoServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.ConnectionPoolConfig;
import redis.clients.jedis.RedisClient;

/**
* Redis feature-store demo server (Jedis + JDK HttpServer).
Expand All @@ -35,7 +35,7 @@ public class DemoServer {
private static FeatureStore store;
private static StreamingWorker worker;
private static FeatureStoreDemo demo;
private static JedisPool jedisPool;
private static RedisClient jedis;

public static void main(String[] args) throws Exception {
String host = "127.0.0.1";
Expand Down Expand Up @@ -77,13 +77,16 @@ public static void main(String[] args) throws Exception {
}
}

JedisPoolConfig poolCfg = new JedisPoolConfig();
ConnectionPoolConfig poolCfg = new ConnectionPoolConfig();
poolCfg.setMaxTotal(64);
poolCfg.setMaxIdle(32);
poolCfg.setMinIdle(4);
jedisPool = new JedisPool(poolCfg, redisHost, redisPort);
jedis = RedisClient.builder()
.hostAndPort(redisHost, redisPort)
.poolConfig(poolCfg)
.build();

store = new FeatureStore(jedisPool, keyPrefix,
store = new FeatureStore(jedis, keyPrefix,
batchTtlSeconds, streamingTtlSeconds);
worker = new StreamingWorker(store, 1000L, usersPerTick, 1337L);
demo = new FeatureStoreDemo(store, worker, 42L);
Expand Down Expand Up @@ -120,7 +123,7 @@ public static void main(String[] args) throws Exception {
System.out.println("\nShutting down...");
worker.stop();
server.stop(0);
jedisPool.close();
jedis.close();
}));

Thread.currentThread().join();
Expand Down
125 changes: 52 additions & 73 deletions content/develop/use-cases/feature-store/java-jedis/FeatureStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.RedisClient;
import redis.clients.jedis.Response;

/**
Expand Down Expand Up @@ -67,7 +66,7 @@ public class FeatureStore {
public static final long DEFAULT_STREAMING_TTL_SECONDS = 5L * 60L;
public static final String DEFAULT_KEY_PREFIX = "fs:user:";

private final JedisPool pool;
private final RedisClient jedis;
private final String keyPrefix;
private final long batchTtlSeconds;
private final long streamingTtlSeconds;
Expand All @@ -77,15 +76,15 @@ public class FeatureStore {
private final AtomicLong readsTotal = new AtomicLong();
private final AtomicLong readFieldsTotal = new AtomicLong();

public FeatureStore(JedisPool pool) {
this(pool, DEFAULT_KEY_PREFIX,
public FeatureStore(RedisClient jedis) {
this(jedis, DEFAULT_KEY_PREFIX,
DEFAULT_BATCH_TTL_SECONDS,
DEFAULT_STREAMING_TTL_SECONDS);
}

public FeatureStore(JedisPool pool, String keyPrefix,
public FeatureStore(RedisClient jedis, String keyPrefix,
long batchTtlSeconds, long streamingTtlSeconds) {
this.pool = pool;
this.jedis = jedis;
this.keyPrefix = keyPrefix;
this.batchTtlSeconds = batchTtlSeconds;
this.streamingTtlSeconds = streamingTtlSeconds;
Expand Down Expand Up @@ -115,8 +114,7 @@ public String keyFor(String entityId) {
*/
public int bulkLoad(Map<String, Map<String, Object>> rows, long ttlSeconds) {
if (rows.isEmpty()) return 0;
try (Jedis jedis = pool.getResource()) {
Pipeline pipe = jedis.pipelined();
try (Pipeline pipe = jedis.pipelined()) {
for (Map.Entry<String, Map<String, Object>> e : rows.entrySet()) {
String key = keyFor(e.getKey());
Map<String, String> encoded = encode(e.getValue());
Expand All @@ -139,9 +137,7 @@ public int bulkLoad(Map<String, Map<String, Object>> rows) {
* pipelines flow through {@link #bulkLoad}.
*/
public void updateBatchFeature(String entityId, String field, Object value) {
try (Jedis jedis = pool.getResource()) {
jedis.hset(keyFor(entityId), field, encodeValue(value));
}
jedis.hset(keyFor(entityId), field, encodeValue(value));
batchWritesTotal.incrementAndGet();
}

Expand Down Expand Up @@ -180,13 +176,13 @@ public void updateStreaming(String entityId, Map<String, Object> fields, long tt
String[] names = encoded.keySet().toArray(new String[0]);

List<Long> expireCodes;
try (Jedis jedis = pool.getResource()) {
Pipeline pipe = jedis.pipelined();
Response<List<Long>> expireResp;
try (Pipeline pipe = jedis.pipelined()) {
pipe.hset(key, encoded);
Response<List<Long>> expireResp = pipe.hexpire(key, ttlSeconds, names);
expireResp = pipe.hexpire(key, ttlSeconds, names);
pipe.sync();
expireCodes = expireResp.get();
}
expireCodes = expireResp.get();
for (Long code : expireCodes) {
if (code == null || code != 1L) {
throw new IllegalStateException(
Expand Down Expand Up @@ -215,19 +211,15 @@ public Map<String, String> getFeatures(String entityId, List<String> fieldNames)
String key = keyFor(entityId);
Map<String, String> out = new LinkedHashMap<>();
if (fieldNames == null) {
try (Jedis jedis = pool.getResource()) {
Map<String, String> all = jedis.hgetAll(key);
if (all != null) out.putAll(all);
}
Map<String, String> all = jedis.hgetAll(key);
if (all != null) out.putAll(all);
readsTotal.incrementAndGet();
readFieldsTotal.addAndGet(out.size());
return out;
}
if (fieldNames.isEmpty()) return out;
List<String> values;
try (Jedis jedis = pool.getResource()) {
values = jedis.hmget(key, fieldNames.toArray(new String[0]));
}
values = jedis.hmget(key, fieldNames.toArray(new String[0]));
for (int i = 0; i < fieldNames.size(); i++) {
String v = values.get(i);
if (v != null) out.put(fieldNames.get(i), v);
Expand All @@ -253,8 +245,7 @@ public Map<String, Map<String, String>> batchGetFeatures(
String[] names = fieldNames.toArray(new String[0]);
Map<String, Map<String, String>> out = new LinkedHashMap<>();
List<Response<List<String>>> responses = new ArrayList<>(entityIds.size());
try (Jedis jedis = pool.getResource()) {
Pipeline pipe = jedis.pipelined();
try (Pipeline pipe = jedis.pipelined()) {
for (String id : entityIds) {
responses.add(pipe.hmget(keyFor(id), names));
}
Expand Down Expand Up @@ -287,9 +278,7 @@ public Map<String, Map<String, String>> batchGetFeatures(
* key-level TTL is set, {@code -2} if the key doesn't exist.
*/
public long keyTtlSeconds(String entityId) {
try (Jedis jedis = pool.getResource()) {
return jedis.ttl(keyFor(entityId));
}
return jedis.ttl(keyFor(entityId));
}

/**
Expand All @@ -302,9 +291,7 @@ public long keyTtlSeconds(String entityId) {
public Map<String, Long> fieldTtlsSeconds(String entityId, List<String> fieldNames) {
if (fieldNames.isEmpty()) return Collections.emptyMap();
List<Long> codes;
try (Jedis jedis = pool.getResource()) {
codes = jedis.httl(keyFor(entityId), fieldNames.toArray(new String[0]));
}
codes = jedis.httl(keyFor(entityId), fieldNames.toArray(new String[0]));
Map<String, Long> out = new LinkedHashMap<>();
for (int i = 0; i < fieldNames.size(); i++) {
// HTTL on a missing key returns a flat list of -2s; jedis
Expand All @@ -329,24 +316,22 @@ public List<String> listEntityIds(int limit) {
List<String> ids = new ArrayList<>();
String pattern = keyPrefix + "*";
String cursor = "0";
try (Jedis jedis = pool.getResource()) {
do {
redis.clients.jedis.params.ScanParams params = new redis.clients.jedis.params.ScanParams()
.match(pattern)
.count(200);
redis.clients.jedis.resps.ScanResult<String> sr = jedis.scan(cursor, params);
for (String k : sr.getResult()) {
if (k.length() > keyPrefix.length()) {
ids.add(k.substring(keyPrefix.length()));
if (ids.size() >= limit) {
Collections.sort(ids);
return ids;
}
do {
redis.clients.jedis.params.ScanParams params = new redis.clients.jedis.params.ScanParams()
.match(pattern)
.count(200);
redis.clients.jedis.resps.ScanResult<String> sr = jedis.scan(cursor, params);
for (String k : sr.getResult()) {
if (k.length() > keyPrefix.length()) {
ids.add(k.substring(keyPrefix.length()));
if (ids.size() >= limit) {
Collections.sort(ids);
return ids;
}
}
cursor = sr.getCursor();
} while (!"0".equals(cursor));
}
}
cursor = sr.getCursor();
} while (!"0".equals(cursor));
Collections.sort(ids);
return ids;
}
Expand All @@ -360,23 +345,19 @@ public long countEntities() {
long count = 0;
String pattern = keyPrefix + "*";
String cursor = "0";
try (Jedis jedis = pool.getResource()) {
do {
redis.clients.jedis.params.ScanParams params = new redis.clients.jedis.params.ScanParams()
.match(pattern)
.count(500);
redis.clients.jedis.resps.ScanResult<String> sr = jedis.scan(cursor, params);
count += sr.getResult().size();
cursor = sr.getCursor();
} while (!"0".equals(cursor));
}
do {
redis.clients.jedis.params.ScanParams params = new redis.clients.jedis.params.ScanParams()
.match(pattern)
.count(500);
redis.clients.jedis.resps.ScanResult<String> sr = jedis.scan(cursor, params);
count += sr.getResult().size();
cursor = sr.getCursor();
} while (!"0".equals(cursor));
return count;
}

public long deleteEntity(String entityId) {
try (Jedis jedis = pool.getResource()) {
return jedis.del(keyFor(entityId));
}
return jedis.del(keyFor(entityId));
}

/**
Expand All @@ -389,19 +370,17 @@ public long reset() {
long deleted = 0;
String pattern = keyPrefix + "*";
String cursor = "0";
try (Jedis jedis = pool.getResource()) {
do {
redis.clients.jedis.params.ScanParams params = new redis.clients.jedis.params.ScanParams()
.match(pattern)
.count(500);
redis.clients.jedis.resps.ScanResult<String> sr = jedis.scan(cursor, params);
List<String> batch = sr.getResult();
if (!batch.isEmpty()) {
deleted += jedis.del(batch.toArray(new String[0]));
}
cursor = sr.getCursor();
} while (!"0".equals(cursor));
}
do {
redis.clients.jedis.params.ScanParams params = new redis.clients.jedis.params.ScanParams()
.match(pattern)
.count(500);
redis.clients.jedis.resps.ScanResult<String> sr = jedis.scan(cursor, params);
List<String> batch = sr.getResult();
if (!batch.isEmpty()) {
deleted += jedis.del(batch.toArray(new String[0]));
}
cursor = sr.getCursor();
} while (!"0".equals(cursor));
return deleted;
}

Expand Down
Loading
Loading