2
votes

I would like to access value with the given pattern from hash in redis with out providing key.

Example

HSET myKey  va11 "Hello" val2 "Hi" Val3 "GooMorning" val4 "Good Evening"
HSET myKey2  va11 "one val2 "two" Val3 "three" val4 "four"

I have set of keys with their values as above. Is there any way to retrieve values without providing keys.

i just want to check is there any value with Good* something like that without providing key.

2

2 Answers

0
votes

I saw that you're using the "lua" tag - if LUA is not a a must, please consider the following example using HVALS. I'l provide some redis-py code to go with:

import redis

# connect to local redis-server:6379
r = redis.Redis()
# initialize sample "myKey" hash
r.hmset("myKey", {'val1': "Hello", 'val2': "Hi", 'val3': "GoodMorning", 'val4': "Good Evening"})
# provide "starts with" pattern (this could obviously be a regex as well)
pattern = "Good"
# find all values starting with the pattern and return them
values_matching = filter(lambda x: x.startswith(pattern), r.hvals("myKey"))
# print values: ["GoodMorning", "Good Evening"]
print values_matching

You don't say that you need the keys for the matching values. If you do, then you should look into the HGETALL command.

EDIT after reading your comments: yes, you will need to loop over all key/values in the hash using HGETALL. An amended example following:

import redis

r = redis.Redis()
r.hmset("myKey", {'val1': "Hello", 'val2': "Hi", 'val3': "GoodMorning", 'val4': "Good Evening"})
pattern = "Good"
# use hgetall() to iterate over all key-value pairs and form values_matching by looking only at pairs where the value starts with "Good"
values_matching = dict([(k, v) for k, v in r.hgetall("myKey").iteritems() if v.startswith(pattern)])
# print values: {'val3': 'GoodMorning', 'val4': 'Good Evening'}
print values_matching
0
votes

Redis doesn't provide this functionality out of the box. However, if I understand your question correctly, you can easily add it.

Keep a sorted set, for example call it allvals, with all the values from your hashes (i.e. do a ZADD to it on every hash update). Use ZRANGEBYLEX on it for suffix searching as means for existence checking:

ZRANGEBYLEX allvals "[Good" "[Good\xff"

EDIT: Given your clarification, this approach is not what you're looking for. Here's my take on the revised challenge.

So. What you're looking for is a way to fetch hash key names if they contain a specific value in one of their fields. One way would be to scan all you hashes and look for that value (as @tobiash suggested) but, depending on the size of your dataset, this may be quite expensive. Another way to go about this is to use sets as means for indexing your hashes. The basic premise is to take every value in the hash(es) and create sets for it. Each such set's members would be the actual key names of the hashes that contain that value.

Let's see how your example's myKey should be indexed (yes, we're building an index here). To begin with, you'll create the following sets out of it:

SADD idx:Hello myKey
SADD idx:Hi myKey
SADD idx:GooMorning myKey
SADD "idx:Good Evening" myKey

Now, by doing SMEMBERS on idx:Hello, you'll get all the key names that have Hello as values. However, since what you're looking for is doing suffix searching, for each value you'll actually need to maintain multiple sets, where each set indexes a substring of the value. For example, for the string Hello you'll actually need:

SADD idx:H myKey
SADD idx:He myKey
SADD idx:Hel myKey
SADD idx:Hell myKey
SADD idx:Hello myKey

Lua can help here if you'll create a script that you'll call to update your hashes. The script should be given the hash key name and the field names + values. Once called, the script will need not only to create/update the actual hash, but also to iterate over all field values and construct the index for them (and their respective substrings).

Let us know if you need help with writing that script ;)