【问题标题】:Dynamic regex search string from another table来自另一个表的动态正则表达式搜索字符串
【发布时间】:2018-06-29 11:06:03
【问题描述】:

我有两张桌子:

项目

CREATE TABLE items (
  ID int,
  TXT string,
  CODE string
);

INSERT INTO items VALUES (1,'AA BB CC','ZZ-100');
INSERT INTO items VALUES (2,'BB CC DD','ZZ-200');
INSERT INTO items VALUES (3,'AA CC EE','ZZ-300');
INSERT INTO items VALUES (4,'EE FF GG','ZZ-400');
INSERT INTO items VALUES (5,'CC HH II','ZZ-500');

+----+----------+--------+
| id | txt      | code   |
+----+----------+--------+
| 1  | AA BB CC | ZZ-100 |
| 2  | BB CC DD | ZZ-200 |
| 3  | AA CC EE | ZZ-300 |
| 4  | EE FF GG | ZZ-400 |
| 5  | CC HH II | ZZ-500 |
+----+----------+--------+

还有regex_table

CREATE TABLE regex_table (
  ID int,
  REGEXSTR string,
  CODE string
);

INSERT INTO regex_table VALUES(1,'AA','ZZ-100');
INSERT INTO regex_table VALUES(1,'CC','ZZ-100');
INSERT INTO regex_table VALUES(2,'AA','ZZ-100');
INSERT INTO regex_table VALUES(2,'BB','ZZ-200');
INSERT INTO regex_table VALUES(2,'CC','ZZ-200');
INSERT INTO regex_table VALUES(3,'DD','ZZ-100');
INSERT INTO regex_table VALUES(3,'DD','ZZ-300');

+----+----------+--------+
| id | regexstr | code   |
+----+----------+--------+
| 1  | AA       | ZZ-100 |
| 1  | CC       | ZZ-100 |
| 2  | BB       | ZZ-200 |
| 2  | AA       | ZZ-100 |
| 2  | CC       | ZZ-200 |
| 3  | DD       | ZZ-100 |
| 3  | DD       | ZZ-300 |
+----+----------+--------+

我想将items.txt 替换为regex_table.regexstr 中的搜索字符串,具体取决于idcode 是否相等。

例如:

场景一:如果id=1,则codeZZ-100,因此搜索字符串为AA|CC

SELECT id,regexp_replace(txt,'AA|CC','<NA>'),code from items where id=1;

+----+--------------------------------------+--------+
| id | regexp_replace(txt, 'aa|cc', '<na>') | code   |
+----+--------------------------------------+--------+
| 1  | <NA> BB <NA>                         | ZZ-100 |
+----+--------------------------------------+--------+

场景2:如果id=2,则codeZZ-200,因此搜索字符串为BB|CC

SELECT id,regexp_replace(txt,'BB|CC','<NA>'),code from items where id=2;

+----+--------------------------------------+--------+
| id | regexp_replace(txt, 'bb|cc', '<na>') | code   |
+----+--------------------------------------+--------+
| 2  | <NA> <NA> DD                         | ZZ-200 |
+----+--------------------------------------+--------+

场景3:如果id=4,则codeZZ-300,因此搜索字符串为DD

SELECT id,regexp_replace(txt,'DD','<NA>'),code from items where id=3;

+----+-----------------------------------+--------+
| id | regexp_replace(txt, 'dd', '<na>') | code   |
+----+-----------------------------------+--------+
| 3  | AA CC EE                          | ZZ-300 |
+----+-----------------------------------+--------+

所以基本上搜索字符串必须是动态的,具体取决于另一个表中的 idcode

有没有办法在 Impala(重要)和 Hive(不太重要)中的一个查询中执行此操作?

注意

  1. idcode 可以是动态的并添加到两个表中(因此无法硬编码到 SQL 中)。必须查询。

  2. 我尽量避免使用JOIN。我想知道是否有办法进行子查询。

  3. 一个想法是传递一个包含连接正则表达式搜索字符串的完整字符串,然后使用一些正则表达式技巧来删除与行无关的“id”和“code”。

更新 1

我试过了:

SELECT i.id, regexp_replace(txt, pattern, '<NA>'), i.code FROM items i INNER JOIN (SELECT id, group_concat('|', regexstr) AS pattern, regex_table.code FROM regex_table GROUP BY regex_table.id, regex_table.code) r ON r.id = i.id AND r.code = i.code;

得到了这个:

