Created
September 25, 2017 01:33
-
-
Save adrienmo/eaca761f8d1539810bce722521797ef7 to your computer and use it in GitHub Desktop.
reverse lookup for geolix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Location do | |
require Logger | |
def create do | |
Geolix.load_database( | |
%{ | |
id: :city, | |
adapter: Geolix.Adapter.MMDB2, | |
source: "/test/GeoLite2-City_20170905.tar.gz" | |
} | |
) | |
city = Geolix.Adapter.MMDB2.Storage.Data.get(:city) | |
:ets.new(:locations, [:named_table, :bag, read_concurrency: true]) | |
{time, _} = :timer.tc(fn () -> recurse(city, city) end) | |
Logger.info("#{time} microsecond to load the city into ets.") | |
end | |
def recurse(_, ""), do: nil | |
def recurse(data, rest) do | |
{value, rest} = Geolix.Adapter.MMDB2.Decoder.decode(data, rest) | |
unless is_nil(value[:country]) or is_nil(value[:city]) do | |
sub = case value do | |
%{subdivisions: [a | _]} -> | |
a | |
_ -> | |
%{ | |
geoname_id: {:other, value.country.geoname_id}, | |
names: %{ | |
en: "Others" | |
} | |
} | |
end | |
:ets.insert_new( | |
:locations, | |
{{:country, value.country.geoname_id}, value.country} | |
) | |
:ets.insert_new( | |
:locations, | |
{ | |
{:sub_division, sub.geoname_id}, | |
%{sub_division: sub, country: value.city.geoname_id} | |
} | |
) | |
:ets.insert_new( | |
:locations, | |
{ | |
{:city, value.city.geoname_id}, | |
%{ | |
city: value.city, | |
country: value.city.geoname_id, | |
sub_division: sub.geoname_id | |
} | |
} | |
) | |
:ets.insert( | |
:locations, | |
{:countries, value.country} | |
) | |
:ets.insert( | |
:locations, | |
{{:country_sub_division, value.country.geoname_id}, sub.geoname_id} | |
) | |
:ets.insert( | |
:locations, | |
{{:sub_division_city, sub.geoname_id}, value.city.geoname_id} | |
) | |
end | |
recurse(data, rest) | |
end | |
def get_countries(lang) do | |
:locations | |
|> :ets.lookup(:countries) | |
|> Enum.map( | |
fn ({ | |
_, | |
%{ | |
geoname_id: geoname_id, | |
names: names | |
} | |
}) -> {get_name(names, lang), geoname_id} | |
end | |
) | |
end | |
def get_provinces(country_geoname_id, lang) do | |
:locations | |
|> :ets.lookup({:country_sub_division, country_geoname_id}) | |
|> Enum.map( | |
fn ({_, geoname_id}) -> | |
[ | |
{ | |
_, | |
%{ | |
sub_division: %{ | |
geoname_id: geoname_id, | |
names: names | |
} | |
} | |
} | |
] = :ets.lookup(:locations, {:sub_division, geoname_id}) | |
{get_name(names, lang), geoname_id} | |
end | |
) | |
end | |
def get_cities(sub_division_geoname_id, lang) do | |
:locations | |
|> :ets.lookup({:sub_division_city, sub_division_geoname_id}) | |
|> Enum.map( | |
fn ({_, geoname_id}) -> | |
[ | |
{ | |
_, | |
%{ | |
city: %{ | |
geoname_id: geoname_id, | |
names: names | |
} | |
} | |
} | |
] = :ets.lookup(:locations, {:city, geoname_id}) | |
{get_name(names, lang), geoname_id} | |
end | |
) | |
end | |
def get_name(names, lang) do | |
if not is_nil(names[lang]) do | |
names[lang] | |
else | |
names[:en] | |
end | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment