2017-01-12 4 views
3

Ich habe gesucht und kann nicht viel zu diesem Thema finden (vielleicht schlechte Suchbegriffe :). Ich habe eine Tabelle, Protopayload.resource, die Apache-Protokollierungsinformationen erhält. Daher enthält das Feld, an dem ich interessiert bin, mehrere Werte, nach denen ich suchen muss. Das Feld ist in einem PHP-URL-Stil formatiert. heißtAufteilen eines Feldes in große Abfrage

/?id=13242134123&ver=12&os_bits=64&os_type=mac&lng=EN 

Dies macht alle Suchvorgänge mit wirklich langen Regexes Daten zu erhalten landen. Fügen Sie dann Anweisungen hinzu, um Daten zu kombinieren.

Beispiel Suche mac kombinieren/win Statistiken

SELECT 
    t1.date, t1.wincount, COALESCE(t2.maccount, 0) AS maccount 
FROM (
    SELECT 
    DATE(metadata.timestamp) AS date, 
    INTEGER(COUNT(protoPayload.resource)) AS wincount 
    FROM (TABLE_DATE_RANGE(tablename, DATE_ADD(CURRENT_TIMESTAMP(), -30, 'DAY'), CURRENT_TIMESTAMP())) 
    WHERE 
    (REGEXP_MATCH(protoPayload.resource, r'ver=[11,12')) 
    AND protoPayload.resource CONTAINS 'os=win' GROUP BY date) t1 
LEFT JOIN (
    SELECT 
    DATE(metadata.timestamp) AS date, 
    INTEGER(COUNT(protoPayload.resource)) AS maccount 
    FROM (TABLE_DATE_RANGE(tablename, DATE_ADD(CURRENT_TIMESTAMP(), -30, 'DAY'), CURRENT_TIMESTAMP())) 
    WHERE 
    (REGEXP_MATCH(protoPayload.resource, r'cv=[p,m][17,16,15,14]')) 
    AND protoPayload.resource CONTAINS 'os=mac' GROUP BY date) t2 
ON 
    t1.date = t2.date 
ORDER BY t1.date 

Was war ich dachte Suche ähnliche Regex zu verwenden. Erstellen Sie eine neue Tabelle. Speichern Sie die Daten anschließend in einer neuen Tabelle mit Beziehungsfeldern. Korrigieren Sie die zukünftige Protokollierung, damit sie ordnungsgemäß in der Tabelle protokolliert wird.

Meine Fragen sind diese gültige Lösung oder gibt es eine viel einfachere Möglichkeit, dies in Google BigQuery zu erreichen? Gibt es eine bessere Möglichkeit, die Daten zu transformieren? Nochmals vielen Dank für die Eingabe!

+0

Willkommen zu StackOverflow! Ihre Frage ist also, ob Google BigQuery eine einfache Möglichkeit zum Parsen von URLs bietet? Ich bin kein GBQ-Experte, aber im Allgemeinen würde ich sagen, dass Ihre Vorgehensweise in Ordnung ist. Das heißt, ich denke, dass Sie eher eine Antwort bekommen, wenn Sie eine Alternative anbieten und Ihre Frage wie "Welches ist besser: a oder b?" – akousmata

Antwort

1

Sie können immer Javascript UDFs für maximale Flexibilität verwenden. Sie sind langsamer als eine reine SQL-Lösung, aber Sie können die Einschränkungen umgehen.

Zum Beispiel:

#standardSQL 
CREATE TEMPORARY FUNCTION parse(query STRING) 
RETURNS STRUCT<id STRING, ver STRING, os_bits STRING, os_type STRING, lng STRING> 
LANGUAGE js AS """ 
    function parseQueryString(query) { 
     // http://codereview.stackexchange.com/a/10396 
     var map = {}; 
     query.replace(/([^&=]+)=?([^&]*)(?:&+|$)/g, function(match, key, value) { 
      (map[key] = map[key] || []).push(value); 
     }); 
     return map; 
    } 

    return parseQueryString(query) 

"""; 


WITH urls AS 
    (SELECT 'id=13242134123&ver=12&os_bits=64&os_type=mac&lng=EN' query 
    UNION ALL 
    SELECT 'id=13242134124&ver=12&os_bits=64&os_type=mac&lng=EN1&lng=EN2' query 
) 


SELECT query, parse(query) as parsed 
FROM urls;. 

enter image description here

2

