Batch geocoding: duizenden adressen verwerken
Terug naar blog
💡 Concepten

Batch geocoding: duizenden adressen verwerken

GeoRex Team10 oktober 202510 min leestijd

Leer hoe je efficiënt grote hoeveelheden adressen geocodeert met batch processing, async patterns en optimale performance.

Wanneer je honderden of duizenden adressen moet geocoderen - denk aan CRM-imports, data migraties of analytics - is efficiënte batch processing essentieel. In dit artikel behandelen we strategieën voor optimale throughput zonder je API limits te overschrijden.

Performance vergelijking tussen sequential, parallel en async processing
Batch processing kan tot 10x sneller zijn dan sequentiële requests

Batch vs Single requests

GeoRex biedt twee manieren om adressen te geocoderen:

MethodeEndpointMax adressenUse case
Single/geocode?q=...&token=TOKEN1Real-time, checkout
LoopMeerdere /geocode callsOnbeperkt*Bulk import, analytics

Bulk geocoding implementeren

Met de token-based authenticatie kun je efficiënt meerdere adressen verwerken. Het token is 10 minuten geldig, dus je kunt veel requests doen met één token:

batch-request.js
// Token ophalen (geldig voor 10 minuten)
async function getToken(apiKey) {
const res = await fetch('https://api.georex.nl/api/token', {
method: 'POST',
headers: { 'X-API-Key': apiKey }
});
return (await res.json()).token;
}
// Enkele geocode request
async function geocodeOne(address, token) {
const query = encodeURIComponent(address);
const res = await fetch(
`https://api.georex.nl/geocode?q=${query}&token=${token}`
);
return res.json();
}
// Batch verwerking met rate limiting
async function batchGeocode(addresses, apiKey) {
const token = await getToken(apiKey);
const results = [];
for (const address of addresses) {
const result = await geocodeOne(address, token);
if (result.features?.length > 0) {
const [lon, lat] = result.features[0].geometry.coordinates;
results.push({
address,
status: 'found',
lat, lon,
...result.features[0].properties
});
} else {
results.push({ address, status: 'not_found' });
}
// Kleine delay om rate limits te respecteren
await new Promise(r => setTimeout(r, 100));
}
return results;
}
// Gebruik
const results = await batchGeocode(
['Damrak 1, Amsterdam', 'Coolsingel 40, Rotterdam'],
'gx_live_your_key'
);
console.log(results);

Grote datasets verwerken

Voor grote datasets moet je chunken, token vernieuwing en rate limiting implementeren:

