追跡データを活用した配送分析ダッシュボードの構築
生の追跡イベントは、正しく分析すれば配送インテリジェンスの宝庫です。追跡データの上に分析ダッシュボードを構築することで、パフォーマンスの低い配送業者を特定し、配送ルートを最適化し、配達時間を短縮することができます。このチュートリアルでは、実用的な配送分析システムの構築方法を解説します。
何を測定するか
コードを書く前に、重要な指標を定義しましょう。
基本的な配達指標
| 指標 | 計算式 | 重要な理由 |
|---|---|---|
| 平均輸送日数 | 輸送日数の合計 / 総配送数 | 配達速度のベースライン |
| 定時配達率 | 定時配達数 / 総配達数 x 100 | 配送業者の信頼性指標 |
| 例外発生率 | 例外が発生した配送数 / 総配送数 x 100 | 配送体験の品質 |
| 初回配達成功率 | 初回で配達成功した数 / 総配達数 x 100 | ラストマイルの効率性 |
ビジネス指標
| 指標 | 計算式 | 重要な理由 |
|---|---|---|
| WISMO率 | 追跡に関する問い合わせ数 / 総配送数 x 100 | 顧客体験の品質 |
| 配達1件あたりのコスト | 配送業者の総コスト / 配達成功数 | コスト効率 |
| 返品配送率 | 返品配送数 / 総配送数 x 100 | 商品またはフルフィルメントの問題 |
追跡データの収集
WhereParcelのWebhookを使用して、追跡イベントを分析用データベースにストリーミングします。
// Webhook receiver - store events for analytics
app.post('/webhooks/tracking', async (req, res) => {
const event = req.body;
// Store raw event for detailed analysis
await db.trackingEvents.insert({
trackingNumber: event.data.trackingNumber,
carrier: event.data.carrier,
status: event.data.latestEvent.status,
location: event.data.latestEvent.location,
timestamp: event.data.latestEvent.timestamp,
receivedAt: new Date(),
});
// Update shipment summary record
await updateShipmentSummary(event.data);
res.status(200).json({ received: true });
});
async function updateShipmentSummary(data) {
const summary = await db.shipmentSummaries.findOne({
trackingNumber: data.trackingNumber,
});
const updates = {
currentStatus: data.latestEvent.status,
lastUpdated: new Date(),
eventCount: (summary?.eventCount || 0) + 1,
};
// Record milestone timestamps
if (data.latestEvent.status === 'picked_up' && !summary?.pickedUpAt) {
updates.pickedUpAt = data.latestEvent.timestamp;
}
if (data.latestEvent.status === 'delivered') {
updates.deliveredAt = data.latestEvent.timestamp;
updates.transitDays = daysBetween(summary?.pickedUpAt, data.latestEvent.timestamp);
}
await db.shipmentSummaries.upsert(
{ trackingNumber: data.trackingNumber },
{ $set: updates }
);
}
分析クエリの構築
配送業者パフォーマンスの比較
async function getCarrierPerformance(dateRange) {
const results = await db.shipmentSummaries.aggregate([
{
$match: {
deliveredAt: { $gte: dateRange.start, $lte: dateRange.end },
},
},
{
$group: {
_id: '$carrier',
totalShipments: { $sum: 1 },
avgTransitDays: { $avg: '$transitDays' },
onTimeCount: {
$sum: { $cond: [{ $lte: ['$transitDays', '$estimatedDays'] }, 1, 0] },
},
exceptionCount: {
$sum: { $cond: ['$hasException', 1, 0] },
},
},
},
{
$project: {
carrier: '$_id',
totalShipments: 1,
avgTransitDays: { $round: ['$avgTransitDays', 1] },
onTimeRate: {
$round: [{ $multiply: [{ $divide: ['$onTimeCount', '$totalShipments'] }, 100] }, 1],
},
exceptionRate: {
$round: [{ $multiply: [{ $divide: ['$exceptionCount', '$totalShipments'] }, 100] }, 1],
},
},
},
{ $sort: { onTimeRate: -1 } },
]);
return results;
}
ルート別の輸送時間
async function getTransitTimeByRoute(carrier, dateRange) {
return db.shipmentSummaries.aggregate([
{
$match: {
carrier,
deliveredAt: { $gte: dateRange.start, $lte: dateRange.end },
},
},
{
$group: {
_id: {
origin: '$originCountry',
destination: '$destinationCountry',
},
avgDays: { $avg: '$transitDays' },
minDays: { $min: '$transitDays' },
maxDays: { $max: '$transitDays' },
p90Days: { $percentile: { input: '$transitDays', p: [0.9], method: 'approximate' } },
count: { $sum: 1 },
},
},
{ $match: { count: { $gte: 10 } } }, // Only statistically significant routes
{ $sort: { avgDays: 1 } },
]);
}
日別配達トレンド
async function getDailyDeliveryTrends(dateRange) {
return db.shipmentSummaries.aggregate([
{
$match: {
deliveredAt: { $gte: dateRange.start, $lte: dateRange.end },
},
},
{
$group: {
_id: { $dateToString: { format: '%Y-%m-%d', date: '$deliveredAt' } },
delivered: { $sum: 1 },
avgTransitDays: { $avg: '$transitDays' },
exceptions: { $sum: { $cond: ['$hasException', 1, 0] } },
},
},
{ $sort: { _id: 1 } },
]);
}
ダッシュボードのレイアウト
ダッシュボードを論理的なセクションに整理しましょう。
概要セクション
- 総配送数(当期 vs 前期)
- 平均輸送時間のトレンド
- 全体の定時配達率
- アクティブな例外の件数
配送業者パフォーマンスセクション
- 配送業者の横並び比較テーブル
- 配送業者ごとの輸送時間分布チャート
- 配送業者別の例外率の推移
ルート分析セクション
- 出発地/到着地別の輸送時間ヒートマップ
- 最速・最遅ルートのトップ10
- ルートレベルの例外パターン
例外モニタリングセクション
- 種類・重要度別のアクティブな例外
- 例外解決時間のトレンド
- 配送業者固有の例外パターン
分析から得られる実践的なインサイト
以下は、発見される可能性のある実際のパターンの例です。
1. 配送業者選択の最適化
Carrier A: Avg 3.2 days, 94% on-time, $8.50/shipment
Carrier B: Avg 2.8 days, 91% on-time, $12.00/shipment
Carrier C: Avg 4.1 days, 97% on-time, $6.00/shipment
時間に敏感な配送には、Carrier Bが最速です。信頼性を伴うコスト最適化には、Carrier Cが最良の選択肢です。これらの判断が、仮定ベースではなくデータドリブンになります。
2. ルート別の配送業者パフォーマンス
ある配送業者が国内では優秀でも、国際配送では低い成績を示す場合があります。ルートレベルの分析でこれが明らかになります。
Carrier A: US → US: 2.1 days avg (excellent)
Carrier A: US → KR: 8.5 days avg (poor — competitors average 5.2 days)
3. 季節的なパターン
繁忙期、梅雨の時期、大規模セールイベントはすべて輸送時間に影響します。過去の分析データは以下の計画に役立ちます。
- 繁忙期の配送業者キャパシティの確保
- 遅延時のお客様へのコミュニケーション
- 輸送距離を短縮するための在庫配置
始め方
- Webhookの収集を設定する — 今日から追跡イベントのキャプチャを始めましょう
- 指標を定義する — まず追跡すべき3〜5個の主要指標を選びましょう
- 基本的なクエリを構築する — 配送業者の比較と日別トレンドが最も価値が高い分析です
- 反復する — 追跡すべきパターンが見つかるにつれて、分析の軸を追加していきましょう
必要なデータはすでに追跡連携を通じて流れています。それを分析に変換することが、配送をコストセンターから競争優位性へと変革するステップです。
Webhookを使ったデータ収集の設定について詳しくは、Webhook ベストプラクティスガイドをご覧ください。