2013-10-27 5 views
10

Я загрузил журналы приложений в BigQuery, и мне нужно рассчитать страну на основе IP-адреса из этих журналов.Как повысить производительность запроса GeoIP в BigQuery?

Я написал запрос соединения между моей таблицей и таблицей сопоставления GeoIP, которую я загрузил с MaxMind.

Идеальный запрос будет OUTER JOIN с диапазоном фильтра, однако BQ поддерживает только = в условиях соединения. Таким образом, запрос выполняет INNER JOIN и обрабатывает отсутствующие значения в каждой стороне JOIN.

Я внесла поправки в свой первоначальный запрос, чтобы он мог работать в общедоступном наборе данных Википедии.

Может кто-нибудь, пожалуйста, помогите мне сделать это быстрее?

SELECT id, client_ip, client_ip_code, B.Country_Name as Country_Name 

FROM 
    (SELECT id, contributor_ip as client_ip, INTEGER(PARSE_IP(contributor_ip)) AS client_ip_code, 1 AS One 
    FROM [publicdata:samples.wikipedia] Limit 1000) AS A1 

JOIN 
    (SELECT From_IP_Code, To_IP_Code, Country_Name, 1 AS One 
    FROM 

     -- 3 IP sets: 1.valid ranges, 2.Gaps, 3. Gap at the end of the set 
     -- all Ranges of valid IPs: 
     (SELECT From_IP_Code, To_IP_Code, Country_Name FROM [QA_DATASET.GeoIP]) 

     -- Missing rages lower from From_IP 
     ,(SELECT 
      PriorRangeEndIP + 1 From_IP_Code, 
      From_IP_Code - 1 AS To_IP_Code, 
      'NA' AS Country_Name 
     FROM 

      -- use of LAG function to find prior valid range 
      (SELECT 
       From_IP_Code, 
       To_IP_Code, Country_Name, 
       LAG(To_IP_Code, 1, INTEGER(0)) 
       OVER(ORDER BY From_IP_Code asc) PriorRangeEndIP     
      FROM [QA_DATASET.GeoIP]) A 

      -- If gap from prior valid range is > 1 than its a gap to fill 
      WHERE From_IP_Code > PriorRangeEndIP + 1) 

     -- Missing rages higher tan Max To_IP 
     ,(SELECT MAX(To_IP_Code) + 1 as From_IP_Code, INTEGER(4311810304) as To_IP_Code, 'NA' AS Country_Name 
     FROM [QA_DATASET.GeoIP]) 
    ) AS B 
ON A1.ONE = B.ONE -- fake join condition to overcome allowed use of only = in joins 

-- Join condition where valid IP exists on left 
WHERE 
    A1.client_ip_code >= B.From_IP_Code 
    AND A1.client_ip_code <= B.To_IP_Code 
    OR (A1.client_ip_code IS NULL 
    AND B.From_IP_Code = 1) -- where there is no valid IP on left contributor_ip 
+0

что выглядит круто! заглядывая в нее .. не могли бы вы поместить таблицу GeoIP в новый набор данных и сделать ее общедоступной (чтобы попробовать запросы). Благодаря! –

+0

Я играл с этим. Благодарим за публикацию таблицы. Самая сложная часть до сих пор имеет дело с нулями. Если nulls можно пропустить, это можно сделать намного быстрее - начиная с запрошенного вами запроса. –

ответ

14

Подчищены версию этого ответа по адресу: http://googlecloudplatform.blogspot.com/2014/03/geoip-geolocation-with-google-bigquery.html

Позвольте мне кругленькую первоначальный запрос:

SELECT 
    id, 
    client_ip, 
    client_ip_code, 
    B.Country_Name AS Country_Name 
FROM (
    SELECT 
    id, 
    contributor_ip AS client_ip, 
    INTEGER(PARSE_IP(contributor_ip)) AS client_ip_code, 
    1 AS One 
    FROM 
    [publicdata:samples.wikipedia] 
    WHERE contributor_ip IS NOT NULL 
    LIMIT 
    1000 
    ) AS A1 
LEFT JOIN 
    (
    SELECT 
    From_IP_Code, 
    To_IP_Code, 
    Country_Name, 
    1 AS One 
    FROM 
    --3 IP sets: 1.valid ranges, 2.Gaps, 3. Gap at the END of the set 
    (
    SELECT 
     From_IP_Code, 
     To_IP_Code, 
     Country_Name 
    FROM 
     [playscape-proj:GeoIP.GeoIP]) -- all Ranges ov valid IPs 
    , 
    (
    SELECT 
     PriorRangeEndIP+1 From_IP_Code, 
     From_IP_Code-1 AS To_IP_Code, 
     'NA' AS Country_Name -- Missing rages lower FROM  From_IP 
    from(
     SELECT 
     From_IP_Code, 
     To_IP_Code, 
     Country_Name 
     , 
     LAG(To_IP_Code, 
      1, 
      INTEGER(0)) OVER(
     ORDER BY 
      From_IP_Code ASC) PriorRangeEndIP --use of LAG function to find prior valid range 
     FROM 
     [playscape-proj:GeoIP.GeoIP])A 
    WHERE 
    From_IP_Code>PriorRangeEndIP+1) -- If gap FROM prior valid range IS >1 than its a gap to fill 
     , 
    (
    SELECT 
     MAX(To_IP_Code)+1 AS From_IP_Code, 
     INTEGER (4311810304) AS To_IP_Code, 
     'NA' AS Country_Name -- Missing rages higher tan Max To_IP 
    FROM 
     [playscape-proj:GeoIP.GeoIP]) 
    ) AS B 
    ON A1.ONE=B.ONE --fake JOIN condition to overcome allowed use of = only IN joins 
