Elastic/OpenSearch:查询复合 IP 范围,如 123。[16-31].0.*

Elastic/OpenSearch: query composite IP range like 123.[16-31].0.*

提问人:Su Zirboni 提问时间:11/1/2023 更新时间:11/1/2023 访问量:25

问:

我想运行一个查询来过滤掉 IP 范围,例如(包括 16 和 31)。一般示例:123.[16-31].0.*

GET _search
{
  "query": {
    "bool": {
      "must": {
        "match_phrase": {
          "somefield": "somevalue"
        }
      },
      "must_not": {
        ... ip filter ...
      }
    }
  }
}

我该如何编写该部分?must_not

一个似乎有效的解决方案是将 16 个范围放在 :must_not

      "must_not": [
        {
          "range": {
            "host.ip": {
              "gte": "123.16.0.0",
              "lte": "123.16.0.255"
            }
          }
        },
.... same for 17 until 30
        {
          "range": {
            "host.ip": {
              "gte": "123.31.0.0",
              "lte": "123.31.0.255"
            }
          }
        }
      ]

但是需要花很多时间才能打下来。我很想使用正则表达式,例如:

      "must_not": {
        "regexp": {
          "host.ip": "123.(1[6-9]|2[0-9]|30|31).0.*"
        }
      }

但显然它失败了.Can only use regexp queries on keyword and text fields - not on [host.ip] which is of type [ip]

Elasticsearch 范围 IPv4 OpenSearch

评论


答:

0赞 imotov 11/1/2023 #1

生成 16 个范围是最快的解决方案。但是,如果您不运行此请求太多次,并且更愿意用一些 CPU 时间换取程序员的时间,则可以使用运行时映射将字段转换为字段。他们的方式,您将能够像对待任何其他文本字段一样对待此字段。因此,您可以执行以下操作:ipkeyword

DELETE test
PUT test
{
  "mappings": {
    "properties": {
      "host": {
        "properties": {
          "ip": {
            "type": "ip"
          }
        }
      }
    }
  }
}

POST test/_bulk?refresh
{"index":{}}
{"host":{"ip":"123.16.0.1"}}
{"index":{}}
{"host":{"ip":"123.16.1.0"}}
{"index":{}}
{"host":{"ip":"124.16.0.1"}}

POST test/_search
{
  "runtime_mappings": {
    "host.ip_string": {
      "type": "keyword",
      "script": {
        "source": "emit(doc['host.ip'].value);"
      }
    }
  },
  "query": {
    "bool": {
      "must_not": [
        {
          "regexp": {
            "host.ip_string": "123.(1[6-9]|2[0-9]|30|31).0.*"
          }
        }
      ]
    }
  }
}

或者更好的是这样的:

POST test/_search
{
  "runtime_mappings": {
    "host.ip_string": {
      "type": "keyword",
      "script": {
        "source": "emit(doc['host.ip'].value);"
      }
    }
  },
  "query": {
    "bool": {
      "must_not": [
        {
          "regexp": {
            "host.ip_string": "123\\.<16-31>\\.0\\..*"
          }
        }
      ]
    }
  }
}

评论

0赞 Su Zirboni 11/2/2023
感谢您@imotov的回答!对我有用的折衷方案是在硬编码查询中使用 16 个范围,并在手动测试时使用运行时映射转换......不能说我喜欢在一个文件中看到 16 个范围,但有效的就是有效的!
0赞 imotov 11/2/2023
那么,你介意@SuZirboni把这个问题标记为答案吗?