fix: critical subscriber matching and performance improvements
- Add missing wireless_mac and wireless_ip to schema validation (was causing highest-confidence matches to be rejected) - Optimize account lookup to load once instead of 5x per refresh (eliminates N+1 query performance issue) - Preserve all matching phases with proper signature updates
This commit is contained in:
parent
a19155f3de
commit
1a9a6e0ef6
2 changed files with 16 additions and 21 deletions
|
|
@ -39,7 +39,7 @@ defmodule Towerops.Gaiia.DeviceSubscriberLink do
|
|||
:subscriber_mac
|
||||
])
|
||||
|> validate_required([:organization_id, :device_id, :gaiia_account_id, :match_method, :confidence])
|
||||
|> validate_inclusion(:match_method, ~w(arp_ip arp_mac subnet site_fallback))
|
||||
|> validate_inclusion(:match_method, ~w(wireless_mac wireless_ip arp_ip arp_mac subnet site_fallback))
|
||||
|> validate_inclusion(:confidence, ~w(high medium low))
|
||||
|> unique_constraint([:device_id, :gaiia_account_id])
|
||||
|> foreign_key_constraint(:organization_id)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,9 @@ defmodule Towerops.Gaiia.SubscriberMatching do
|
|||
# Load all wireless client entries for this org's devices
|
||||
wireless_clients = load_wireless_clients(organization_id)
|
||||
|
||||
# Load account lookup once for all phases (performance optimization)
|
||||
account_lookup = load_account_id_lookup(organization_id)
|
||||
|
||||
# Build lookup maps
|
||||
arp_by_ip = Map.new(arp_entries, fn e -> {e.ip_address, e} end)
|
||||
arp_by_mac = Map.new(arp_entries, fn e -> {normalize_mac(e.mac_address), e} end)
|
||||
|
|
@ -76,26 +79,28 @@ defmodule Towerops.Gaiia.SubscriberMatching do
|
|||
wc_by_ip = wireless_clients |> Enum.filter(& &1.ip_address) |> Map.new(fn w -> {w.ip_address, w} end)
|
||||
|
||||
# Phase 1: Wireless client MAC match (highest confidence)
|
||||
{wc_mac_matched, wc_mac_links} = match_by_wireless_mac(items, wc_by_mac, organization_id, now)
|
||||
{wc_mac_matched, wc_mac_links} = match_by_wireless_mac(items, wc_by_mac, account_lookup, organization_id, now)
|
||||
|
||||
# Phase 2: Wireless client IP match (high confidence)
|
||||
remaining_after_wc_mac = Enum.reject(items, &MapSet.member?(wc_mac_matched, &1.id))
|
||||
{wc_ip_matched, wc_ip_links} = match_by_wireless_ip(remaining_after_wc_mac, wc_by_ip, organization_id, now)
|
||||
|
||||
{wc_ip_matched, wc_ip_links} =
|
||||
match_by_wireless_ip(remaining_after_wc_mac, wc_by_ip, account_lookup, organization_id, now)
|
||||
|
||||
# Phase 3: ARP IP match (medium confidence)
|
||||
matched_so_far = MapSet.union(wc_mac_matched, wc_ip_matched)
|
||||
remaining_after_wc = Enum.reject(items, &MapSet.member?(matched_so_far, &1.id))
|
||||
{ip_matched, ip_links} = match_by_arp_ip(remaining_after_wc, arp_by_ip, organization_id, now)
|
||||
{ip_matched, ip_links} = match_by_arp_ip(remaining_after_wc, arp_by_ip, account_lookup, organization_id, now)
|
||||
|
||||
# Phase 4: ARP MAC match (medium confidence)
|
||||
matched_so_far = MapSet.union(matched_so_far, ip_matched)
|
||||
remaining_after_ip = Enum.reject(items, &MapSet.member?(matched_so_far, &1.id))
|
||||
{mac_matched, mac_links} = match_by_arp_mac(remaining_after_ip, arp_by_mac, organization_id, now)
|
||||
{mac_matched, mac_links} = match_by_arp_mac(remaining_after_ip, arp_by_mac, account_lookup, organization_id, now)
|
||||
|
||||
# Phase 5: Site fallback (low confidence)
|
||||
matched_ids = MapSet.union(matched_so_far, mac_matched)
|
||||
remaining = Enum.reject(items, &MapSet.member?(matched_ids, &1.id))
|
||||
site_links = match_by_site_fallback(remaining, organization_id, now)
|
||||
site_links = match_by_site_fallback(remaining, account_lookup, organization_id, now)
|
||||
|
||||
all_links = wc_mac_links ++ wc_ip_links ++ ip_links ++ mac_links ++ site_links
|
||||
|
||||
|
|
@ -259,9 +264,7 @@ defmodule Towerops.Gaiia.SubscriberMatching do
|
|||
|> Map.new()
|
||||
end
|
||||
|
||||
defp match_by_wireless_mac(items, wc_by_mac, org_id, now) do
|
||||
account_lookup = load_account_id_lookup(org_id)
|
||||
|
||||
defp match_by_wireless_mac(items, wc_by_mac, account_lookup, org_id, now) do
|
||||
{matched_ids, links} =
|
||||
Enum.reduce(items, {MapSet.new(), []}, fn item, {matched, acc} ->
|
||||
normalized = normalize_mac(item.mac_address)
|
||||
|
|
@ -292,9 +295,7 @@ defmodule Towerops.Gaiia.SubscriberMatching do
|
|||
{matched_ids, Enum.reverse(links)}
|
||||
end
|
||||
|
||||
defp match_by_wireless_ip(items, wc_by_ip, org_id, now) do
|
||||
account_lookup = load_account_id_lookup(org_id)
|
||||
|
||||
defp match_by_wireless_ip(items, wc_by_ip, account_lookup, org_id, now) do
|
||||
{matched_ids, links} =
|
||||
Enum.reduce(items, {MapSet.new(), []}, fn item, {matched, acc} ->
|
||||
wc = if item.ip_address, do: Map.get(wc_by_ip, item.ip_address)
|
||||
|
|
@ -324,9 +325,7 @@ defmodule Towerops.Gaiia.SubscriberMatching do
|
|||
{matched_ids, Enum.reverse(links)}
|
||||
end
|
||||
|
||||
defp match_by_arp_ip(items, arp_by_ip, org_id, now) do
|
||||
account_lookup = load_account_id_lookup(org_id)
|
||||
|
||||
defp match_by_arp_ip(items, arp_by_ip, account_lookup, org_id, now) do
|
||||
{matched_ids, links} =
|
||||
Enum.reduce(items, {MapSet.new(), []}, fn item, {matched, acc} ->
|
||||
arp = if item.ip_address, do: Map.get(arp_by_ip, item.ip_address)
|
||||
|
|
@ -356,9 +355,7 @@ defmodule Towerops.Gaiia.SubscriberMatching do
|
|||
{matched_ids, Enum.reverse(links)}
|
||||
end
|
||||
|
||||
defp match_by_arp_mac(items, arp_by_mac, org_id, now) do
|
||||
account_lookup = load_account_id_lookup(org_id)
|
||||
|
||||
defp match_by_arp_mac(items, arp_by_mac, account_lookup, org_id, now) do
|
||||
{matched_ids, links} =
|
||||
Enum.reduce(items, {MapSet.new(), []}, fn item, {matched, acc} ->
|
||||
normalized = normalize_mac(item.mac_address)
|
||||
|
|
@ -389,9 +386,7 @@ defmodule Towerops.Gaiia.SubscriberMatching do
|
|||
{matched_ids, Enum.reverse(links)}
|
||||
end
|
||||
|
||||
defp match_by_site_fallback(items, org_id, now) do
|
||||
account_lookup = load_account_id_lookup(org_id)
|
||||
|
||||
defp match_by_site_fallback(items, account_lookup, org_id, now) do
|
||||
# Load network site -> TowerOps site mappings
|
||||
site_mappings =
|
||||
NetworkSite
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue