RedisTemplate get hash key by value - spring

I'm very new both on Spring and Redis. I would like to know if there is a way to get the KEY by value?
My KEY is patterned like this: "{typeOfFile}:{id}:{filename}"
typeOfFile could either be "image", "html", or "pdf".
For instance, I want to get the get the KEY of an image type of file with a given fileHash and content. I'm doing it with this kind of idea:
private String getKeyByVal(final String givenFileHash, final String content) {
// get all keys that starts with "image"
Set<String> keys = redisTemplate.keys("image*");
if (keys != null) {
for (String key : keys) {
Map<Object, Object> val = redisTemplate.opsForHash().entries(key);
// check if the value of KEY is equal to the given fileHash
if (val.get("fileHash").equals(givenFileHash) && val.get("content").equals(content)) {
return key;
}
}
}
}
However, I was told that this is quite costly since I'm getting all the keys that starts with "image", and manually check all of them.
Now I'm thinking, maybe it would be much better if I can get the KEY by value. So that it would be easier to get all of its properties. Is that possible in Redis?

No, this is not possible in Redis. You can however store a reverse map in simultaneous as below:
fileHash -> "{typeOfFile}:{id}:{filename}"
This solution assumes that the file hash is unique. If the hash is not unique then you can store a set of ids with the same hash, retrieve the content for each of them and compare. Still a lot faster than the original solution.

Related

What are supported types for keys of hash in freemarker?

Can we use any type for keys of hash in Freemarker ?
For instance:
In Java we have:
Hash<User, Boolean> mapUserToSelected = new HashMap<>()
And in Freemarker we have:
<#list mapUserToSelected as user, selected>
<p>${user.name}</p>
<p>${selected?c}</p>
</#list>
However, we got "The following has evaluated to null or missing" for the <p>${selected?c}</p> and I am sure that it exists in the map.
If I use String for keys of hash Hash<String, Boolean> mapUserToSelected = new HashMap<>() it will work.
Is the key of hash needed to be String only?
The object mapUserToSelected can contain any Object as key, the built in ?c will convert a string to numeric. Not sure why you're applying it to Boolean.
Also, not to confuse ourselves: When we want to send the object mapUserToSelected from Logic (controller) to UI then tha's when the key must be String based on the definition of TemplateHashModel.
Example:
ModelAndView mainView = new ModelAndView();
mainView.getModel().put("usersMap", mapUserToSelected );
But the object itself can contain anything, you can get the keys list using mapUserToSelected?keys then access each the list of the keys using ?index if you are interested in the value of every key.

How to convert list of map list<map<string, object>> to list of value of map map<string,list<string>> using steam api java 8

I have a list of map. The map contains string as key & object as value. Most likely values also string. I want to group by one value so that I will get a set of value as key and another group of unique values as a list. Actually, list of map is couchbase select data.
e.g:
[{"id":"1", "status":"pending"},{"id":"2", "status":"download"},{"id":"3", "status":"pending"},{"id":"4", "status":"pending"}, {"id":"5", "status":"ready"},{"id":"6", "status":"download"}] => {"pending":["1","3","4"], "download":["2","6"], "ready":["5"]}
Try this out. Notice that my values are Strings NOT Objects as yours. In your case you need to cast it explicitly to String like so,
s -> (String) s.get("status")
s -> (String) s.get("id")
Map<String, List<String>> idsByStatus = listOfMap.stream().collect(
Collectors.groupingBy(s -> s.get("status"), Collectors.mapping(s -> s.get("id"), Collectors.toList())));

Whats the key value in the Cache populated via #Cachable

I have a cache thats populated via #Cacheable as follows
#Cacheable(value = "accountGroupCache")
public List<Acc> getAccInfo(int groupId, String user)
I would like to know what will be the key value pair for this cache? I am using ehcahe to do the caching.
The key will be based on the parameters to your getAccInfo() method. The value is going to be the List<Acc> returned by your method.
According to the docs:
28.3.1.1 Default Key Generation
Since caches are essentially key-value stores, each invocation of a
cached method needs to be translated into a suitable key for cache
access. Out of the box, the caching abstraction uses a simple
KeyGenerator based on the following algorithm:
If no params are given, return 0.
If only one param is given, return that instance.
If more the one param is given, return a key computed from the hashes of all parameters.
Looking at the source code for DefaultKeyGenerator, this is how it computes "a key computed from the hashes of all parameters":
int hashCode = 17;
for (Object object : params) {
hashCode = 31 * hashCode +
(object == null ? NULL_PARAM_KEY : object.hashCode());
}

