How Redis represents String as bits internally? - redis

I'm trying to understand the bit representation of a String (most specifically in Redis)
I tried this:
redis> SET mykey3 hello
OK
redis> SETBIT mykey3 7 0
(integer) 0
redis> SETBIT mykey3 7 1
(integer) 0
redis> GET mykey3
"iello"
redis> SET mykey4 5
OK
redis> SETBIT mykey4 7 0
(integer) 1
redis> GET mykey4
"4"
So what is the bit representation of "hello" and "5" in this case?
Also how the other Redis types, List, Set, Sorted Set are represented as binary bit? Such that bit operations can work for it? Or this is not the case?
From what is seems everything is stored as binary-safe String? If so, how does a List, Set, Sorted Set are represented as safe String?

If you look at bitops.c you'll see that indeed bit commands only work with string key type.
From redis.io:
All the following data types are supported as values:
Binary-safe strings.
Lists of binary-safe strings.
Sets of binary-safe
strings, that are collection of unique unsorted elements. You can
think at this as a Ruby hash where all the keys are set to the 'true'
value.
Sorted sets, similar to Sets but where every element is
associated to a floating number score. The elements are taken sorted
by score. You can think of this as Ruby hashes where the key is the
element and the value is the score, but where elements are always
taken in order without requiring a sorting operation.
So only the lists and sets values are stored in binary-safe strings. This is also true for the keys and hash values as well as sorted set members.

Related

How to get all 'key namespaces' (object types) in Redis?

