I am trying to RPUSH a string with blank spliter into a Redis List, but when I using the RPUSH in RedisSinkBuilder, the string cannot be splited.
Code:
RedisSinkBuilder<Tuple2<String, String>> builder = new RedisSinkBuilder<>();
RedisSink<Tuple2<String, String>> redisSink = builder
.redisMapper(new Tuple2RedisMapper())
.syncType(RedisSyncType.ASYNC)
.deployType(RedisType.STANDALONE)
.hostname(redisTestHost)
.port(redisTestPort)
.dataType(RedisDataType.LIST)
.redisCommand(RedisCommand.RPUSH)
.additionalTTL(60)
.build();
testDataStream.addSink(redisSink).name("test");
Example:
key: "test"
value: "1 2 3 4 5"
Expected Data in Redis:
1)"1"
2)"2"
3)"3"
4)“4"
5)"5"
However, I got only 1 element in the test list:
1)"1 2 3 4 5"
Any ideas on how I can RPUSH multiple elements in a string into a list in Redis?
Many Thanks!
Related
I am able to add and get a particular user object from Redis I am adding object like this:
private static final String USER_PREFIX = ":USER:";
public void addUserToRedis(String serverName,User user) {
redisTemplate.opsForHash().put(serverName + USER_PREFIX + user.getId(),
Integer.toString(user.getId()),user);
}
If a userId is 100 I am able to get by key: SERVER1:USER:100
Now I want to retrieve all Users as Map<String,List<User>> ,
For example, get all users by this key SERVER1:USER: Is it possible ? Or I need to modify my addUserToRedis method? Please suggest me.
I would recommend not using the "KEYS" command in production as this can severely impact REDIS latencies (can even bring down the cluster if you have a large number of keys stored)
Instead, you would want to use a different command than plain GET/SET.
It would be better if you use a Sets or Hashes
127.0.0.1:6379> sadd server1 user1 user2
(integer) 2
127.0.0.1:6379> smembers server1
1) "user2"
2) "user1"
127.0.0.1:6379>
Using sets you can simply add your users to server keys and get the entire list of users on a server.
If you really need a map of < server, list < users > > you can use hashes with stringified user data and then convert it to actual User POJO at application layer
127.0.0.1:6379> hset server2 user11 name
(integer) 1
127.0.0.1:6379> hset server2 user13 name
(integer) 1
127.0.0.1:6379> hgetall server2
1) "user11"
2) "name"
3) "user13"
4) "name"
127.0.0.1:6379>
Also do note that keeping this much big data into a single key is not an ideal thing to do.
i dont use java but here's how to use SCAN
const Redis = require('ioredis')
const redis = new Redis()
async function main() {
const stream = redis.scanStream({
match: "*:user:*",
count: 100,
})
stream.on("data", (resultKeys) => {
for (let i = 0; i < resultKeys.length; i++) {
// console.log(resultKeys[i])
// do your things here
}
});
stream.on("end", () => {
console.log("all keys have been visited");
});
}
main()
Finally I came up with this solution with wildcard search and avoiding KEYS, and here is my complete method:
public Map<String, User> getUserMapFromRedis(String serverName){
Map<String, User> users=new HashMap<>();
RedisConnection redisConnection = null;
try {
redisConnection = redisTemplate.getConnectionFactory().getConnection();
ScanOptions options = ScanOptions.scanOptions().match(serverName + USER_PREFIX+"*").build();
Cursor<byte[]> scan = redisConnection.scan(options);
while (scan.hasNext()) {
byte[] next = scan.next();
String key = new String(next, StandardCharsets.UTF_8);
String[] keyArray=key.split(":");
String userId=keyArray[2];
User user=//get User by userId From Redis
users.put(userId, user);
}
try {
scan.close();
} catch (IOException e) {
}
}finally {
redisConnection.close(); //Ensure closing this connection.
}
return users;
}
I have a hashset in redis like below.
"abcd" : {
"rec.number.984567": "value1",
"rec.number.973956": "value2",
"rec.number.990024": "value3",
"rec.number.910842": "value4",
"rec.number.910856": "...",
"other.abcd.efgh": "some value",
"other.xyza.blah": "some other value"
"..." : "...",
"..." : "...",
"..." : "...",
"..." : "..."
}
if I call hgetall abcd, it will give me all fields in the hash. My objective is to get only those fields of the hashset that begin with "rec.number". When I call like
redis-cli hmget "abcd" "rec.number*",
it gives me a result like
1)
Is there a way to retrieve data for only those keys which start with my expected pattern? I want to retrieve only those keys because my dataset contains many other irrelevant fields.
HMGET do not supports wildcard in field name. You can use HSCAN for that:
HSCAN abcd 0 MATCH rec.number*
More about SCAN function in official docs.
LUA way
This script does it in LUA scripting:
local rawData = redis.call('HGETALL', KEYS[1]);
local ret = {};
for idx = 1, #rawData, 2 do
if string.match(rawData[idx], ARGV[1]) then
hashData[rawData[idx]] = rawData[idx + 1];
end
end
Nice intro about using redis-cliand LUA in Redis may be found in A Guide for Redis Users.
I have a doc like the following:
as you can see I have an array entity: {1,3,4}
Now I want to just change 4 to 10 in that array and update it for that I have the following code:
DBCollection coll = db.getCollection("test");
BasicDBObject newDocument = new BasicDBObject();
BasicDBObject searchQuery = new BasicDBObject().append("time", "20141105230000");
coll.update(searchQuery, newDocument);
String[] str = { "1", "3", "10" };
DBObject updateMatchingElem = new BasicDBObject("$set",
new BasicDBObject().append("entity", str));
coll.update(searchQuery, updateMatchingElem);
But this way is not a good way because I kind of remove entity and then insert the whole array again. Is there anyway that I can just change the one element like 4 to 10?
Now I want to just change 4 to 10 in that array and update it
You can do it in the following way, using the $ positional operator.
//db.collection.update({"entity":4},{$set:{"entity.$":10}})
DBObject find = new BasicDBObject( "entity", 4);
DBObject set = new BasicDBObject( "entity.$", 10);
DBObject update = new BasicDBObject().append("$set", set);
coll.update(find, update);
Note that you can at most update only one single matching array element, even if there are other matching elements in the array. For instance, if there are two 4s in the array, only the first occurrence of 4 will get updated. This is how the positional operator works.
Whenever you use the positional operator in the update query, the find query must contain the field in the find part of the query.
I have a query like this
start n = node:node_auto_index('ids:"123", "456" ... ') return n
Here 123, 456 is a list of keys as a single param {list}. Now when I try to write this in Java
String q = " START n=node:node_auto_index('key:{ids}') return n "
Map<String, Object> map = new HashMap<String, Object>();
map.put("ids", keyList); // keyList is a list of strings
But somehow calling graphstoreclient.executeCypher(q, map) fails with parse error, can you point me to any documentation / correct syntax on this.
PS - This query works fine on console.
Since you're supplying a lucene query string, parameterize the entire string:
String q = " START n=node:node_auto_index({ids}) return n "
Map<String, Object> map = new HashMap<String, Object>();
map.put("ids", keyList);
keyList should now look like ids:"123", "456" ...
I have the following result set :
Name Occurrence
Jack 2
Jill 1
Tom 3
I want to put this in HashMap? I was able to display only the one entry
Or is it best to use a ArrayList ?
Dictionary<string, int> dictionary =
new Dictionary<string, int>();
dictionary.Add("Jack ", 2);
dictionary.Add("Jill ", 1);
dictionary.Add("Tom ", 3);