I need a way to cache searches on my node.js app. I had an idea that uses redis but I am not sure how to implement it.
What I want to do is have a hard limit on how many searches are going to be cached because I have a limited amount of RAM. For each search, I want to store the search query and the corresponding search results.
Lets say that my hard limit on the number of searches cached is 4. Each search query is a box in the following diagram:
If there was a new search that was not cached, the new search gets pushed to the top, and the search query at the bottom gets removed.
But if there was a search that was cached, the cached search query gets removed from its position and added to the top of the cache. For example, if search 3
was searched.
By doing this, I use a relatively same amount of memory while the most searched queries would always float around in the cache and less popular searches would go through the cache and get removed.
My question is, how exactly would I do this? I thought I may have been able to do it with lists, but I am not sure how you can check if a value exists in a list. I also thought I might be able to do this with sorted sets, where I would set the score of the set to be the index, but then if a search query gets moved within the cache, I would need to change the score of every single element in the set.
Simplest for you is to spin up new redis instance just for handling search cache. For this instance you can set max memory as needed. Then you will set maxmemory-policy
for this instance to allkeys-lru
. By doing this, redis will automatically delete least recently used cache entry (which is what you want). Also, you will be limiting really by memory usage not by max number of cache entries.
To this redis instance you will then insert keys as: search:$seachterm => $cachedvalue
and set expire for this key for few minutes for example (so you don't serve stale answers). By doing this redis will do hard work for you.
You definitely want to use a sortedset
here's what you do:
1st query: select the top element from your sortedset: zrevrange(0,1) WITHSCORES
2nd query: in a multi, do: A. insert your element with the score that you retrieved + 1. If that element exists in the list already it will simply be rescored and not added twice.
B. zremrankbyrank. I haven't tested this, but I think the parameters you want are (0,-maxListSize)
Take a look at ZREMRANGEBYRANK . You can limit the amount of data in your sorted set to a given size.