Aller au contenu

Géocoder des adresses et des lieux canadiens

Vous avez un texte qui nomme un lieu au Canada, tapé par une personne ou rangé dans un tableur, et il vous faut un point à placer sur une carte. Ce tutoriel choisit la bonne recherche pour vos données, indique quelle confiance accorder à chaque réponse et traite une liste entière d'un coup.

Recherche cartographique, pas validation d'adresse

unmap trouve le lieu que quelqu'un veut dire, à partir de données canadiennes ouvertes, pour que vous puissiez le placer sur une carte. Il ne vérifie pas qu'une adresse peut recevoir du courrier, ne la corrige pas au format de Postes Canada et ne confirme pas qu'un logement existe. S'il vous faut une vérification d'adresse certifiée pour le courrier, c'est un autre type de produit, et unmap n'en est pas un.

résultat en direct
le code qui l'a produit
import { Unmap } from "@unmap/sdk";

const unmap = new Unmap({ key: "um_live_..." });

const results = await unmap.geocoder.search("17 Ave SW Calgary", { limit: 3 });

Le code est du TypeScript ordinaire. Pour le câblage React, Next.js, Vue ou Nuxt, partez des recettes par cadriciel.

D'où viennent les réponses

Six sources ouvertes sont fusionnées en un seul corpus : OpenStreetMap, OpenAddresses (Canada), le Registre national des adresses de Statistique Canada, la Base de données toponymiques du Canada (BDTC) de RNCan, Who's On First et GeoNames. Les enregistrements qui décrivent le même lieu sont fusionnés avant l'indexation et un seul survit ; source sur un résultat nomme celui-là. Les noms anglais et français sont sur le même enregistrement.

La couverture s'arrête à la frontière. Une recherche inverse ou à proximité ancrée hors du Canada répond 422 outside_coverage, et une recherche ne retourne jamais de résultat dans un autre pays.

Cherchez du texte libre

search prend le texte tel qu'il est écrit et classe par pertinence. Nommer une ville dans la requête la favorise sans rien exclure. Quand vous en savez plus sur le lecteur, dites-le avec les contrôles : region exclut les autres provinces, bbox exclut tout ce qui est hors d'une boîte, et focus ne fait que favoriser les résultats proches d'un point.

const results = await unmap.geocoder.search("main st", {
  region: "NS",
  focus: [-63.5752, 44.6488],
  limit: 5,
});

La différence entre focus et les deux autres est celle à bien saisir. focus réordonne et n'exclut rien ; region et bbox retirent des résultats, et quand rien ne survit vous recevez [].

Utilisez la recherche structurée quand vous avez les parties

Si vos données sont déjà réparties en colonnes, envoyez les colonnes. Un moteur de texte libre doit deviner quel mot est la ville, et une supposition ratée devient un mot de recherche ordinaire.

const [hit] = await unmap.geocoder.structured({
  address: "101 17 Ave SW",
  city: "Calgary",
  region: "AB",
});

address et city décident quels enregistrements sont candidats. region et postalcode les restreignent : ils excluent les enregistrements qui les contredisent et gardent ceux qui n'en disent rien.

Jugez la qualité de la réponse

Chaque résultat dit à quel point il correspond à ce que vous avez envoyé et avec quelle précision il est placé, dans deux champs distincts. Décidez de ce que votre application accepte avant de stocker un point.

import type { GeocodeResult } from "@unmap/sdk";
 
function isExactPoint(result: GeocodeResult): boolean {
  return result.match_type === "exact" && result.precision === "point";
}

match_type porte sur votre requête : exact, partial, ou fallback quand vous avez donné un numéro civique et que la réponse est la rue ou la ville. precision porte sur la position : point désigne un enregistrement d'adresse ou de lieu distinct dans la source, pas une précision au toit, et locality est un centroïde. Rien n'est interpolé : une adresse absente de toutes les sources revient comme la rue, marquée fallback, plutôt que comme un point inventé. match_reasons nomme ce qui n'a pas correspondu.

Géocodez une liste

batch envoie jusqu'à 100 requêtes en une seule demande et répond dans le même ordre. Le client découpe pour vous une liste plus longue en demandes de 100. Chaque requête non vide compte pour un appel, comme si vous l'envoyiez seule.

const rows = await unmap.geocoder.batch(["17 Ave SW Calgary", "Trois-Rivières", "ᐃᖃᓗᐃᑦ"], {
  limit: 1,
});
 
for (const [best] of rows) {
  console.log(best?.name, best?.match_type);
}

Une requête sans correspondance donne [] à sa place, jamais une supposition : le résultat reste aligné sur vos lignes. Pour un fichier CSV sur votre propre machine, voir Géocodage par lots.

Là où cette approche se trompe

  • Ce n'est pas une validation postale. Un résultat vous dit où se trouve un lieu. Il ne vous dit pas que le courrier y arrivera.
  • Un code postal n'est pas une clé de recherche. Une requête qui n'est qu'un code postal ne retourne pas la zone que le code couvre. Envoyez-le avec la rue, où il restreint les candidats, et attendez-vous à postalcode_not_verified quand l'enregistrement source n'en a pas.
  • Les logements sont rarement dans les données. Une requête qui en nomme un revient habituellement sans lui, marquée unit_not_verified. Gardez le numéro de logement dans votre propre champ.
  • Une route rurale répond par la communauté. RR 2 Okotoks se résout en Okotoks, pas en une boîte aux lettres. Une requête qui n'est que RR 2 reçoit un 400 qui demande la communauté.
  • Une description légale de terrain n'est pas une adresse. Envoyez NW-25-24-1-W5 à la recherche tel quel ; voir Trouver une description légale de terrain en Alberta.

Voir aussi