2  Quick guide

This chapter gets you from zero to a working match in a few minutes, using a tiny in-memory database so you don’t need to download G-NAF first. Everything here actually runs — the output you see below was generated by the code above it, against the current package source.

When you’re ready to match against real Australian addresses, skip to Building a good lookup table.

2.1 Install

# install.packages("devtools")
devtools::install_github("https://github.com/KyleHaynes/gnafr")

2.2 A five-minute, no-download example

A real database is built from a multi-million-row G-NAF file (see Building a good lookup table). To see the whole API working end to end right now, this section builds a database with three hand-written addresses instead.

library(gnafr)
library(data.table)

# ":memory:" creates a database that lives only for this R session.
con <- gnaf_connect(":memory:")
gnaf_init(con)

demo_addresses <- data.table(
  address_label = c(
    "10 MUSGRAVE ROAD, RED HILL QLD 4059",
    "120 MUSGRAVE ROAD, RED HILL QLD 4059",
    "18-20 DRIFT CLOSE, GOLDSBOROUGH QLD 4865"
  ),
  number_first  = c(10L, 120L, 18L),
  number_last   = c(NA_integer_, NA_integer_, 20L),
  street_name   = c("MUSGRAVE", "MUSGRAVE", "DRIFT"),
  street_type   = c("ROAD", "ROAD", "CLOSE"),
  locality_name = c("RED HILL", "RED HILL", "GOLDSBOROUGH"),
  state         = c("QLD", "QLD", "QLD"),
  postcode      = c(4059L, 4059L, 4865L),
  longitude     = c(153.0066, 153.0080, 145.6203),
  latitude      = c(-27.4570, -27.4575, -17.2806)
)

gnaf_add(con, demo_addresses)
gnaf_status(con)
              table  rows
             <char> <num>
1:   gnaf_addresses     0
2: custom_addresses     3

Now match a deliberately messy input string against it:

result <- gnaf_match(
  "unit 5 18-20 drift cl goldsborough 4865",
  con,
  max_results = 2,
  verbose = FALSE
)

result[, .(input_raw, matched, total_score, address_label,
           score_postcode, score_street_name, score_number)]
                                 input_raw matched total_score                            address_label score_postcode score_street_name score_number
                                    <char>  <lgcl>       <int>                                   <char>          <int>             <int>        <int>
1: unit 5 18-20 drift cl goldsborough 4865    TRUE          95 18-20 DRIFT CLOSE, GOLDSBOROUGH QLD 4865             20                40           10

A perfectly clean input scores 100:

gnaf_match("10 Musgrave Road, Red Hill QLD 4059", con, verbose = FALSE)[
  , .(input_raw, matched, total_score, address_label)
]
                             input_raw matched total_score                       address_label
                                <char>  <lgcl>       <int>                              <char>
1: 10 Musgrave Road, Red Hill QLD 4059    TRUE         100 10 MUSGRAVE ROAD, RED HILL QLD 4059

A typo’d postcode (4058 instead of 4059) still matches, with the postcode component scored down rather than the match being rejected — see near-miss postcode credit for why:

gnaf_match("10 Musgrave Road, Red Hill QLD 4058", con, verbose = FALSE)[
  , .(input_raw, matched, total_score, score_postcode, address_label)
]
                             input_raw matched total_score score_postcode                       address_label
                                <char>  <lgcl>       <int>          <int>                              <char>
1: 10 Musgrave Road, Red Hill QLD 4058    TRUE          94             14 10 MUSGRAVE ROAD, RED HILL QLD 4059

A street number that isn’t in the database at all, by contrast, is never returned as a low-scoring match — it’s filtered out before scoring even runs (see the number pre-filter):

gnaf_match("999 Musgrave Road, Red Hill QLD 4059", con, min_score = 0, verbose = FALSE)[
  , .(input_raw, matched, match_status, total_score, address_label)
]
                              input_raw matched match_status total_score address_label
                                 <char>  <lgcl>       <char>       <int>        <char>
1: 999 Musgrave Road, Red Hill QLD 4059   FALSE no_candidate          NA          <NA>

Always close the connection when you’re done with it (in-memory databases simply vanish; file-backed ones should still be disconnected cleanly):

2.3 The two calls you’ll use most

# Connect once per session, reuse the connection across many gnaf_match() calls
con <- gnaf_connect("C:/temp/gnaf.duckdb")

# Match a vector of addresses — this is the function you'll call repeatedly
results <- gnaf_match(addresses, con, max_results = 1, min_score = 60)

gnaf_match()’s two most useful tuning knobs:

Argument Default Effect
max_results 1 Return up to N candidates per input, ranked best first.
min_score 60 Drop candidates scoring below this. Lower it for audit/review workflows; raise it for stricter automated pipelines.

2.4 Where to next