给出两个表,我想对所有IP进行查找,并找到它所属的网络:

我有两张大桌子:

clients

以及以下网络:

networks

关于ClientIP(第一个表),我想用ip_address来转换整列

关于第二列(第二个表),我想用ip_network来转换整个列

大概是这样的:

import ipaddress

network = ipaddress.ip_network('99.96.0.0/13')
ip_obj = ipaddress.ip_address('99.87.29.96')
print(ip_obj in network)

然后执行应用函数,但它非常慢,特别是对于这种大小的表.

我注意到在像KQL这样的一些数据库中,有一个内置的支持: ipv4-lookup

polars中有没有内置的对iplookup的支持?还是在pyarrows? 有什么建议吗?

推荐答案

假设网络数据帧的IpCidr个数据块不重叠,则可以将IPv4地址转换为pl.Int64并获得CIDR块内的最大值.

仅使用pl.Expr将IPv4地址转换为pl.Int64的函数

import polars as pl

def ip_addr4_int64_expr(ipv4_str_expr: pl.Expr):
    return (
        ipv4_str_expr.str.split(".")
        .list.eval(
            pl.element().cast(pl.Int64)
            * (2 ** (8 * (pl.element().cumcount(reverse=True)))).cast(pl.Int64)
        )
        .list.sum()
    )

通过获取可用主机的数量并将其添加到基本的IPV4‘S Int64表示法中,可以从CIDR的前缀派生出一系列地址.

cidr_split_ipv4_expr = pl.col("IpCidr").str.split("/").list.get(0)
cidr_prefix_expr = pl.col("IpCidr").str.split("/").list.get(1).cast(pl.Int64)

ip_cidr_df = ip_cidr_df.with_columns(
    ip_addr4_int64_expr(cidr_split_ipv4_expr).alias("ip_addr4_int64"),
    (
        ip_addr4_int64_expr(cidr_split_ipv4_expr)
        - 1
        + ((2 ** (32 - cidr_prefix_expr)).cast(pl.Int64))
    ).alias("cidr_ip_max"),
)

client_df = client_df.with_columns(
    ip_addr4_int64_expr(pl.col("ClientIP")).alias("ip_addr4_int64"),
)

使用join_asof可以进行范围查找.然后将返回的高于最大IP范围的值设置为空.

client_df = (
    client_df.sort("ip_addr4_int64")
    .join_asof(ip_cidr_df.sort("ip_addr4_int64"), on="ip_addr4_int64")
    .select(
        "ClientIP",
        "Timestamp",
        pl.when(pl.col("ip_addr4_int64") <= pl.col("cidr_ip_max"))
        .then(pl.col("Info"))
        .alias("Info"),
    )
)

例如:

ip_cidr_df = pl.DataFrame(
    {
        "IpCidr": [
            "99.96.0.0/13", "99.88.0.0/13", "1.0.136.0/22", "1.0.128.0/21",
            "1.0.0.0/24", "10.0.0.0/8", "127.0.0.0/8", "172.16.0.0/12",
            "192.168.0.0/16",
        ],
        "Info": [
            "ATT-INTERNET4", "ATT-INTERNET4", "TOT-NET TOT Public Company Limit", 
            "TOT-NET TOT Public Company Limit", "CLOUDFLARENET", "The 10.0.0.0/8 Range",
            "The 127.0.0.0/8 Range", "The 172.16.0.0/12 Range", "The 192.168.0.0/16 Range",
        ],
    }
)

client_df = pl.DataFrame(
    {
        "Timestamp": [
            "2023-06-01 00:00:00", "2023-06-01 00:00:00", "2023-06-01 00:00:00", 
            "2023-06-01 00:00:00", "2023-06-30 23:59:00", "2023-06-30 23:59:00",
            "2023-06-30 23:59:00",
        ],
        "ClientIP": [
            "1.0.0.14", "99.96.1.5", "99.87.29.96", "10.0.0.1", "127.0.0.1", "172.16.0.1", "192.168.0.1",
        ],
    }
)

输出:

shape: (7, 3)
┌─────────────┬─────────────────────┬──────────────────────────┐
│ ClientIP    ┆ Timestamp           ┆ Info                     │
│ ---         ┆ ---                 ┆ ---                      │
│ str         ┆ str                 ┆ str                      │
╞═════════════╪═════════════════════╪══════════════════════════╡
│ 1.0.0.14    ┆ 2023-06-01 00:00:00 ┆ CLOUDFLARENET            │
│ 10.0.0.1    ┆ 2023-06-01 00:00:00 ┆ The 10.0.0.0/8 Range     │
│ 99.87.29.96 ┆ 2023-06-01 00:00:00 ┆ null                     │
│ 99.96.1.5   ┆ 2023-06-01 00:00:00 ┆ ATT-INTERNET4            │
│ 127.0.0.1   ┆ 2023-06-30 23:59:00 ┆ The 127.0.0.0/8 Range    │
│ 172.16.0.1  ┆ 2023-06-30 23:59:00 ┆ The 172.16.0.0/12 Range  │
│ 192.168.0.1 ┆ 2023-06-30 23:59:00 ┆ The 192.168.0.0/16 Range │
└─────────────┴─────────────────────┴──────────────────────────┘

注:此答案假定数据帧仅由IPv4地址组成,并且ip_cidr_df中没有重叠的CIDR块. 可以通过将IPv6地址转换为由pl.Int64组成的pl.Struct来应用相同的逻辑.

Python相关问答推荐

PyQt5如何将pyuic 5生成的Python类添加到QStackedWidget中?

Python plt.text中重叠,包adjust_text不起作用,如何修复?

计算相同形状的两个张量的SSE损失

无法使用equals_html从网址获取全文

列表上值总和最多为K(以O(log n))的最大元素数

Pythind 11无法弄清楚如何访问tuple元素

运行回文查找器代码时发生错误:[类型错误:builtin_index_or_system对象不可订阅]

通过Selenium从页面获取所有H2元素

如何让程序打印新段落上的每一行?

Python虚拟环境的轻量级使用

无法定位元素错误404

try 将一行连接到Tensorflow中的矩阵

形状弃用警告与组合多边形和多边形如何解决

如果满足某些条件,则用另一个数据帧列中的值填充空数据帧或数组

使用groupby方法移除公共子字符串

寻找Regex模式返回与我当前函数类似的结果

基于另一列的GROUP-BY聚合将列添加到Polars LazyFrame

Python 3试图访问在线程调用中实例化的类的对象

Scipy差分进化:如何传递矩阵作为参数进行优化?

有没有一种方法可以在朗肯代理中集成向量嵌入