kip

kip

ex_cldr Core Team

Tz_world / timezone_boundary_builder update

tz_world is a library that maps a location (lat, lng) to a timezone.

From time-to-time the base data in timzone_boundary_builder is updated based upon updates to the IANA timezone database.

With the IANA timezone database being updated to version 2020a on April 23rd, timezone_boundary_builder has now also updated its release.

For current users of tz_world you can update the data source in two ways:

  1. Run mix tz_world.update
  2. In a running system, call TzWorld.reload_timezone_data/0. Application restart is not required - the new data is downloaded and installed in the running system.

First Post! Switch mode

LostKobrakai

LostKobrakai

Yeah, I can finally replace my manually imported world map in my db without update logic :slight_smile:

Most Liked

kip

kip

ex_cldr Core Team

I have refactored tz_world to separate different backend strategies. Please feel free to give it a try, I plan to release a new version on hex later this week.

New Backend Access modules

  • TzWorld.Backend.Memory which retains all data in memory for fastest performance at the expense of using approximately 1Gb of memory
  • TzWorld.Backend.Dets which uses Erlang’s :dets data store. This uses negligible memory at the expense of slow access times (approximaltey 500ms in testing)
  • TzWorld.Backend.DetsWithIndexCache which balances memory usage and performance. This backend is recommended in most situations since its performance is similar to TzWorld.Backend.Memory (about 5% slower in testing) and uses about 25Mb of memory
  • TzWorld.Backend.Ets which uses :ets for storage. With the default settings of :compressed for the :ets table its memory consumption is about 512Mb but with access that is over 20 times slower than TzWorld.Backend.DetsWithIndexCache

Most interesting is that by caching the bounding boxes in memory, the backend TzWorld.Backend.DetsWithIndexCache looks to be a good balance of memory utilisation and performance. It uses only ~20Mb of memory to store the bounding boxes and has performance similar to the in-memory backend.

Basic Benchmark

Name                                 ips        average  deviation         median         99th %
Backend Memory                     52.34       19.10 ms    ±14.86%       18.34 ms       30.62 ms
Backend DetsWithIndexCache         50.10       19.96 ms    ±13.15%       20.79 ms       24.66 ms
Backend Ets                         2.33      428.53 ms     ±2.51%      432.73 ms      441.58 ms
Backend Dets                        0.59     1693.80 ms     ±9.62%     1646.47 ms     2018.27 ms

Comparison: 
Backend Memory                     52.34
Backend DetsWithIndexCache         50.10 - 1.04x slower +0.85 ms
Backend Ets                         2.33 - 22.43x slower +409.43 ms
Backend Dets                        0.59 - 88.66x slower +1674.70 ms
kip

kip

ex_cldr Core Team

It’s been a year since any functional updates or bug fixes for tz_world so today I published tz_world version 1.0.0.

Really, the only change is the version number. Still actively maintained, just no open issues or functional enhancement requests.

kip

kip

ex_cldr Core Team

Yep, turns out its really big (and this is the version not including geo data for the oceans).

I will, for the next release:

  1. Turn the storage and access mechanisms into a behaviour
  2. Implement a :dets backend (first priority)
  3. Implement a PostGis backend (which was already written by the original author of tz_world)
  4. Implement a non-PostGis backend for filtering by bounding box

Probably going to take a couple of weeks to get this done.

Thanks for the vigilance @LostKobrakai.

Last Post!

kip

kip

ex_cldr Core Team

I’ve just published tz_world version 2.1.0.

The primary changes are:

  • The addition of a new backend, TzWorld.Backend.SpatialIndex that implements a pure-Elixir R-tree (Sort-Tile-Recursive packed) index. This index results in substantially faster lookups.

  • File and :json streaming to optimise the memory usage when running mix tz_world.update. This task used to consume a peak of 980Mb. It now consumes a peak of 70Mb.

The reason for the major release bump are:

  • The removal of two backends that just aren’t good choices: TzWorld.Backend.Memory and TzWorld.Backend.Ets; and

  • The new format of the on-disk data resulting from the new streaming build.

Performance comparisons

Benchmarked against the previous backends across a categorised fixture set (dense regions, sparse/large zones, small/thin zones, ocean points with no match, points adjacent to the international date line):

Input category Speedup vs. the next-fastest existing backend
ocean (no-match) 18.2×
sparse_or_large 1.64×
dense (cities) 1.43×
random uniform 1.42×
small_or_thin 1.08×

The largest wins are on no-match queries: previously, points in the open ocean caused a full scan of every shape’s bounding box; the R-tree exits at the root.

Memory comparison of mix tz_world.update

Version 2.0 rewrote the data-update pipeline to stream end-to-end. The source zip is downloaded straight to a temp file (no in-memory body), unzipped to disk (no in-memory JSON), parsed in 64 KiB chunks via OTP’s built-in :json module with a feature-diverting decoder callback, and each Geo.Polygon / Geo.MultiPolygon is written to the on-disk index as it is decoded. The full GeoJSON is never resident in memory at any point.

Measured BEAM peak memory of mix tz_world.update on the without-oceans dataset (158 MB GeoJSON, 419 shapes, post-GC sampled):

Version Peak BEAM memory during update
1.x ≈ 920 MB
2.x ≈ 70 MB

Where Next?

Trending in Announcing Top

bluzky
You may know https://ui.shadcn.com/, a UI component library for React. I really love it’s design style and components. I’ve built some co...
385 14863 120
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
shahryarjb
The Chelekom project is a library of Phoenix and LiveView components generated via Mix tasks to fit developer needs seamlessly. One of i...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
zachdaniel
Introducing AshStorage! Attachment and file management that slots directly into your resources :smiling_face_with_sunglasses: I had hope...
New

Other Trending Topics Top

type1fool
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
akoutmos
@hugobarauna and I (Alex Koutmos) have been hard at work on writing a book on Nerves that takes you from simply blinking LEDs to building...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
bjorng
We want to introduce a new native datatype to Erlang: native records. Although replacing all tuple records with native records is not our...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
yureehuh
Introduction Founded in 2017 by landscape ecologist and fire mitigation expert Harry Statter, Frontline developed the first fully integra...
New

We're in Beta

About us Mission Statement