addrkit: 'selfcheck' command — resolve the whole registry against itself
Exhaustive check of all 72,825 indexed addresses: 72,811 exact (99.98%), 14 partial (malformed house units, e.g. '27с1', '32 к 1/4-1/6'), 0 not_found, 0 ambiguous.
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
|||||||
"git.totmin.ru/en2zmax/addrkit/internal/adapters/llm"
|
"git.totmin.ru/en2zmax/addrkit/internal/adapters/llm"
|
||||||
"git.totmin.ru/en2zmax/addrkit/internal/adapters/registrystore"
|
"git.totmin.ru/en2zmax/addrkit/internal/adapters/registrystore"
|
||||||
"git.totmin.ru/en2zmax/addrkit/internal/config"
|
"git.totmin.ru/en2zmax/addrkit/internal/config"
|
||||||
|
"git.totmin.ru/en2zmax/addrkit/internal/domain/address"
|
||||||
"git.totmin.ru/en2zmax/addrkit/internal/domain/match"
|
"git.totmin.ru/en2zmax/addrkit/internal/domain/match"
|
||||||
"git.totmin.ru/en2zmax/addrkit/internal/eval"
|
"git.totmin.ru/en2zmax/addrkit/internal/eval"
|
||||||
"git.totmin.ru/en2zmax/addrkit/internal/seed"
|
"git.totmin.ru/en2zmax/addrkit/internal/seed"
|
||||||
@@ -35,6 +36,8 @@ func main() {
|
|||||||
os.Exit(runResolve(os.Args[2:]))
|
os.Exit(runResolve(os.Args[2:]))
|
||||||
case "eval":
|
case "eval":
|
||||||
os.Exit(runEval(os.Args[2:]))
|
os.Exit(runEval(os.Args[2:]))
|
||||||
|
case "selfcheck":
|
||||||
|
os.Exit(runSelfcheck(os.Args[2:]))
|
||||||
case "help", "-h", "--help":
|
case "help", "-h", "--help":
|
||||||
usage()
|
usage()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
@@ -53,6 +56,7 @@ Usage:
|
|||||||
addrkit verify -db registry.db
|
addrkit verify -db registry.db
|
||||||
addrkit resolve -db registry.db "2-я Станционная улица 1/1 стр."
|
addrkit resolve -db registry.db "2-я Станционная улица 1/1 стр."
|
||||||
addrkit eval -db registry.db [-sample 500] [-seed 1]
|
addrkit eval -db registry.db [-sample 500] [-seed 1]
|
||||||
|
addrkit selfcheck -db registry.db
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,3 +269,57 @@ func (c *countingRewriter) avg() time.Duration {
|
|||||||
}
|
}
|
||||||
return c.total / time.Duration(c.calls)
|
return c.total / time.Duration(c.calls)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// runSelfcheck resolves every indexed address against the index and reports how
|
||||||
|
// many resolve back to themselves. This is the strongest answer to "do all
|
||||||
|
// addresses resolve?": it exercises the whole registry, not a sample.
|
||||||
|
func runSelfcheck(args []string) int {
|
||||||
|
fs := flag.NewFlagSet("selfcheck", flag.ExitOnError)
|
||||||
|
db := fs.String("db", "", "SQLite database")
|
||||||
|
_ = fs.Parse(args)
|
||||||
|
if *db == "" {
|
||||||
|
fmt.Fprintln(os.Stderr, "selfcheck: -db is required")
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
_, entries, err := registrystore.Load(*db)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "selfcheck: %v\n", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
resolver := match.NewResolver(match.NewIndex("selfcheck", entries, match.DefaultOptions()), nil)
|
||||||
|
|
||||||
|
exact := 0
|
||||||
|
byStatus := map[string]int{}
|
||||||
|
var failures []string
|
||||||
|
for _, e := range entries {
|
||||||
|
res := resolver.Resolve(context.Background(), e.Address)
|
||||||
|
if res.Status == address.StatusFound && sameEntry(res.Address, e) {
|
||||||
|
exact++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
byStatus[string(res.Status)]++
|
||||||
|
if len(failures) < 40 {
|
||||||
|
failures = append(failures, fmt.Sprintf("[%s] %q -> %q", res.Status, e.Address, res.Address))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out := map[string]any{
|
||||||
|
"entries": len(entries),
|
||||||
|
"exact": exact,
|
||||||
|
"exact_rate": float64(exact) / float64(max(len(entries), 1)),
|
||||||
|
"non_exact": byStatus,
|
||||||
|
"failures": failures,
|
||||||
|
}
|
||||||
|
enc := json.NewEncoder(os.Stdout)
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
_ = enc.Encode(out)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// sameEntry reports whether a resolved address is the same street and house
|
||||||
|
// unit as the registry entry it came from.
|
||||||
|
func sameEntry(resolved string, e address.Entry) bool {
|
||||||
|
p := address.Parse(resolved)
|
||||||
|
return p.StreetKey == e.StreetKey &&
|
||||||
|
p.House == e.House && p.HouseFrac == e.HouseFrac && p.HouseLetter == e.HouseLetter &&
|
||||||
|
p.Building == e.Building && p.BuildingFrac == e.BuildingFrac && p.BuildingLetter == e.BuildingLetter
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user