<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Felipe Hoffa</title>
    <description>The latest articles on DEV Community by Felipe Hoffa (@felipehoffa).</description>
    <link>https://dev.to/felipehoffa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F16074%2F46c7b18d-89cc-43cc-a146-cbc4abc7eb1a.jpeg</url>
      <title>DEV Community: Felipe Hoffa</title>
      <link>https://dev.to/felipehoffa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/felipehoffa"/>
    <language>en</language>
    <item>
      <title>Geolocation with BigQuery: De-identify 76 million IP addresses in 20 seconds</title>
      <dc:creator>Felipe Hoffa</dc:creator>
      <pubDate>Mon, 08 Jul 2019 16:00:00 +0000</pubDate>
      <link>https://dev.to/googlecloud/geolocation-with-bigquery-de-identify-76-million-ip-addresses-in-20-seconds-3dpc</link>
      <guid>https://dev.to/googlecloud/geolocation-with-bigquery-de-identify-76-million-ip-addresses-in-20-seconds-3dpc</guid>
      <description>&lt;p&gt;We published our first approach to de-identifying IP addresses four years ago—&lt;a href="https://cloudplatform.googleblog.com/2014/03/geoip-geolocation-with-google-bigquery.html"&gt;GeoIP geolocation with Google BigQuery—&lt;/a&gt; and it's time for an update that includes the best and latest BigQuery features, like using the latest SQL standards, dealing with nested data, and handling joins much faster. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/bigquery/"&gt;BigQuery is Google Cloud’s&lt;/a&gt; serverless data warehouse designed for scalability and fast performance. Using it lets you explore large datasets to find new and meaningful insights. To comply with current policies and regulations, you might need to de-identify the IP addresses of your users when analyzing datasets that contain personal data. For example, under &lt;a href="https://cloud.google.com/blog/topics/inside-google-cloud/google-cloud-ready-for-gdpr"&gt;GDPR&lt;/a&gt;, an IP address might be considered &lt;a href="https://support.google.com/analytics/answer/7686480?hl=en"&gt;PII or personal data&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Replacing collected IP addresses with a &lt;a href="https://www.google.com/about/company/user-consent-policy-help.html"&gt;coarse location&lt;/a&gt; is one method to help reduce risk—and BigQuery is ready to help. Let's see how.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to de-identify IP address data
&lt;/h2&gt;

&lt;p&gt;For this example of how you can easily de-identify IP addresses, let’s use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;76 million IP addresses collected by Wikipedia from anonymous editors between 2001 and 2010&lt;/li&gt;
&lt;li&gt;MaxMind's &lt;a href="https://dev.maxmind.com/geoip/geoip2/geolite2/"&gt;Geolite2 free geolocation database&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;BigQuery's improved byte and networking functions &lt;code&gt;NET.SAFE_IP_FROM_STRING(), NET.IP_NET_MASK()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;BigQuery's &lt;a href="https://cloud.google.com/bigquery/docs/nested-repeated"&gt;new superpowers&lt;/a&gt; that deal with nested data, generate arrays, and run incredibly fast joins&lt;/li&gt;
&lt;li&gt;The new &lt;a href="https://cloud.google.com/bigquery/docs/gis-visualize"&gt;BigQuery Geo Viz tool&lt;/a&gt; that uses Google Maps APIs to chart geopoints around the world.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's go straight into the query. Use the code below to replace IP addresses with the generic location.&lt;/p&gt;

&lt;h3&gt;
  
  
  Top countries editing Wikipedia
&lt;/h3&gt;

&lt;p&gt;Here’s the list of countries where users are making edits to Wikipedia, followed by the query to use:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--88GRoeFP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/gweb-cloudblog-publish/images/list_of_countries.max-1000x1000.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--88GRoeFP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/gweb-cloudblog-publish/images/list_of_countries.max-1000x1000.png" alt="list of countries.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;standardSQL&lt;/span&gt;

&lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="k"&gt;replace&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="k"&gt;source&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;IP&lt;/span&gt; &lt;span class="n"&gt;addresses&lt;/span&gt;
&lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt; &lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="s1"&gt;'m using the same Wikipedia set from the previous article
WITH source_of_ip_addresses AS (
  SELECT REGEXP_REPLACE(contributor_ip, '&lt;/span&gt;&lt;span class="n"&gt;xxx&lt;/span&gt;&lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="s1"&gt;')  ip, COUNT(*) c
  FROM `publicdata.samples.wikipedia`
  WHERE contributor_ip IS NOT null  
  GROUP BY 1
)

