2017-03-31 73 views

回答

4

下面爲快速和簡單的選擇嘗試爲您提供:

#standardSQL 
WITH lookups AS (
    SELECT 
    'ç,æ,œ,á,é,í,ó,ú,à,è,ì,ò,ù,ä,ë,ï,ö,ü,ÿ,â,ê,î,ô,û,å,ø,Ø,Å,Á,À,Â,Ä,È,É,Ê,Ë,Í,Î,Ï,Ì,Ò,Ó,Ô,Ö,Ú,Ù,Û,Ü,Ÿ,Ç,Æ,Œ,ñ' AS accents, 
    'c,ae,oe,a,e,i,o,u,a,e,i,o,u,a,e,i,o,u,y,a,e,i,o,u,a,o,O,A,A,A,A,A,E,E,E,E,I,I,I,I,O,O,O,O,U,U,U,U,Y,C,AE,OE,n' AS latins 
), 
pairs AS (
    SELECT accent, latin FROM lookups, 
    UNNEST(SPLIT(accents)) AS accent WITH OFFSET AS p1, 
    UNNEST(SPLIT(latins)) AS latin WITH OFFSET AS p2 
    WHERE p1 = p2 
), 
yourTableWithWords AS (
    SELECT word FROM UNNEST(
     SPLIT('brasília,ångström,aperçu,barège, beau idéal, belle époque, béguin, bête noire, bêtise, Bichon Frisé, blasé, blessèd, bobèche, boîte, bombé, Bön, Boötes, boutonnière, bric-à-brac, Brontë Beyoncé,El Niño') 
    ) AS word 
) 
SELECT 
    word AS word_with_accent, 
    (SELECT STRING_AGG(IFNULL(latin, char), '') 
    FROM UNNEST(SPLIT(word, '')) char 
    LEFT JOIN pairs 
    ON char = accent) AS word_without_accent 
FROM yourTableWithWords 

輸出是

word_with_accent word_without_accent  
blessèd   blessed 
El Niño   El Nino 
belle époque belle epoque  
boîte   boite  
Boötes   Bootes 
blasé   blase  
ångström  angstrom  
bobèche   bobeche 
barège   barege 
bric-à-brac  bric-a-brac 
bête noire  bete noire 
Bichon Frisé Bichon Frise  
Brontë Beyoncé Bronte Beyonce 
bêtise   betise 
beau idéal  beau ideal 
bombé   bombe  
brasília  brasilia  
boutonnière  boutonniere 
aperçu   apercu 
béguin   beguin 
Bön    Bon 

UPDATE

下面是如何收拾這個邏輯到SQL UDF - 如此accent2latin(word)可以被稱爲做一個「神奇」的

#standardSQL 
CREATE TEMP FUNCTION accent2latin(word STRING) AS 
((
    WITH lookups AS (
    SELECT 
    'ç,æ,œ,á,é,í,ó,ú,à,è,ì,ò,ù,ä,ë,ï,ö,ü,ÿ,â,ê,î,ô,û,å,ø,Ø,Å,Á,À,Â,Ä,È,É,Ê,Ë,Í,Î,Ï,Ì,Ò,Ó,Ô,Ö,Ú,Ù,Û,Ü,Ÿ,Ç,Æ,Œ,ñ' AS accents, 
    'c,ae,oe,a,e,i,o,u,a,e,i,o,u,a,e,i,o,u,y,a,e,i,o,u,a,o,O,A,A,A,A,A,E,E,E,E,I,I,I,I,O,O,O,O,U,U,U,U,Y,C,AE,OE,n' AS latins 
), 
    pairs AS (
    SELECT accent, latin FROM lookups, 
     UNNEST(SPLIT(accents)) AS accent WITH OFFSET AS p1, 
     UNNEST(SPLIT(latins)) AS latin WITH OFFSET AS p2 
    WHERE p1 = p2 
) 
    SELECT STRING_AGG(IFNULL(latin, char), '') 
    FROM UNNEST(SPLIT(word, '')) char 
    LEFT JOIN pairs 
    ON char = accent 
)); 

WITH yourTableWithWords AS (
    SELECT word FROM UNNEST(
     SPLIT('brasília,ångström,aperçu,barège, beau idéal, belle époque, béguin, bête noire, bêtise, Bichon Frisé, blasé, blessèd, bobèche, boîte, bombé, Bön, Boötes, boutonnière, bric-à-brac, Brontë Beyoncé,El Niño') 
    ) AS word 
) 
SELECT 
    word AS word_with_accent, 
    accent2latin(word) AS word_without_accent 
FROM yourTableWithWords 
+0

它的工作!謝謝@Mikhail。這是一個非常好的解決方案! –

+0

@FelipeCarlo - 當然。感謝您接受/投票。你可以進一步將它包裝成漂亮的SQL UDF,以便它更易於使用/「便攜」! –

+0

@FelipeCarlo - 查看SQL更新UDF –

2

值得一提的是,什麼你問的是unicode text normalization簡化的情況。許多語言在其標準庫中都有此功能(例如,Java)。一種好的方法是插入已經規範化的文本BigQuery。如果這不起作用 - 例如,因爲您需要保留原始文本,並且擔心打到BigQuery's row size limit - 那麼您需要在查詢中進行標準化。