LevelDB key,value from csv

I've huge csv file database of ~5M rows having below fields
start_ip,end_ip,country,city,lat,long
I am storing these in LevelDB using start_ip as the key and rest as the value.
How can I retrieve records for keys where
( ip_key > start_ip and ip_key < end_ip )
Any alternative solution.
I assume that your keys are the hash values of the IP and the hashes are 64-bit `unsigned' integers, but if that's not the case then just modify the code below to account for the proper keys.
void MyClass::ReadRecordRange(const uint64 startRange, const uint64 endRange)
{
// Get the start slice and the end slice
leveldb::Slice startSlice(static_cast<const char*>(static_cast<const void*>(&startRange)), sizeof(startRange));
leveldb::Slice endSlice(static_cast<const char*>(static_cast<const void*>(&endRange)), sizeof(endRange));
// Get a database iterator
shared_ptr<leveldb::Iterator> dbIter(_database->NewIterator(leveldb::ReadOptions()));
// Possible optimization suggested by Google engineers
// for critical loops. Reduces memory thrash.
for(dbIter->Seek(startSlice); dbIter->Valid() && _options.comparator->Compare(dbIter->key(), endSlice)<=0); dbIter->Next())
{
// get the key
dbIter->key().data();
// get the value
dbIter->value().data();
// TODO do whatever you need to do with the key/value you read
}
}
Note that _options are the same leveldb::Options with which you opened the database instance. You want to use the comparator specified in the options so that the order in which you read the records is the same as the order in the database.
If you're not using boost or tr1, then you can either use something else similar to the shared_ptr or just delete the leveldb::Iterator by yourself. If you don't delete the iterator, then you'll leak memory and get asserts in debug mode.

Design a Data Structure for web server to store history of visited pages

The server must maintain data for last n days. It must show the most visited pages of the current day first and then the most visited pages of next day and so on.
I'm thinking along the lines of hash map of hash maps. Any suggestions ?
Outer hash map with key of type date and value of type hash map.
Inner hash map with key of type string containing the url and value of type int containing the visit count.
Example in C#:
// Outer hash map
var visitsByDay =
new Dictionary<DateTime, VisitsByUrl>(currentDate, new VisitsByUrl());
...
// inner hash map
public class VisitsByUrl
{
public Dictionary<string, int> Urls { get; set; }
public VisitsByUrl()
{
Urls = new Dictionary<string, int>();
}
public void Add(string url)
{
if (Urls[url] != null)
Urls[url] += 1;
else
Urls.Add(url, 1);
}
}
You can keep a hash for each day that has will of the type :-
And a queue of length n. which will have these hashes for each day. Also you will store seperate hash totalHits which will sum all of these
Class Stats {
queue< hash<url,hits> > completeStats;
hash<url,hits> totalStats;
public:-
int getNoOfTodayHits(url) {
return completeStats[n-1][url];
}
int getTotalStats(url) {
return totalStats[url];
}
void addAnotherDay() {
// before popping check if the length is n or not :)
hash<url,hits> lastStats = completeStats.pop();
hash<url,hits> todayStats;
completeStats.push_back(todayStats);
// traverse through lastStats and decrease the value from total stats;
}
// etc.
};
We can have a combination of Stack & Hash Map.
We can create an Object of URL and timestamp, then push it onto the Stack.
Most recent visited Url will be on the top.
We can use the timestamp combined with URL to create a key, which is mapped to the count of visited Urls.
In order to display most visited pages in chronological order, we can pop the stack, create a key and fetch the count associated with the Url. Sort them while displaying.
Time complexity: O(n) + Sort time (depends on the number of pages visited)
This depends on what you want. For example, do you want to store the actual data for the pages in the history, or just the URLs? If somebody has visited a page twice, should it show up twice in the history?
A hash map would be suitable if you wanted to store the data for a page, and wanted each page to show up only once.
If, as I'd consider more likely, you want to store only the URLs, but want each stored multiple times if it was visited more than once, an array/vector would probably make more sense. If you expect to see a lot of duplication of (relatively) long URLs, you could create a set of URLs, and for each visit store some sort of pointer/index/reference to the URL in question. Note, however, that maintaining this can become somewhat non-trivial.

Resources