SELECT country_name, SUM(c) c
FROM (
  SELECT ip, country_name, c
  FROM (
    SELECT *, NET.SAFE_IP_FROM_STRING(ip) &amp;amp; NET.IP_NET_MASK(4, mask) network_bin
    FROM source_of_ip_addresses, UNNEST(GENERATE_ARRAY(9,32)) mask
    WHERE BYTE_LENGTH(NET.SAFE_IP_FROM_STRING(ip)) = 4
  )
  JOIN `fh-bigquery.geocode.201806_geolite2_city_ipv4_locs`  
  USING (network_bin, mask)
)
GROUP BY 1
ORDER BY 2 DESC

Query complete (20.9 seconds elapsed, 1.14 GB processed)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Top cities editing Wikipedia
&lt;/h3&gt;

&lt;p&gt;These are the top cities where users are making edits to Wikipedia, collected from 2001 to 2010, followed by the query to use:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ghk6FS4d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/gweb-cloudblog-publish/images/top_cities.max-1000x1000.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ghk6FS4d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/gweb-cloudblog-publish/images/top_cities.max-1000x1000.png" alt="top cities.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--40L30nex--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/gweb-cloudblog-publish/images/map_of_top_cities.max-1000x1000.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--40L30nex--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/gweb-cloudblog-publish/images/map_of_top_cities.max-1000x1000.png" alt="map of top cities.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="k"&gt;replace&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="k"&gt;source&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;IP&lt;/span&gt; &lt;span class="n"&gt;addresses&lt;/span&gt;
&lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt; &lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="s1"&gt;'m using the same Wikipedia set from the previous article
WITH source_of_ip_addresses AS (
  SELECT REGEXP_REPLACE(contributor_ip, '&lt;/span&gt;&lt;span class="n"&gt;xxx&lt;/span&gt;&lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="s1"&gt;')  ip, COUNT(*) c
  FROM `publicdata.samples.wikipedia`
  WHERE contributor_ip IS NOT null  
  GROUP BY 1
)