As we may know, good naming convention for Redis keys is "object-type:id"
How to get all key namespaces (symbols before :)?
E.g.
127.0.0.1:6379> KEYS *
1) "bar:1"
2) "baz:1"
3) "baz:3"
4) "foo:1"
5) "foo:2"
6) "baz:2"
I want a command like
127.0.0.1:6379> SCAN 0 MATCH "(^\w+):" COUNT 10
1) "6"
2) "foo"
3) "bar"
4) "baz"
But seems like MATCH option of SCAN command does not support PCRE pattern syntax.
In real, I got
127.0.0.1:6379> SCAN 0 MATCH "(^\w+):" COUNT 10
1) "6"
2) (empty list or set)
Any ideas ?
You could create an index key and add each namespace to it every time you add a new key:
SADD "namespaces" "foo". But there would be problem with deleting them, as you'd have to check if the deleted object was the last of it's type.
The second option would be creating a module (if you're using Redis >= 4.0) with a command that you could use to add and remove said keys, that would have it's own type in which it would store object-type counters (so it wouldn't have to call KEYS * which is quite slow). The problem here would be if you had key expiration, or oom key deletion configured. The counter would be incorrect once a key gets deleted by Redis itself.
The third option is to create a module with one command that would call KEYS *, then get the first part of the key and add it to a hash map/dictionary (using RedisModuleDict) and then return it using RedisModule_ReplyWithString(ctx, str) in a loop
I think that you could also write it in Lua instead of creating a module, but a module written in C is probably going to be faster... and I don't know Lua so I won't be able to help you there.
You could always write a simple script in bash that would get the object-type from each key and SADD it to a temporary key then read it, print and delete afterwards, but that's the same as the third option but slower and has to use a temporary key which might be used by some other script or something.

How to make a set of unique records in Elm

I need a set of unique records. But Elm Core's Set restricts set members to comparable:
import Set exposing (Set)
mySet = Set.empty
Set.insert {name="Foo"} mySet
-- TYPE MISMATCH ----------------------------------------------------------- elm
The 1st argument to `insert` is not what I expect:
6| Set.insert {name="Foo"} mySet
^^^^^^^^^^^^
This argument is a record of type:
{ name : String }
But `insert` needs the 1st argument to be:
comparable
Hint: Only ints, floats, chars, strings, lists, and tuples are comparable.
How do you make a set of records in Elm?
With the standard library you can't. As noted in the "Hint" you could use a tuple, but these are limited to 3-tuples in 0.19.
So, I think your best bet is to use https://package.elm-lang.org/packages/Gizra/elm-all-set/latest/EverySet

Redis Hash/Set Storing multiple types

I am new to redis so I apologize if this question seems naive. I want to create a hash of the following type:
item = {{"bititem":00001010000100...001010},
{"property":1}}
Where bititem is a bit array created by setbit and property is a simple integer value. Is there any way to do this in redis or do I have to create different objects?
From your example, it is not clear to me why you need the extra depth-level around bititem.
Also, it is not clear to me what you want to do with it afterwards. So I give you three scenario's:
1. Serialized:
You can always serialize your data if it involves multiple levels. Most efficient is MsgPack, second best is JSON. You can deserialize the data in Lua-Redis when needed.
2. Hashed:
If you don't need multiple levels, simply do:
HSET item:01 bititem 00001010000100...001010
HSET item:01 property 1
Only do this though, if you really need to extract the different datamembers often. Separate members have quite some overhead. In general, I prefer to serialize the whole object (with a SET or a HSET).
3. Bitwise enabled:
If you want to make use of Redis' bitwise operations, you need to use simple strings (GET/SET). For example:
SET item:01:bititem "00001010000100...001010"
SET item:01:property 1
or even better:
SET item:01:bititem "00001010000100...001010"
SET item:01:properties [all-other-properties-serialized-as-msgpack]
Hope this helps, TW

In Redis, command for retrieving values from sorted-set

I tried adding some sample score-value pairs to redis sorted set using below code:
String key = "set";
redis.zadd(key, 5, "1034");
redis.zadd(key, 2, "1030");
redis.zadd(key, 1, "1089");
and tried retrieving it using byteArray and BitSet
byte[] byteArr = redis.get(key.getBytes());
BitSet bitSet = fromByteArrayReverse(byteArr);
System.out.println(bitset.toString()));
also i tried executing
System.out.println(redis.get(key.getBytes()));
which is supposed to give me an address of the byte-array
But for both of these commands i get the error
" ERR Operation against a key holding the wrong kind of value"
So can anyone please tell me why does this error occur in the first place and also the correct redis command/code to retrieve values from a redis sorted-set??
What you want is calling
ZSCORE key "1034"
Or in the case of wanting only elements between two particular scores
ZRANGEBYSCORE key lower upper
Since you also have "rank" (position or index, as in a list) you can also ask for example for the first three elements in your set
ZRANGEBYRANK key 0 2
The error you are getting is because once you assign a value to a key, that value defines the type of the internal structure on redis, and you can only use commands for that particular structure (or generic key commands such as DEL and so on). In your case you are trying to mix sorted sets with byte operations and it doesn't match.
To see all sorted set commands, please refer to http://redis.io/commands#sorted_set

Redis sort gives strange results

I'm trying to find out why I do get these strange results from this sort query:
redis> sort set:package:1:all_games by hash:game:*->rating DESC LIMIT 0 10 GET hash:game:*->rating
1. "10"
2. "10"
3. "10"
4. "9,1"
5. "9"
6. "9,2"
7. "9"
8. "9,1"
9. "9"
10. "9,4"
redis>
I know the data uses , in stead of . and it will be fixed. But why is it sorted so inconsistently? I'd at least expect it to give consistent results (The 9,1's in sequence).
Can anyone explain what's going on here?
As mentioned by Ofer, by default, the sort is numeric and the elements are compared as double precision floating point numbers.
Redis sort function works by populating a C array from the original container. The initial order of the items in this array is the order of the items in the initial container (which is undefined for set for instance).
Each item is then tagged with a score value. Redis uses the standard strtod function to convert the string value to a double. This function works with a best effort approach: it tries to convert as many characters as possible. So the "9", "9,1" "9,2" and "9,4" strings will all be converted to 9.0
Finally the array is sorted using either the standard qsort algorithm, either the BENTLEY/McILROY algorithm (depending if limit parameters are set or not). AFAIK, none of these sort algorithms are stable. It means the order of the items with the same score will be random in the result.
This is exactly what you get on the example: you have the "10" items first, and then the "9" items. Order of the "9" items is random.
Add ALPHA at the end:
sort set:package:1:all_games by hash:game:*->rating DESC LIMIT 0 10 GET hash:game:*->rating ALPHA
By default, sorting is numeric and elements are compared by their value interpreted as double precision floating point number.
When a list (or set) contains string values and you want to sort them lexicographically, use the ALPHA modifier.
See: http://redis.io/commands/sort