können Sie eine SQL-Funktion verwenden, um die Schlüssel-Wert-Paare in ein Array zu analysieren, die in der Regel schneller als mit Hilfe von JavaScript. Zum Beispiel

#standardSQL 
CREATE TEMPORARY FUNCTION ParseKeys(queryString STRING) 
RETURNS ARRAY<STRUCT<key STRING, value STRING>> AS (
    (SELECT 
    ARRAY_AGG(STRUCT(
     entry[OFFSET(0)] AS key, 
     entry[OFFSET(1)] AS value)) 
    FROM (
    SELECT SPLIT(pairString, '=') AS entry 
    FROM UNNEST(SPLIT(REGEXP_EXTRACT(queryString, r'/\?(.*)'), '&')) AS pairString) 
    ) 
); 
SELECT ParseKeys('/?foo=bar&baz=2'); 

Jetzt können Sie auf diesem mit einer Funktion erstellen, die die Schlüssel in struct Felder schwenken:

#standardSQL 
CREATE TEMP FUNCTION GetAttributes(queryString STRING) AS (
    (SELECT AS STRUCT 
    MAX(IF(key = 'id', CAST(value AS INT64), NULL)) AS id, 
    MAX(IF(key = 'ver', CAST(value AS INT64), NULL)) AS ver, 
    MAX(IF(key = 'os_bits', CAST(value AS INT64), NULL)) AS os_bits, 
    MAX(IF(key = 'os_type', value, NULL)) AS os_type, 
    MAX(IF(key = 'lng', value, NULL)) AS lng 
    FROM UNNEST(ParseKeys(queryString))) 
); 

alles zusammen Einlochen, können Sie die GetAttributes Funktion mit einigem Abtastwerteingang ausprobieren:

#standardSQL 
CREATE TEMPORARY FUNCTION ParseKeys(queryString STRING) 
RETURNS ARRAY<STRUCT<key STRING, value STRING>> AS (
    (SELECT 
    ARRAY_AGG(STRUCT(
     entry[OFFSET(0)] AS key, 
     entry[OFFSET(1)] AS value)) 
    FROM (
    SELECT SPLIT(pairString, '=') AS entry 
    FROM UNNEST(SPLIT(REGEXP_EXTRACT(queryString, r'/\?(.*)'), '&')) AS pairString) 
    ) 
); 
CREATE TEMP FUNCTION GetAttributes(queryString STRING) AS (
    (SELECT AS STRUCT 
    MAX(IF(key = 'id', CAST(value AS INT64), NULL)) AS id, 
    MAX(IF(key = 'ver', CAST(value AS INT64), NULL)) AS ver, 
    MAX(IF(key = 'os_bits', CAST(value AS INT64), NULL)) AS os_bits, 
    MAX(IF(key = 'os_type', value, NULL)) AS os_type, 
    MAX(IF(key = 'lng', value, NULL)) AS lng 
    FROM UNNEST(ParseKeys(queryString))) 
); 
SELECT url, GetAttributes(url).* 
FROM UNNEST(['/?id=13242134123&ver=12&os_bits=64&os_type=mac&lng=EN', 
      '/?id=2343645745&ver=15&os_bits=32&os_type=linux&lng=FR']) AS url; 
0

ich sehe einige Probleme in der Abfrage in Ihrer Frage
1. sieht aus wie regexp nicht korrekt ist und n ot-Capture, was Sie
2. Abfrage ist stark over-engineered erwarten und kann sehr vereinfacht werden

unten nach oben Adresse ist Punkte

SELECT 
    DATE(metadata.timestamp) AS date, 
    SUM(REGEXP_MATCH(protoPayload.resource, r'ver=(11|12)\b') 
     AND protoPayload.resource CONTAINS 'os_type=win' 
) AS wincount, 
    SUM(REGEXP_MATCH(protoPayload.resource, r'cv=(p|m)(17|16|15|14)\b') 
     AND protoPayload.resource CONTAINS 'os_type=mac' 
) AS maccount 
FROM (TABLE_DATE_RANGE(tablename, DATE_ADD(CURRENT_TIMESTAMP(), -30, 'DAY'), 
            CURRENT_TIMESTAMP())) 
GROUP BY date 

Bitte beachten Sie: Sie betreffende Abfrage geschrieben, mit BigQuery Legacy-SQL , also behalte ich meine Antwort im selben Dialekt

Verwandte Themen