当前位置: 首页 > 面试题库 >

Redis或Mongo用于确定数字是否在范围内?

薄兴昌
2023-03-14
问题内容

我需要一种方法来快速检查IP地址是否属于许多禁止的IP范围之一。

我目前使用iptables检查IP是否落在指定范围内。这在几千个范围内都可以正常工作,但是这个数字将急剧增加到几十万,并且还将继续增长。

我当前的简单地向iptables添加新规则的方法的另一个问题是重复项的数量不断增加。

在将IP或范围添加到规则集之前,我需要一种有效的方法来检查IP或范围是否属于现有(较大)范围。

Ruby是我最熟悉的语言,但是对于越来越多的范围,哪种数据结构将是最佳选择?

我想出的一个解决方案是使用Redis集或MongoDB将单个IP存储为整数,然后简单地检查IP是否存在于集内……但是我的直觉告诉我,必须有一种更聪明的方法。

如果我要将IP转换为整数并存储范围,那么遍历范围以查看现有的较大范围是否已包含新IP或范围的最佳方法是什么?

最后说明:速度比内存成本更为重要。


问题答案:

与上一幅海报相反,我认为您不能通过使用朴素索引来获得O(log
n)复杂性。让我们以mongodb为例。您可以定义两个索引(用于范围的开始和结束属性),但是mongodb仅使用一个索引来解决给定查询。因此它将不起作用。现在,如果您使用涉及范围的开始和结束属性的单个复合索引,则复杂度将是对数的,以找到要检查的第一个范围,但是,它将变得线性,以找到与查询匹配的最后一个范围。最糟糕的情况是O(n),并且当所有存储的范围都与输入重叠时,您就会拥有它。

附带说明一下,如果您知道要做什么,则使用Redis排序集可以模拟排序索引(复杂度为O(log
n))。Redis不仅仅是一个简单的键值存储。使用跳过列表实现Redis排序集,并且得分和值都用于比较项目。

为了解决这种问题,需要专用的索引结构。您可能需要看一下:

http://en.wikipedia.org/wiki/Segment_tree

http://en.wikipedia.org/wiki/Interval_tree

如果关注的是速度与空间的关系,则使索引变平可能会很有趣。例如,让我们考虑以下范围(仅使用整数来简化讨论):

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

可以建立索引非重叠段的稀疏结构。

0  []
2  [A C]
4  [A C B]
7  [A C D]
9  [C D]
10 [D]
11 []

每个条目都包含一个非重叠段的下限作为键,并包含匹配范围的列表或集合作为一个值。条目应使用已排序的容器(树,跳过列表,btree等)建立索引。

要找到匹配5的范围,我们寻找小于或等于5的第一个条目(在本示例中为4),并提供了范围列表([ACB])

使用这种数据结构,查询的复杂度实际上为O(log n)。但是,构建和维护它并非易事(且昂贵)。它可以与mongodb和Redis一起实现。

这是Redis的示例:

> rpush range:2 2-8 2-9
(integer) 2
> rpush range:4 2-8 2-9 4-6
(integer) 3
> rpush range:7 2-8 2-9 7-10
(integer) 3
> rpush range:9 2-9 7-10
(integer) 2
> rpush range:10 7-10
(integer) 1
> zadd range_index 0 range:0 2 range:2 4 range:4 7 range:7 9 range:9 10 range:10
(integer) 6
> zrevrangebyscore range_index 5 0 LIMIT 0 1
1) "range:4"
> lrange range:4 0 -1
1) "2-8"
2) "2-9"
3) "4-6"


 类似资料:
  • 我目前有一个数字列表,我想知道这些数字中的哪些在一定范围内,以及它们在列表中的位置是什么。 我对巴黎相当陌生,所以我不知道该怎么做。 举一个简单的例子来说明我在做什么: 查找位于 0.05 和 0.15 范围内的数字 1 到 20 的逆函数 我列了一个清单,像这样: 从这里,我想要所有i的列表,以便A[i]在该范围内。 但我不知道如何从这里开始。我尝试了一些简单的if/for语句,但这些都不起作用

  • 检查给定的数字是否在给定范围内。 使用算术比较来检查给定的数字是否在指定的范围内。如果没有指定第三个参数 end ,则范围被认为是从 0 到 start 。 const inRange = (n, start, end = null) => { if (end && start > end) end = [start, (start = end)][0]; return end == nu

  • 对于我的Java类,我正在编写一个小程序,首先选择一个介于1和100之间的数字。然后,它会提示用户开始猜测正确的。如果用户对的猜测过高或过低,程序会打印出一个新范围,供他们在该范围内进行猜测。如果用户输入或,程序只需重新要求用户输入,但不会以任何方式更改范围。 示例输出(当机密号为20时)如下所示: 该项目似乎已经基本完成,但只有一个例外。其中一个要求是,当用户键入的超出我们给定的1和100范围时

  • 有没有办法确定一个数字是否在两个特定数字的范围内,如果这些数字正在变化?例如: 确定 num3 是否介于 num1 和 num2 之间是相当容易的。但是,假设 num1 和 num2 在程序运行期间动态变化: 其他一切都保持不变。现在,与以前相同的算法将不再有效。有没有一种优雅的方法来检查数字是否使用动态变化的最大值和最小值的范围?

  • 这是我的密码: 基本上,我正在编写一个程序来计算考试分数,但是首先用户必须输入0-100之间的分数。 如果用户输入的测试分数超出该范围,我希望程序告诉用户重写该数字。我不希望程序以错误结束。我该怎么做?

  • 问题内容: 有没有一种方法可以在不执行此冗余代码的情况下测试范围: ? 就像一个函数: 用法: ? PHP是否具有这种内置功能?还是其他方式可以做到? 问题答案: 我认为您不会获得比您的功能更好的方法。 它是干净的,易于遵循和理解的,并返回条件的结果(无混乱)。