Skip to content

Instantly share code, notes, and snippets.

@adrienmo
Created September 25, 2017 01:33
Show Gist options
  • Save adrienmo/eaca761f8d1539810bce722521797ef7 to your computer and use it in GitHub Desktop.
Save adrienmo/eaca761f8d1539810bce722521797ef7 to your computer and use it in GitHub Desktop.
reverse lookup for geolix
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