bulk-processor.js
class BulkGeocoder {
constructor(apiKey, options = {}) {
this.apiKey = apiKey;
this.batchSize = options.batchSize || 100;
this.delayBetweenRequests = options.delay || 100; // ms
this.maxRetries = options.maxRetries || 3;
this.token = null;
this.tokenExpiry = 0;
}
// Token management (vernieuw als bijna verlopen)
async getToken() {
if (!this.token || Date.now() > this.tokenExpiry - 60000) {
const res = await fetch('https://api.georex.nl/api/token', {
method: 'POST',
headers: { 'X-API-Key': this.apiKey }
});
const data = await res.json();
this.token = data.token;
this.tokenExpiry = Date.now() + (data.expires_in * 1000);
}
return this.token;
}
/**
* Geocodeer een grote dataset
* @param {string[]} addresses - Array van adressen
* @param {Function} onProgress - Callback voor voortgang
*/
async processAll(addresses, onProgress) {
const results = [];
const chunks = this.chunkArray(addresses, this.batchSize);
for (let i = 0; i < chunks.length; i++) {
const chunk = chunks[i];
// Progress callback
if (onProgress) {
onProgress({
current: i + 1,
total: chunks.length,
processed: results.length,
totalAddresses: addresses.length
});
}
// Process chunk met retry
const chunkResults = await this.processChunkWithRetry(chunk);
results.push(...chunkResults);
}
return results;
}
async processChunkWithRetry(addresses) {
let lastError;
for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
try {
return await this.processChunk(addresses);
} catch (error) {
lastError = error;
if (error.status === 429) {
const waitTime = this.delayBetweenRequests * attempt * 10;
console.log(`Rate limited, wacht ${waitTime}ms...`);
await this.sleep(waitTime);
} else if (attempt < this.maxRetries) {
await this.sleep(1000 * attempt);
}
}
}
throw lastError;
}
async processChunk(addresses) {
const results = [];
for (const address of addresses) {
const token = await this.getToken();
const query = encodeURIComponent(address);
const response = await fetch(
`https://api.georex.nl/geocode?q=${query}&token=${token}`
);
if (!response.ok) {
const error = new Error(`Request failed: ${response.status}`);
error.status = response.status;
throw error;
}
const data = await response.json();
if (data.features?.length > 0) {
const [lon, lat] = data.features[0].geometry.coordinates;
results.push({
address,
status: 'found',
lat, lon,
...data.features[0].properties
});
} else {
results.push({ address, status: 'not_found' });
}
await this.sleep(this.delayBetweenRequests);
}
return results;
}
chunkArray(array, size) {
const chunks = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Gebruik
const geocoder = new BulkGeocoder('gx_live_your_key');
const addresses = [
'Damrak 1, Amsterdam',
'Coolsingel 40, Rotterdam',
// ... nog duizenden adressen
];
const results = await geocoder.processAll(addresses, (progress) => {
console.log(`Chunk ${progress.current}/${progress.total} (${progress.processed} adressen verwerkt)`);
});
console.log(`Klaar! ${results.length} adressen geocodeerd.`);

Parallelle verwerking

Voor nog snellere verwerking kun je meerdere batches parallel uitvoeren (mits je rate limit dit toestaat):

parallel-processing.js
const processParallel = async (addresses, concurrency = 5) => {
const chunks = chunkArray(addresses, 100);
const results = [];
// Verwerk chunks in groepen van 'concurrency'
for (let i = 0; i < chunks.length; i += concurrency) {
const batch = chunks.slice(i, i + concurrency);
const batchResults = await Promise.all(
batch.map((chunk, index) =>
processBatch(chunk, i + index)
)
);
results.push(...batchResults.flat());
// Kleine pauze tussen parallelle groepen
await sleep(500);
}
return results;
};

Let op je rate limits

Parallelle verwerking kan snel je rate limit bereiken. Check je plan voor de maximale requests per seconde en pas de concurrency daarop aan.

Resultaten verwerken

Na batch geocoding moet je de resultaten analyseren en eventuele fouten afhandelen:

result-handler.js
const analyzeResults = (results) => {
const stats = {
total: results.length,
found: 0,
notFound: 0,
errors: 0,
lowConfidence: 0
};
const successful = [];
const failed = [];
const needsReview = [];
for (const result of results) {
if (result.status === 'found') {
stats.found++;
if (result.confidence < 0.7) {
stats.lowConfidence++;
needsReview.push(result);
} else {
successful.push(result);
}
} else if (result.status === 'not_found') {
stats.notFound++;
failed.push(result);
} else {
stats.errors++;
failed.push(result);
}
}
return {
stats,
successful,
failed,
needsReview,
successRate: ((stats.found / stats.total) * 100).toFixed(1) + '%'
};
};
// Gebruik
const analysis = analyzeResults(results);
console.log(`Success rate: ${analysis.successRate}`);
console.log(`Needs review: ${analysis.needsReview.length} adressen`);

Best practices voor batch geocoding

  1. Valideer input vooraf - Filter ongeldige adressen vóór verzending
  2. Gebruik eigen IDs - Koppel resultaten terug aan je brondata
  3. Implementeer retry logic - Netwerk kan falen, rate limits kunnen optreden
  4. Log voortgang - Bij grote datasets wil je weten waar je bent
  5. Bewaar failed records - Voor handmatige verwerking achteraf
  6. Batch async wanneer mogelijk - Gebruik workers of queue systems

Samenvatting

Efficiënte batch geocoding combineert de juiste batch sizes, rate limiting, error handling en parallellisatie. Met de patronen in dit artikel kun je datasets van elke grootte verwerken terwijl je binnen je API limits blijft en robuust omgaat met fouten.

batchperformancebulkasync
Delen:

Gerelateerde artikelen

Klaar om te beginnen met GeoRex?

Probeer onze geocoding API gratis en ontdek hoe eenvoudig adresverwerking kan zijn.

Cookie-instellingen

Wij gebruiken optionele analytische cookies om onze website te verbeteren. Deze cookies worden alleen geplaatst met uw expliciete toestemming. Meer informatie