+----+----------------------------------------------+--------+
| id | regexp_replace(txt, pattern, '<na>')         | code   |
+----+----------------------------------------------+--------+
| 1  | <NA>A<NA>A<NA> <NA>B<NA>B<NA> <NA>           | ZZ-100 |
| 3  | <NA>A<NA>A<NA> <NA>C<NA>C<NA> <NA>E<NA>E<NA> | ZZ-300 |
| 2  | <NA>B<NA>B<NA> <NA> <NA>D<NA>D<NA>           | ZZ-200 |
+----+----------------------------------------------+--------+

更新 2

我已经开始工作了

SELECT o.id, 
       o.code, 
       items.txt, 
       o.regexstr, 
       IF(o.regexstr IS NOT NULL, regexp_replace(items.txt, o.regexstr, 
       '<NA>'), items.txt) masked 
FROM   items 
       LEFT JOIN (SELECT i.id                          id, 
                         i.code                        code, 
                         group_concat(r.regexstr, '|') regexstr 
                  FROM   items i 
                         left join (SELECT id, 
                                           regexstr, 
                                           regex_table.code 
                                    FROM   regex_table) r 
                                ON r.id = i.id 
                                   AND r.code = i.code 
                  GROUP  BY i.id, 
                            i.code) o 
              ON items.id = o.id 
                 AND items.code = o.code; 

输出:

+----+--------+----------+----------+--------------+
| id | code   | txt      | regexstr | masked       |
+----+--------+----------+----------+--------------+
| 5  | ZZ-500 | CC HH II | NULL     | CC HH II     |
| 2  | ZZ-200 | BB CC DD | BB|CC    | <NA> <NA> DD |
| 4  | ZZ-400 | EE FF GG | NULL     | EE FF GG     |
| 3  | ZZ-300 | AA CC EE | DD       | AA CC EE     |
| 1  | ZZ-100 | AA BB CC | CC|AA    | <NA> BB <NA> |
+----+--------+----------+----------+--------------+

但这似乎相当“复杂”。有什么让它更简洁的想法吗?

【问题讨论】:

  • 我不相信这会起作用,因为 Impala 或 Hive 不支持函数表达式中的子查询
  • 是的,如果有办法,我可以加入。虽然不太喜欢
  • 我刚刚发布了 UPDATE 1 的输出。在语法范围内,它可以工作(除了使用 group_concat 代替。但结果很奇怪。
  • 也许用group_concat('|', collect_set(regexstr))替换group_concat(..)
  • 请查看我的 UPDATE 2,因为我让它工作了。以前如果我把group_concat 放在regexp_replace 里面,它会给我错误。所以我必须在它之外再做一个SELECT。如果您有更好的想法,这似乎是非常麻烦的解决方案。

标签: sql regex hadoop hive impala


【解决方案1】:

您可以使用CASE 表达式将所有内容组合在一起:

SELECT
    id,
    CASE WHEN id = 1 THEN regexp_replace(txt, 'AA|CC', '<NA>')
         WHEN id = 2 THEN regexp_replace(txt, 'BB|CC', '<NA>')
         WHEN id = 3 THEN regexp_replace(txt, 'DD', '<NA>') END AS output
    code
FROM items
WHERE id IN (1, 2, 3);

【讨论】:

  • 对不起,我在上面添加了一些说明,因为我无法对值进行硬编码
【解决方案2】:
SELECT o.id, 
       o.code, 
       items.txt, 
       o.regexstr, 
       IF(o.regexstr IS NOT NULL, regexp_replace(items.txt, o.regexstr, 
       '<NA>'), items.txt) masked 
FROM   items 
       LEFT JOIN (SELECT i.id                          id, 
                         i.code                        code, 
                         group_concat(r.regexstr, '|') regexstr 
                  FROM   items i 
                         left join (SELECT id, 
                                           regexstr, 
                                           regex_table.code 
                                    FROM   regex_table) r 
                                ON r.id = i.id 
                                   AND r.code = i.code 
                  GROUP  BY i.id, 
                            i.code) o 
              ON items.id = o.id 
                 AND items.code = o.code; 

输出:

+----+--------+----------+----------+--------------+
| id | code   | txt      | regexstr | masked       |
+----+--------+----------+----------+--------------+
| 5  | ZZ-500 | CC HH II | NULL     | CC HH II     |
| 2  | ZZ-200 | BB CC DD | BB|CC    | <NA> <NA> DD |
| 4  | ZZ-400 | EE FF GG | NULL     | EE FF GG     |
| 3  | ZZ-300 | AA CC EE | DD       | AA CC EE     |
| 1  | ZZ-100 | AA BB CC | CC|AA    | <NA> BB <NA> |
+----+--------+----------+----------+--------------+

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-08
    • 1970-01-01
    • 2019-09-25
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    相关资源
    最近更新 更多