SELECT city_name, SUM(c) c, ST_GeogPoint(AVG(longitude), AVG(latitude)) point
FROM (
  SELECT ip, city_name, c, latitude, longitude, geoname_id
  FROM (
    SELECT *, NET.SAFE_IP_FROM_STRING(ip) &amp;amp; NET.IP_NET_MASK(4, mask) network_bin
    FROM source_of_ip_addresses, UNNEST(GENERATE_ARRAY(9,32)) mask
    WHERE BYTE_LENGTH(NET.SAFE_IP_FROM_STRING(ip)) = 4
  )
  JOIN `fh-bigquery.geocode.201806_geolite2_city_ipv4_locs`  
  USING (network_bin, mask)
)
WHERE city_name  IS NOT null
GROUP BY city_name, geoname_id
ORDER BY c DESC
LIMIT 5000` 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Exploring some new BigQuery features
&lt;/h2&gt;

&lt;p&gt;These new queries are compliant with the latest SQL standards, enabling a few new tricks that we'll review here.&lt;/p&gt;

&lt;h3&gt;
  
  
  New MaxMind tables: Goodbye math, hello IP masks
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://dev.maxmind.com/geoip/geoip2/geolite2/"&gt;downloadable GeoLite2 tables&lt;/a&gt; are not based in ranges anymore. Now they use proper IP networks, like in "156.33.241.0/22".&lt;/p&gt;

&lt;p&gt;Using BigQuery, we parsed these into binary IP addresses with integer masks. We also did some pre-processing of the GeoLite2 tables, combining the networks and locations into a single table, and adding the parsed network columns, as shown here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;standardSQL&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IP_FROM_STRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_EXTRACT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s1"&gt;'(.*)/'&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;network_bin&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_EXTRACT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s1"&gt;'/(.*)'&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;INT64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`fh-bigquery.geocode.201806_geolite2_city_ipv4`&lt;/span&gt; 
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="nv"&gt;`fh-bigquery.geocode.201806_geolite2_city_locations_en`&lt;/span&gt;
&lt;span class="k"&gt;USING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;geoname_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Geolocating one IP address out of millions
&lt;/h3&gt;

&lt;p&gt;To find one IP address within this table, like "103.230.141.7," something like this might work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;country_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;city_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`fh-bigquery.geocode.201806_geolite2_city_ipv4_locs`&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;network_bin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IP_FROM_STRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'103.230.141.7'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But that doesn't work. We need to apply the correct mask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;country_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;city_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`fh-bigquery.geocode.201806_geolite2_city_ipv4_locs`&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;network_bin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IP_FROM_STRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'103.230.141.7'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;NET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IP_NET_MASK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And that gets an answer: this IP address seems to live in Antarctica.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling up
&lt;/h3&gt;

&lt;p&gt;That looked easy enough, but we need a few more steps to figure out the right mask and joins between the GeoLite2 table (more than 3 million rows) and a massive source of IP addresses.&lt;/p&gt;

&lt;p&gt;And that's what the next line in the main query does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
     &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SAFE_IP_FROM_STRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
       &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;NET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IP_NET_MASK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;network_bin&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;source_of_ip_addresses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;UNNEST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GENERATE_ARRAY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is basically applying a CROSS JOIN with all the possible masks (numbers between 9 and 32) and using these to mask the source IP addresses. And then comes the really neat part: BigQuery manages to handle the correct JOIN in a massively fast way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network_bin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;BigQuery here picks up only one of the masked IPs—the one where the masked IP and the network with that given mask matches. If we dig deeper, we'll find in the execution details tab that BigQuery did an "INNER HASH JOIN EACH WITH EACH ON", which requires a lot of shuffling resources, while still not requiring a full CROSS JOIN between two massive tables.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EaiH_A9s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/gweb-cloudblog-publish/images/big_query.max-1000x1000.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EaiH_A9s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/gweb-cloudblog-publish/images/big_query.max-1000x1000.png" alt="big query.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t1qr8oxh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/gweb-cloudblog-publish/images/big_query_2.max-1000x1000.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t1qr8oxh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/gweb-cloudblog-publish/images/big_query_2.max-1000x1000.png" alt="big query 2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Go further with anonymizing data
&lt;/h2&gt;

&lt;p&gt;This is how BigQuery can help you to replace IP addresses with coarse locations and also provide aggregations of individual rows. This is just one technique that can help you reduce the risk of handling your data. GCP provides several other tools, including &lt;a href="https://cloud.google.com/dlp/"&gt;Cloud Data Loss Prevention&lt;/a&gt; (DLP), that can help you scan and de-identify data. You now have several options to explore and use datasets that let you comply with regulations. What interesting ways are you using de-identified data? &lt;a href="https://twitter.com/felipehoffa?lang=en"&gt;Let us know.&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Find the latest &lt;a href="https://console.cloud.google.com/bigquery?p=bigquery-public-data&amp;amp;d=geolite2&amp;amp;page=dataset"&gt;MaxMind GeoLite2 table in BigQuery&lt;/a&gt;, thanks to our &lt;a href="https://cloud.google.com/public-datasets/"&gt;Google Cloud Public Datasets&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>gcp</category>
      <category>bigquery</category>
      <category>sql</category>
      <category>gis</category>
    </item>
    <item>
      <title>test</title>
      <dc:creator>Felipe Hoffa</dc:creator>
      <pubDate>Wed, 20 Feb 2019 15:32:46 +0000</pubDate>
      <link>https://dev.to/felipehoffa/test-259g</link>
      <guid>https://dev.to/felipehoffa/test-259g</guid>
      <description>&lt;p&gt;This is my first post&lt;/p&gt;

</description>
      <category>test</category>
    </item>
    <item>
      <title>Hi, I'm Felipe Hoffa</title>
      <dc:creator>Felipe Hoffa</dc:creator>
      <pubDate>Tue, 11 Apr 2017 02:45:39 +0000</pubDate>
      <link>https://dev.to/felipehoffa/hi-im-felipe-hoffa</link>
      <guid>https://dev.to/felipehoffa/hi-im-felipe-hoffa</guid>
      <description>&lt;p&gt;You can find me on Twitter as &lt;a href="https://twitter.com/felipehoffa" rel="noopener noreferrer"&gt;@felipehoffa&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I live in San Francisco.&lt;/p&gt;

&lt;p&gt;I work for Google.&lt;/p&gt;

&lt;p&gt;You can find many of my posts at &lt;a href="https://medium.com/@hoffa/" rel="noopener noreferrer"&gt;https://medium.com/@hoffa/&lt;/a&gt;, but I might post more here too.&lt;/p&gt;

&lt;p&gt;Nice to meet you.&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
