Stal is a small library (54 lines of code at the time of writing this article) that abstracts multi-step set operations in Redis. To illustrate what it does, consider the trivial example of computing the difference between one set and the intersection of two other sets. This is what you can do with Redis:
SINTERSTORE temp1 A B SDIFF C temp1
The first command computes the intersection of sets
B, then stores the result in
The next command computes the difference between sets
temp1 and returns the result. The goal is met, but
you may want to delete the
temp1 key as it’s no longer
needed. In addition, for atomicity, you may want to wrap those
commands in a
EXEC call. This is
what we would have so far:
MULTI SINTERSTORE temp1 A B SDIFF C temp1 DEL temp1 EXEC
Finally, for performance, you may want to pipeline all those commands. This is what you would end up with if you use a client that supports pipelining:
redis.queue("MULTI") redis.queue("SINTERSTORE", "temp1", "A", "B") redis.queue("SDIFF", "C", "temp1") redis.queue("DEL", "temp1") redis.queue("EXEC") redis.commit
I’m using Redic in the example.
This is all very simple and efficient, and building these operations by hand is a no-brainer. If you want to create more complex queries, and particularly if you want to build them on the fly, it can get a bit more complicated.
With Stal, you can build that query with an s-expression:
Stal.solve(redis, [:SDIFF, "C", [:SINTER, "A", "B"]])
Stal takes care of pipelining the commands in a
EXEC block, as well as generating
and deleting any temporary keys. But most importantly, it makes it
very easy to incrementally build complex queries.
Ohm is an object-hash mapper that is almost as old as Redis itself. It has support for complex queries, and until recently it shipped with code to ease that process. By relying on Stal, its code went from 600 to 516 lines of code. Stal itself is tiny, just 54 lines of code, so the net change for Ohm was 30 lines less.
Stal can be used directly or as a valuable building block for other libraries.