WHERE 
    A1.client_ip_code>=B.From_IP_Code 
    AND A1.client_ip_code<=B.To_IP_Code -- JOIN condition WHERE valid IP exists ON left 
    OR (A1.client_ip_code IS NULL 
    AND B.From_IP_Code=1) -- WHERE there IS no valid IP ON left contributor_ip; 

Это длинный запрос! (и очень интересный). Он работает через 14 секунд. Как мы можем его оптимизировать?

Некоторые трюки я нашел:

  • Пропустить NULLs. Если в журнале нет IP-адреса, не пытайтесь его сопоставить.
  • Уменьшить комбинации. Вместо того, чтобы присоединяться к каждой левой стороне записи с каждой правой стороной, как насчет присоединения только записей 39.x.x.x с левой стороны с записями 39.x.x.x с правой стороны. Существует только несколько (3 или 4) правила, которые охватывают несколько диапазонов. Было бы легко добавить пару правил в таблицу геолита, чтобы добавить правила для покрытия этих пробелов.

Так что я меняюсь:

  • 1 AS One в INTEGER(PARSE_IP(contributor_ip)/(256*256*256)) AS One (дважды).
  • Добавление «WHERE contributor_ip NOT NOT NULL».

И теперь он работает через 3 секунды! 5% ips не может быть привязано географически, возможно, описанными пробелами (легко исправить).

Теперь, как насчет перехода от LIMIT 1000 к LIMIT 300000. Как долго это займет?

37 секунд! Гораздо лучше, чем описанные 25 минут. Если вы хотите пойти еще выше, я бы предложил превратить правую сторону таблицы в статическую, поскольку когда-то вычисленная она не меняется вообще, это просто расширение основных правил. Затем вы можете использовать JOIN EACH.

SELECT 
    id, 
    client_ip, 
    client_ip_code, 
    B.Country_Name AS Country_Name 
FROM (
    SELECT 
    id, 
    contributor_ip AS client_ip, 
    INTEGER(PARSE_IP(contributor_ip)) AS client_ip_code, 
    INTEGER(PARSE_IP(contributor_ip)/(256*256*256)) AS One 
    FROM 
    [publicdata:samples.wikipedia] 
    WHERE contributor_ip IS NOT NULL 
    LIMIT 
    300000 
    ) AS A1 
JOIN 
    (
    SELECT 
    From_IP_Code, 
    To_IP_Code, 
    Country_Name, 
    INTEGER(From_IP_Code/(256*256*256)) AS One 
    FROM 
    --3 IP sets: 1.valid ranges, 2.Gaps, 3. Gap at the END of the set 
    (
    SELECT 
     From_IP_Code, 
     To_IP_Code, 
     Country_Name 
    FROM 
     [playscape-proj:GeoIP.GeoIP]) -- all Ranges ov valid IPs 
    , 
    (
    SELECT 
     PriorRangeEndIP+1 From_IP_Code, 
     From_IP_Code-1 AS To_IP_Code, 
     'NA' AS Country_Name -- Missing rages lower FROM  From_IP 
    from(
     SELECT 
     From_IP_Code, 
     To_IP_Code, 
     Country_Name 
     , 
     LAG(To_IP_Code, 
      1, 
      INTEGER(0)) OVER(
     ORDER BY 
      From_IP_Code ASC) PriorRangeEndIP --use of LAG function to find prior valid range 
     FROM 
     [playscape-proj:GeoIP.GeoIP])A 
    WHERE 
    From_IP_Code>PriorRangeEndIP+1) -- If gap FROM prior valid range IS >1 than its a gap to fill 
     , 
    (
    SELECT 
     MAX(To_IP_Code)+1 AS From_IP_Code, 
     INTEGER (4311810304) AS To_IP_Code, 
     'NA' AS Country_Name -- Missing rages higher tan Max To_IP 
    FROM 
     [playscape-proj:GeoIP.GeoIP]) 
    ) AS B 
    ON A1.ONE=B.ONE --fake JOIN condition to overcome allowed use of = only IN joins 
WHERE 
    A1.client_ip_code>=B.From_IP_Code 
    AND A1.client_ip_code<=B.To_IP_Code -- JOIN condition WHERE valid IP exists ON left 
    OR (A1.client_ip_code IS NULL 
    AND B.From_IP_Code=1) -- WHERE there IS no valid IP ON left contributor_ip; 
+0

