Vlad Dumitrache
Vlad Dumitrache

Reputation: 300

Checking if IP falls within a range with Redis

I am interested in using Redis to check if a IP address (converted into integer) falls within a range of IPs. It is very likely that the ranges will overlap.

I have found this question/answer, although I am not able to fully understand the logic behind it.

Thank you for your help!

Upvotes: 2

Views: 1145

Answers (2)

Ofir Luzon
Ofir Luzon

Reputation: 10907

EDIT - Since I got a downvote (a comment to explain why would be nice), I've removed some clutter from my answer.

@DidierSpezia answer in your linked question is a good answer, but it becomes hard to maintain if you are adding/removing ranges.

However it is not trivial (and expensive) to build and maintain it.

I have an answer that is easier to maintain, but it could get slow and memory expensive to compute with many ranges as it requires cloning a set of all ranges.

You need to save all ranges twice, in two sets. The score of each range will be its border values.

Going with the sets in @DidierSpezia example:

A 2-8
B 4-6
C 2-9
D 7-10 

Your two sets will be:

ZADD ranges:low 2 "2-8" 4 "4-6" 2 "2-9" 7 "7-10"
ZADD ranges:high 8 "2-8" 6 "4-6" 9 "2-9" 10 "7-10"

To query to which ranges a value belongs, you need to trim the ranges that the lower border is higher than the queried value, and trim the ranges that the higher border is lower.

The most efficient way I can think of is cloning one of the sets, trimming one of it sides by the rules gave above, changing the scores of the ranges to reflect the other border and then trim the second side.

Here's how to find the ranges 5 belongs to:

    ZUNIONSTORE tmp 1 ranges:low
    ZREMRANGEBYSCORE tmp (5 +inf 
    ZINTERSTORE tmp 2 tmp ranges:high WEIGHTS 0 1
    ZREMRANGEBYSCORE tmp -inf (5 
    ZRANGE tmp 0 -1

Upvotes: 2

thepirat000
thepirat000

Reputation: 13114

In this discussion, Dvir Volk and @antirez suggested to use a sorted set in which each entry represent a range, and has the following form:

Member = "min-max" range

Score = max value

For example:

ZADD z 10 "0-10"
ZADD z 20 "10-20"
ZADD z 100 "50-100"

And in order to check if a value falls within a range, you can use ZRANGEBYSCORE and parse the member returned.

For example, to check value 5:

ZRANGEBYSCORE z 5 +inf LIMIT 0 1

this will return the "0-10" member, and you only need to parse the string and validate if your value is in between.

To check value 25:

ZRANGEBYSCORE z 25 +inf LIMIT 0 1

will return "50-100", but the value is not between that range.

Upvotes: 1

Related Questions