我需要使用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 |
+------------------------+--------------+
答案 0 :(得分:0)
我对查询很确定。但是,您可以使用this tool并设计要修改查询的任何表达式。
我的猜测是,这可能会有所帮助:
^(?!d|b|www3).*
您可以使用OR (?!d|b|www3)
列出要排除在列表中的任何域。
您可以在此link中可视化您的表情:
您可能想将所需的URL添加到an expression similar to:
^(sam|www.google|1.11|www.sample|www3.sample).*
答案 1 :(得分:0)
所以,我找到了解决方案。 Redshift不支持基于列的正则表达式,因此替代方法是使用Python UDF。
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;