wmnnd

wmnnd

Stable Partitioning Algorithm With No Side Effects

Hey folks,

I need to implement some sort of partitioning of data records. A certain part of records should be processed in one way, another part in another way. So I thought it would be nice to implement a stable partitioning algorithm that splits datasets into a given number of partitions with given proportions.

So, given three partitions and their relative thresholds

[a: 0, b: 0.33, c: 0.66]

I want to be able to take a term, pipe it into a partitioning function and receive the name of the partition:

partition("foo", partitions: partitions) # => :a
partition("bar", partitions: partitions) # => :c
partition("foobar", partitions: partitions) # => :b

My idea is to use a simple hash function to generate a uniformly distributed stable pseudo-random number for any term and then pick the suitable partition.

Here’s what I’ve come up. I’m really curious to see what you think of the approach or if you have ideas for better/faster/more elegant solutions.

defmodule Partitioner do
  @spec partition(term :: []) :: integer()
  def partition(term, opts \\ []) do
    term
    |> normalize(opts)
    |> do_partition(opts)
  end

  defp normalize(term, opts) do
    salt = Keyword.get(opts, :salt, nil)

    {term, salt}
    |> :erlang.term_to_binary()
    |> do_hash()
    |> :binary.first()
    |> do_normalize()
  end

  defp do_hash(binary), do: :crypto.hash(:sha, binary)

  defp do_normalize(int), do: int / 255

  defp do_partition(float, opts) do
    opts
    |> Keyword.get(:partitions, a: 0, b: 0.5)
    |> Enum.max_by(&match_partition(float, &1))
    |> elem(0)
  end

  defp match_partition(float, {_, threshold}) when float > threshold, do: threshold

  defp match_partition(_, _), do: 0
end

Marked As Solved

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Sounds like a job for erlang — OTP 29.0.2 (erts 17.0.2)

iex(10)> partitions = [:a, :b, :c]                                   
[:a, :b, :c]
iex(11)> ["foo", "bar", "foobar"] |> Enum.map(&:erlang.phash2(&1, 2)) |> Enum.map(&Enum.at(partitions, &1))
[:a, :a, :b]

Also Liked

wmnnd

wmnnd

That’s awesome, I was half-expecting to find a function like this in the Erlang standard library :smiley:

Last Post!

wmnnd

wmnnd

That’s awesome, I was half-expecting to find a function like this in the Erlang standard library :smiley:

Where Next?

Popular in Questions Top

joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

Other popular topics Top

vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

We're in Beta

About us Mission Statement