如何在Redshift中使用动态正则表达式提取域名?

时间:2019-05-13 02:59:49

标签: regex postgresql url amazon-redshift

我需要使用Redshift PostgreSQL从URL中提取域名。示例:从“ www.google.com”提取“ google.com”。我的数据集中的每个网址都有不同的顶级域名(TLD)。我的方法是先将匹配的TLD加入数据集中,然后使用正则表达式提取“ first_string.TLD”。在Redshift中,我收到错误消息“该模式必须是有效的UTF-8文字字符表达式”。有办法解决吗?

我的数据集样本:

 +---+------------------------+--------------+
 | id|    trimmed_domain      |  tld         |
 +---+------------------------+--------------+
 | 1 | sample.co.uk           | co.uk        |
 | 2 | www.sample.co.uk       | co.uk        |
 | 3 | www3.sample.co.uk      | co.uk        |
 | 4 | biz.sample.co.uk       | co.uk        |
 | 5 | digital.testing.sam.co | co           |
 | 6 | sam.co                 | co           |
 | 7 | www.google.com         | com          |
 | 8 | 1.11.220               |              |
 +---+------------------------+--------------+ 

我的代码:

 SELECT t1.extracted_domain, COUNT(DISTINCT(t1.id))
 FROM(
     SELECT 
     d.id,
     d.trimmed_domain,
     CASE 
     WHEN d.tld IS null THEN d.trimmed_domain ELSE 
      regexp_replace(d.trimmed_domain,'(.*\.)((.[a-z]*).*'||replace(tld,'.','\.')||')','\2') 
     END AS "extracted_domain" 
     FROM dataset d
     )t1
  GROUP BY 1
  ORDER BY 2;

预期输出:

 +------------------------+--------------+
 |    extracted_domain    |  count       |
 +------------------------+--------------+
 | sample.co.uk           | 4            |
 | sam.co                 | 2            |
 | google.com             | 1            |
 | 1.11.220               | 1            |
 +------------------------+--------------+

3 个答案:

答案 0 :(得分:0)

我对查询很确定。但是,您可以使用this tool并设计要修改查询的任何表达式。

我的猜测是,这可能会有所帮助:

^(?!d|b|www3).*

您可以使用OR (?!d|b|www3)列出要排除在列表中的任何域。

enter image description here

RegEx电路

您可以在此link中可视化您的表情:

enter image description here


您可能想将所需的URL添加到an expression similar to

^(sam|www.google|1.11|www.sample|www3.sample).*

enter image description here

答案 1 :(得分:0)

所以,我找到了解决方案。 Redshift不支持基于列的正则表达式,因此替代方法是使用Python UDF。

  1. 将tld列更改为正则表达式模式。part1

  2. 逐行查找并使用正则表达式模式列提取域名。 part2

  3. 按extracted_domain分组并计数用户。

SQL查询如下:

CREATE OR REPLACE function extractor(col_domain varchar)
RETURNS varchar
IMMUTABLE AS $$
    import re
    _regex = ''
    for domain in col_domain:
        if domain is None:
           continue
        else:
           _regex += r'{}'.format(domain)
    domain_regex = r'([^/.]+\.({}))'.format(_regex)
    return domain_regex
$$ LANGUAGE plpythonu;

CREATE OR REPLACE FUNCTION regex_match(in_pattern varchar, input_str varchar)
RETURNS varchar
IMMUTABLE AS $$
    import re
    if in_pattern == '':
        a = str(input_str)
    else: 
        a= str(re.search(in_pattern, input_str).group())
    return a
$$ LANGUAGE plpythonu;

SELECT 
t2.extracted_domain,
COUNT(DISTINCT(t2.id)) AS "Unique Users"
FROM(
    SELECT 
    t1.id,
    t1.trimmed_domain,
    regex_match(t1.regex_pattern, t1.trimmed_domain) AS "extracted_domain"
    FROM(
        SELECT 
        id,
        trimmed_domain,
        CASE WHEN tld is null THEN '' ELSE extractor(tld) END AS "regex_pattern"
        FROM dataset
        )t1
    )t2
GROUP BY 1
ORDER BY 2 DESC
LIMIT 10;  

在大型数据集上,Python UDF似乎很慢。因此,我愿意提出改进查询的建议。

答案 2 :(得分:0)

如果您知道要从域中删除的前缀,那么为什么不仅仅排除这些前缀呢?以下查询只是从域名中删除已知的www / http / etc前缀,并计算归一化的域名。

SELECT COUNT(*) from 
  (select REGEXP_REPLACE(domain, '^(https|http|www|biz)') FROM domains) 
GROUP BY regexp_replace;