ElasticSearch 正则表达式逻辑问题

问题描述 投票:0回答:2

我遇到了一些我似乎无法克服的 ElasticSearch 问题,特别是正则表达式查询类型。我有一个名为

test-index
的索引。其中包含带有 url 字段的文档。一个特定文档的 url 字段设置为以下内容:

https://hello-world.com/help/me

我希望能够运行一个查询,该查询将使用正则表达式将其返回到我的结果集中。这是我的查询:

  "query": {
    "bool": {
      "must": [
        {
          "bool": {
            "should": [
              {
                "regexp": {
                  "url": "*.hello-world.com/help/me/?"
                }
              }
            ]
          }
        }
      ]
    }
  }
}

基本上,我希望任何与子域、二级域、顶级域和子目录(有或没有最后的

/
)匹配的 url 都能匹配。但是,当我运行上述查询时,结果集中未返回预期的文档。根据我对 ElasticSearch 正则表达式的了解,我还尝试了以下查询更新,但无济于事:

*.hello-world\.com\/help\/me\/?
*.hello-world\\.com\\/help\\/me\\/?
*.hello-world\\.com/help/me/?
(https?:\\/\\/)?(www\\.)?hello-world\\.com\\/help\\/me\\/?
(https?:\/\/)?(www\.)?hello-world\.com\/help\/me\/?

我真的不明白为什么这个文档没有吸引人。我已经对索引运行了精确匹配查询,并且文档以这种方式被捕获。关于 ElasticSearch 中的正则表达式查询,有什么我不明白的地方吗?我还可以采取另一条路吗?再次提前致谢!

elasticsearch opensearch
2个回答
0
投票

正则表达式

GET test-index/_search
{
  "query": {
    "regexp": {
      "url":"https?://(?:[a-zA-Z0-9-]+.)?hello-world.com\/help/me/?"
    }
  }
}

通配符

GET test-index/_search
{
  "query": {
    "wildcard": {
      "url": "*hello-world.com/help/me*"
    }
  }
}

快速提示

两者都可能很慢,因为这会增加查找匹配项所需的迭代并降低搜索性能。

尝试使用 UAX URL 电子邮件标记器对 URL 执行搜索。


0
投票

没有正则表达式和通配符的解决方案

最快的解决方案是没有

regexp
wildcard

的解决方案

URL 不是原子数据。所以应该分成几部分

将 URL 的每个部分映射为

parsed_url
对象的字段

PUT /test-index
{
    "mappings": {
        "properties": {
            "url": {
                "type": "keyword"
            },
            "parsed_url": {
                "properties": {
                    "is_parsed": {
                        "type": "boolean"
                    },
                    "protocol": {
                        "type": "keyword"
                    },
                    "host": {
                        "type": "keyword"
                    },
                    "path": {
                        "type": "keyword"
                    },
                    "query": {
                        "type": "keyword"
                    },
                    "fragment": {
                        "type": "keyword"
                    }
                }
            }
        }
    }
}

is_parsed
是解析结果。所有字段都是关键字(除了
is_parsed

文件

PUT /test-index/_bulk
{"create":{"_id":1}}
{"url":"https://sub.hello-world.com/help/me/index.php?param=value#label"}
{"create":{"_id":2}}
{"url":"https://hello-world.com/help/me"}

URL 由

update_by_query

解析
POST /test-index/_update_by_query
{
    "script": {
        "source": """
            String[] urlItems = new String[]{'protocol', 'host', 'path', 'query', 'fragment'};
            int[] urlItemIndices = new int[]{2, 4, 5, 7, 9};
            
            String url = ctx['_source']['url'];
            Pattern regexp = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/;
            Matcher m = regexp.matcher(url);
            
            ctx['_source']['parsed_url.is_parsed'] = m.matches();
            if (m.matches()) {
                for (int i = 0; i < urlItems.length; i++) {
                    ctx['_source']['parsed_url.' + urlItems[i]] = m.group(urlItemIndices[i]);
                }
            }
        """
    }
}

在这个answer

中找到了正则表达式

是时候去寻找了。每个部分都可以通过单独的

term
查询找到。解析后的 URL 通过
filter

选择
GET /test-index/_search?filter_path=hits.hits
{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "parsed_url.host": "hello-world.com"
                    }
                },
                {
                    "term": {
                        "parsed_url.path": "/help/me"
                    }
                }
            ],
            "filter": [
                {
                    "term": {
                        "parsed_url.is_parsed": "true"
                    }
                }
            ]
        }
    }
}

回应

{
    "hits" : {
        "hits" : [
            {
                "_index" : "test-index",
                "_type" : "_doc",
                "_id" : "2",
                "_score" : 1.3862942,
                "_source" : {
                    "parsed_url.host" : "hello-world.com",
                    "parsed_url.path" : "/help/me",
                    "parsed_url.query" : null,
                    "parsed_url.is_parsed" : true,
                    "url" : "https://hello-world.com/help/me",
                    "parsed_url.protocol" : "https",
                    "parsed_url.fragment" : null
                }
            }
        ]
    }
}

可能的改进是提取子域、域和域区域

Java 有

java.net.URL
类来解析 URL,但 Painless 无法为我的 Elasticsearch 识别它

© www.soinside.com 2019 - 2024. All rights reserved.