Groovy: MultiValueMap with Maps as keys
Heres's something I'm thinking about doing, and I want to know if you think it's a good idea or not.
I retrieve a bunch of rows from a database, which in groovy gives me a list of lists something like:
[
[ 'Dog', 'M', 'Mutt', 'Sammy' ],
[ 'Cat', 'F', 'Siamese', 'Pat' ],
[ 'Dog', 'M', 'Husky', 'Taco' ],
...
]
Not my real data set but you get the idea.
Since I will be pulling this data pretty frequently and doing some analysis to it before presenting it in the UI, I want to store it in a MultiValueMap keyed by groovy maps (i.e. LinkedHashMaps), so I can retrieve the bits and pieces of it that I need, without going to DB every time. It's kind of a cache of a subset of data that comes from several tables (more complex than the animals data above).
I would be able to use it like this:
animals.get([species:'Dog', gender:'M'])
returns:
[['Sammy', 'Mutt'], ['Taco', 'Husky'] ]
I think I have some idea how to implement it, so I'm not really looking for that (though if you have a novel suggestion please share). I'm mainly looking for somebody to tell me that either this won't work for some reason, or it sounds fine, or it won't scale, etc. Or maybe there's some easier way to get a similar functionality. One more consideration: the whole data set can sometimes be sorta large-ish, e.g. few 100k records. If not this, what's a good way to deal with it, aside from hit th开发者_如何学Ce DB every time?
I realize there are lots of key/value caching solutions around, but I don't think I need anything so heavy duty for what I'm doing. It is just a small webapp with pretty low usage, mostly internal to the company I'm building it for.
If the subset of values you're using is static/deterministic, I'd just turn that into a string and use that as the key in your map. So instead of animals.get([species:'Dog', gender:'M'])
, I'd use animals.get('species:Dog:gender:M')
.
I know you said that you were thinking that a key-value store is too heavyweight, but this is also the perfect kind of use case for Redis, which can natively store things like hash maps.
The kind of cache that you're talking about storing is exactly how we use it in production where I work, and it's been great. It's very fast, and makes it available to all running processes without having to have a singleton, or multiple copies of very large maps. Cache invalidation is also something you'd need to think about that redis helps to solve.
You can use the grails-redis plugin to memoize your database calls, so that it automatically checks redis first to see if it's in the cache, if it isn't, it queries the database and sticks it in the cache before returning it. See the docs on github for more details/examples.
return redisService.memoizeHash('species:Dog:gender:M') {
// database call that returns object, then you turn that into hash
Dog d = Dog.findBy...
[species: d.species, gender: d.gender, breed: d.breed, name: d.name, ...]
}
This way, it queries the database only if Redis doesn't already have it in cache. On cache miss, it saves the return value in redis at the specified key.
(Disclaimer, I'm the author of the grails-redis plugin, so I've got some bias)
Using a mutable Map as a key is a really bad idea, because if the key changes then it will not be found.
精彩评论