Elastic/OpenSearch如何高效排除123.[16-31].0.*这类IP范围
Elastic/OpenSearch 过滤指定IP范围的简洁查询方案
需求背景
需要在查询中过滤掉123.[16-31].0.*(包含16和31)的IP范围,现有通用查询结构如下:
GET _search { "query": { "bool": { "must": { "match_phrase": { "somefield": "somevalue" } }, "must_not": { ... ip filter ... } } } }
目前通过16个独立的range条件可以实现需求,但写法繁琐;尝试正则查询因host.ip为IP类型字段而报错(仅keyword/text类型支持regexp查询)。
优化方案
方案1:脚本查询(简洁直观)
利用IP类型字段的脚本API,直接提取IP段进行判断,无需重复编写多个range:
GET _search { "query": { "bool": { "must": { "match_phrase": { "somefield": "somevalue" } }, "must_not": { "script": { "script": { "source": "def ip = doc['host.ip']; return ip.getSegment(1) >= 16 && ip.getSegment(1) <= 31 && ip.getSegment(2) == 0;" } } } } } }
- 说明:
getSegment(n)方法按索引提取IP段(索引从0开始,第二段对应索引1,第三段对应索引2),直接判断第二段在16-31区间且第三段为0即可精准匹配目标IP范围。
方案2:范围+脚本组合查询(兼顾性能)
如果担心脚本查询的性能,可以用单个range覆盖第二段16-31的所有IP,再通过脚本限定第三段为0,减少查询条件数量:
GET _search { "query": { "bool": { "must": { "match_phrase": { "somefield": "somevalue" } }, "must_not": [ { "bool": { "filter": [ { "range": { "host.ip": { "gte": "123.16.0.0", "lte": "123.31.255.255" } } }, { "script": { "script": { "source": "doc['host.ip'].getSegment(2) == 0;" } } } ] } } ] } } }
- 说明:先用range缩小IP范围到
123.16.0.0-123.31.255.255,再通过脚本筛选出第三段为0的IP,避免遍历全量数据。
为什么正则查询失败?
Elasticsearch/OpenSearch的regexp查询仅支持keyword和text类型字段,host.ip属于IP类型字段,不支持正则匹配语法,因此会触发报错。
内容的提问来源于stack exchange,提问作者Su Zirboni
相关产品推荐
相关产品推荐

