When playing with new features in databases, it’s often helpful to be able to have a meaningful amount of data, to get closer to at least approximating a real workload. My use case revolved around needing to generate random phrases, as well as a random nearby coordinate.

I’m a huge fan of Elixir, and so it was my language of choice for this. I didn’t want to deal with the overhead of adding any dependencies, so communicating directly with Postgres through Elixir was not an option. I decided I would have the script generate a bunch of INSERT statements that I could then pass to Postgres directly.

It ended up looking like this:

# words.exs
# random words generated from https://www.randomlists.com/random-words
words = ["general", "sweet", "boot", "enormous", "thumb", "rinsing", "soda", "bells", "hurry", "class", "wrap", "face", "creature", "taller", "angle", "pin", "purple", "driving", "fun", "elderly", "guitar", "magical", "pie", "acoustics", "pretend", "electricity", "cheese", "turkey", "tea"]
central_latitude = 43.0384303
central_longitude = -87.9079503
# file to create
file_path = "./sql.sql"
stream = Stream.repeatedly(fn ->
  # get coordinate within .033 degrees in each direction
  latitude = central_latitude + :random.uniform / 30.0
  longitude = central_longitude + :random.uniform / 30.0
  # Grab 5 random words from the list, and join them with a space to create one string
  words = Enum.take_random(words, 5) |> Enum.join(" ")
  # Emit desired string
  "INSERT INTO test (words, words_vector, geo) VALUES ('#{words}', to_tsvector('#{words}'), ST_GeomFromText('POINT(#{longitude}  #{latitude})', 4326));"
# Lazily take as many rows as we'd like to generate, and then join them with a line.
sql = Stream.take(stream, 250000)
      |> Enum.join("n")
File.write!(file_path, sql, [:write])
# run with:
# >elixir words.exs

Once it’s run, I have a file with 250,000 insert statements that can be run through Postgres with:

psql -d database_name --quiet -f sql.sql

It wasn’t the most efficient way to solve the issue, but it didn’t need to be 🙂

Feel free to contact me on Twitter at @mitchellhenke with any questions or clarifications. Thanks for reading!