add index for weather

This commit is contained in:
Graham McIntire 2025-07-03 13:07:34 -05:00
parent c8ee465015
commit 48b8c7de94
No known key found for this signature in database
4 changed files with 45 additions and 51 deletions

View file

@ -404,6 +404,34 @@ defmodule Aprsme.Packets do
get_packets_for_replay(opts_with_time)
end
@doc """
Gets weather packets for a specific callsign within a time range.
This is optimized for weather queries by filtering at the database level.
"""
@impl true
@spec get_weather_packets(String.t(), DateTime.t(), DateTime.t(), map()) :: [struct()]
def get_weather_packets(callsign, start_time, end_time, opts \\ %{}) do
limit = Map.get(opts, :limit, 500)
base_query = from(p in Packet, order_by: [asc: p.received_at])
query =
base_query
|> filter_by_time(%{start_time: start_time, end_time: end_time})
|> filter_by_callsign(%{callsign: callsign})
|> filter_weather_packets()
|> limit_results(%{limit: limit})
|> select_with_virtual_coordinates()
Repo.all(query)
end
# Filter for weather packets at the database level
defp filter_weather_packets(query) do
from p in query,
where: p.data_type == "weather" or (p.symbol_table_id == "/" and p.symbol_code == "_")
end
@doc """
Retrieves a continuous stream of stored packets for replay in chronological order.

View file

@ -7,6 +7,7 @@ defmodule Aprsme.PacketsBehaviour do
@callback stream_packets_for_replay(map()) :: Enumerable.t()
@callback get_packets_for_replay(map()) :: list()
@callback get_recent_packets(map()) :: list()
@callback get_weather_packets(String.t(), DateTime.t(), DateTime.t(), map()) :: list()
@callback clean_old_packets() :: {:ok, non_neg_integer()} | {:error, any()}
@callback clean_packets_older_than(pos_integer()) :: {:ok, non_neg_integer()} | {:error, any()}
end

View file

@ -2,8 +2,6 @@ defmodule AprsmeWeb.WeatherLive.CallsignView do
@moduledoc false
use AprsmeWeb, :live_view
import Jason
alias Aprsme.Packets
alias AprsmeWeb.MapLive.PacketUtils
@ -57,59 +55,12 @@ defmodule AprsmeWeb.WeatherLive.CallsignView do
end
defp get_weather_history(callsign, start_time, end_time) do
opts = %{callsign: callsign, start_time: start_time, end_time: end_time, limit: 1000}
opts
|> Packets.get_packets_for_replay()
|> Enum.filter(&PacketUtils.weather_packet?/1)
|> Enum.sort_by(& &1.received_at)
Packets.get_weather_packets(callsign, start_time, end_time, %{limit: 500})
end
defp default_time_range do
now = DateTime.utc_now()
{DateTime.add(now, -48 * 3600, :second), now}
end
defp build_temp_chart_svg(history) do
data =
history
|> Enum.map(fn pkt ->
[pkt.received_at, pkt.temperature, pkt.dew_point]
end)
|> Enum.filter(fn [_, t, d] -> not is_nil(t) and not is_nil(d) end)
if data == [] do
"<svg width=\"600\" height=\"300\"><text x=\"50\" y=\"150\">No data</text></svg>"
else
dataset = Dataset.new(data, ["Time", "Temperature", "Dew Point"])
dataset
|> Plot.new(LinePlot, 600, 300, smoothed: false)
|> Plot.titles("Temperature & Dew Point (°F)", nil)
|> Plot.axis_labels("Time", "°F")
|> Plot.to_svg()
end
end
defp build_humidity_chart_svg(history) do
data =
history
|> Enum.map(fn pkt ->
[pkt.received_at, pkt.humidity]
end)
|> Enum.filter(fn [_, h] -> not is_nil(h) end)
if data == [] do
"<svg width=\"600\" height=\"300\"><text x=\"50\" y=\"150\">No data</text></svg>"
else
dataset = Dataset.new(data, ["Time", "Humidity"])
dataset
|> Plot.new(LinePlot, 600, 300, smoothed: false)
|> Plot.titles("Humidity (%)", nil)
|> Plot.axis_labels("Time", "%")
|> Plot.to_svg()
end
{DateTime.add(now, -24 * 3600, :second), now}
end
defp calc_dew_point(temp, humidity) when is_number(temp) and is_number(humidity) do

View file

@ -0,0 +1,14 @@
defmodule Aprsme.Repo.Migrations.AddSenderIndexToPackets do
use Ecto.Migration
def change do
# Add index on sender field for efficient callsign filtering
create index(:packets, [:sender])
# Add compound index for sender + received_at for efficient time-based callsign queries
create index(:packets, [:sender, :received_at])
# Add compound index for sender + has_position for weather packet queries
create index(:packets, [:sender, :has_position])
end
end