Благодарим вас за подробный ответ! 0,1. Я бы поставил правую сторону в статическую таблицу. 2. Я боюсь, что «From_IP_Code/(256 * 256 * 256) как один« не работает нормально, поскольку есть диапазоны, которые распространяются между 2 или даже 3 значениями. 3. пропуски нулей в соединении сложны, так как это может привести к отбрасыванию записей в конечном наборе данных (но это может быть обработано с условием мутного соединения). Я читал, что вы, ребята, скоро добавите некоторую гибкость, чтобы присоединиться к условиям. Надеюсь, это упростит такие запросы. –

+1

Да: вопрос диапазона, который распространяет 2 или 3 значения, легко решить. К счастью, есть только около 5 из этих случаев. Самое простое исправить было бы добавить эти несколько правил для покрытия разрыва. Например, если диапазон идет от 4.0.0.0 до 5.255.255.255, вы можете дублировать его, чтобы иметь от 4.0.0 до 4.255.255.255 и 5.0.0.0 до 5.255.255.255. Есть всего несколько случаев для покрытия, и для этих низких инвестиций вы получите гораздо более быстрые запросы позже. –

+0

Для тех, кто использует стандартные SQL, существуют функции Net для замены устаревших функций, таких как PARSE_IP(). – Flair

7

Как прохладное дополнение (см. Предыдущий ответ, чтобы получить подробную информацию): Каковы главные страны, внесшие изменения в Википедию?

Row Country_Name c  
1 United States 36605405  
2 United Kingdom 10355936  
3 Canada   4988835 
4 Australia  3387582 
5 India   1447756 
6 Germany   1414713 
7 Philippines  765874 
8 Netherlands  668850 
9 Ireland   651370 
10 France   602113 
11 New Zealand  590554 
12 Sweden   556544 
.... 
Query complete (28.5s elapsed, 1.07 GB processed) 

Запрос:

SELECT Country_Name, COUNT(*) c 
FROM (
SELECT 
id, 
client_ip, 
client_ip_code, 
B.Country_Name AS Country_Name 
FROM (
SELECT 
    id, 
    contributor_ip AS client_ip, 
    INTEGER(PARSE_IP(contributor_ip)) AS client_ip_code, 
    INTEGER(PARSE_IP(contributor_ip)/(256*256*256)) AS One 
FROM 
    [publicdata:samples.wikipedia] 
WHERE contributor_ip IS NOT NULL 
-- NO LIMITS - use ALL the data! 
    ) AS A1 
JOIN 
(
SELECT 
    From_IP_Code, 
    To_IP_Code, 
    Country_Name, 
    INTEGER(From_IP_Code/(256*256*256)) AS One 
FROM 
    --3 IP sets: 1.valid ranges, 2.Gaps, 3. Gap at the END of the set 
    (
    SELECT 
    From_IP_Code, 
    To_IP_Code, 
    Country_Name 
    FROM 
    [playscape-proj:GeoIP.GeoIP]) -- all Ranges ov valid IPs 
    , 
    (
    SELECT 
    PriorRangeEndIP+1 From_IP_Code, 
    From_IP_Code-1 AS To_IP_Code, 
    'NA' AS Country_Name -- Missing rages lower FROM  From_IP 
    from(
    SELECT 
     From_IP_Code, 
     To_IP_Code, 
     Country_Name, 
     LAG(To_IP_Code, 
     1, 
     INTEGER(0)) OVER(
     ORDER BY 
     From_IP_Code ASC) PriorRangeEndIP --use of LAG function to find prior valid range 
    FROM 
     [playscape-proj:GeoIP.GeoIP])A 
    WHERE 
    From_IP_Code>PriorRangeEndIP+1) -- If gap FROM prior valid range IS >1 than its a gap to fill 
    , 
    (
    SELECT 
    MAX(To_IP_Code)+1 AS From_IP_Code, 
    INTEGER (4311810304) AS To_IP_Code, 
    'NA' AS Country_Name -- Missing rages higher tan Max To_IP 
    FROM 
    [playscape-proj:GeoIP.GeoIP]) 
    ) AS B 
ON A1.ONE=B.ONE --fake JOIN condition to overcome allowed use of = only IN joins 
WHERE 
A1.client_ip_code>=B.From_IP_Code 
AND A1.client_ip_code<=B.To_IP_Code -- JOIN condition WHERE valid IP exists ON left 
OR (A1.client_ip_code IS NULL 
    AND B.From_IP_Code=1) -- WHERE there IS no valid IP ON left contributor_ip; 
) 
GROUP BY 1 ORDER BY 2 DESC 
+0

Это отличный пример использования ip с BQ. Я не могу видеть таблицу [playcape-proj: GeoIP.GeoIP] в общедоступных наборах данных. Я хотел запустить вышеупомянутые запросы. Можете ли вы, пожалуйста, направить меня. Спасибо – bunny

+0

см. Запрос на https://cloudplatform.googleblog.com/2014/03/geoip-geolocation-with-google-bigquery.html –

+0

Могу ли я узнать, какова точность этого преобразования GeoIP в город, долгота-широта. Можем ли мы полагаться на это или это приближение местоположения на основе IP. – bunny

Смежные вопросы