某些數據庫具有用於查詢的各種完整性的Unicode標準化(例如,PostgreSQL's unaccent method,PrestoDB's normalize method)的實現。不幸的是,BigQuery不是其中之一。在撰寫本文時,BigQuery中沒有文本規範化功能。這個答案的實現是一種「滾動你自己的未知」。當BigQuery發佈官方功能時,每個人都應該使用它!

假設你需要在你的查詢中進行規範化(並且Google還沒有提供這方面的功能),這些都是一些合理的選擇。

方法1:使用NORMALIZE

谷歌現在拿出一個NORMALIZE功能。 (感謝@WillianFuks在標註中的註釋!)現在,這是文本標準化的明顯選擇。例如:

SELECT REGEXP_REPLACE(NORMALIZE(text), r"\pM", '') FROM yourtable; 

有是如何工作的,以及爲什麼需要在評論REGEXP_REPLACE通話的簡要說明。

我已經留下了參考的其他方法。

方法2:使用REGEXP_REPLACEREPLACE上的內容

我使用REGEXP_REPLACE實現在傳統的SQL文本規範化的只有小寫的情況。 (在標準SQL的模擬是相當不言自明的。)我使用下面的查詢運行與1K左右的平均長度的文本字段一些測試在一個大表28M行:

SELECT id, text FROM 
    (SELECT 
    id, 
    CASE 
    WHEN REGEXP_CONTAINS(LOWER(text), r"[àáâäåæçèéêëìíîïòóôöøùúûüÿœ]") THEN 
     REGEXP_REPLACE(
     REGEXP_REPLACE(
      REGEXP_REPLACE(
      REGEXP_REPLACE(
       REGEXP_REPLACE(
       REPLACE(REPLACE(REPLACE(REPLACE(LOWER(text), 'œ', 'ce'), 'ÿ', 'y'), 'ç', 'c'), 'æ', 'ae'), 
       r"[ùúûü]", 'u'), 
      r"[òóôöø]", 'o'), 
      r"[ìíîï]", 'i'), 
     r"[èéêë]", 'e'), 
     r"[àáâäå]", 'a') 
    ELSE 
     LOWER(text) 
    END AS text 
    FROM 
    yourtable ORDER BY id LIMIT 10); 

與:

WITH lookups AS (
    SELECT 
    'ç,æ,œ,á,é,í,ó,ú,à,è,ì,ò,ù,ä,ë,ï,ö,ü,ÿ,â,ê,î,ô,û,å,ø,ñ' AS accents, 
    'c,ae,oe,a,e,i,o,u,a,e,i,o,u,a,e,i,o,u,y,a,e,i,o,u,a,o,n' AS latins 
), 
pairs AS (
    SELECT accent, latin FROM lookups, 
    UNNEST(SPLIT(accents)) AS accent WITH OFFSET AS p1, 
    UNNEST(SPLIT(latins)) AS latin WITH OFFSET AS p2 
    WHERE p1 = p2 
) 
SELECT foo FROM (
    SELECT 
    id, 
    (SELECT STRING_AGG(IFNULL(latin, char), '') AS foo FROM UNNEST(SPLIT(LOWER(text), '')) char LEFT JOIN pairs ON char=accent) AS foo 
    FROM 
    yourtable ORDER BY id LIMIT 10); 

平均來說,REGEXP_REPLACE實施約2.9s跑;基於陣列的實現在大約12.5s內運行。

方法3:在搜索模式

什麼把我帶到了這個問題,我是一個搜索的使用情況下使用REGEXP_REPLACE。對於這個用例,我可以規範化我的語料庫文本,使其看起來更像我的查詢,或者我可以「非規範化」我的查詢,使它看起來更像我的文本。以上描述了第一種方法的實現。這描述了第二個的實現。

當一個單詞搜索,可以使用REGEXP_MATCH匹配功能,只使用以下方式更新查詢:

a -> [aàáaâäãåā] 
e -> [eèéêëēėę] 
i -> [iîïíīįì] 
o -> [oôöòóøōõ] 
u -> [uûüùúū] 
y -> [yÿ] 
s -> [sßśš] 
l -> [lł] 
z -> [zžźż] 
c -> [cçćč] 
n -> [nñń] 
æ -> (?:æ|ae) 
œ -> (?:œ|ce) 

所以查詢「你好」是這樣的,作爲一個正則表達式:

r"h[eèéêëēėę][lł][lł][oôöòóøōõ]" 

將單詞轉換爲正則表達式應該在任何語言中都相當簡單。這不是針對發佈的問題的解決方案 - 「如何刪除BigQuery中的重音符號?」 - 而是相關用例的解決方案,這可能會將人們(如我!)帶到此頁面。

+1

我想知道標準化方法如何解決這個問題。我嘗試使用新的[normalize](https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#normalize)函數,但它不起作用。你知道如何製作它嗎? –

+0

當您使用新的'NORMALIZE'功能時,您是否簡單地調用'NORMALIZE'?默認情況下,該函數將從「變音符」字符中分解「字母」字符以創建重音字符的標準化序列表示,但不會刪除變音符號。如果要刪除變音符號,則需要執行另一步驟;像'REGEXP_REPLACE(s,r「[^ \ pL \ pN \ pP \ pS \ pZ]」,'')'或'REGEXP_REPLACE(s,r「[\ pM]」,'')'可能會做招。 (請參閱[這裏](https://github.com/google/re2/wiki/Syntax)瞭解這裏使用的unicode字符類。) – sigpwned

+0

非常有趣的信息!感謝那! –

相關問題