時系列データ - Qiita Advent Calendar 2025 - Qiita
データサイエンスというよりはデータ基盤や分析寄りの話ですが、いつか書いておきたいネタにちょうどよい時系列データというテーマのアドベントカレンダーがあったので書いていきます。
前置き
IoTデバイスから収集される時系列データは、通信環境の影響でデータの遅延が発生することがよくあります。本記事では、実際の車載IoTデバイスを例に、遅延を考慮したデータ基盤の設計と運用について解説します。
特に以下のような課題をお持ちの方に参考になる内容です
- IoTデバイスの通信断による欠損データの対応
- 遅延データを考慮したデータ基盤の設計
- 時系列データの品質管理と分析手法
IoTデバイスについて
当社のビジネスでは簡単に言うと車のエンジンの起動制御ができるIoTデバイスを用いて、自動車ローンの与信補強、盗難防止、アルコールインターロック(お酒を飲んだら車が動かない)を行っています。
書けそうな範囲で前提条件を列挙します
- IoTデバイスは車両に取り付け、サーバーと通信するために携帯通信網を用いる
- 場所によって圏外になることがある。その際はIoTデバイスにサーバー未送信のデータが蓄積される
- エンジンの起動制御のための通信も行われる
- 車両のエンジンのオンオフ状態に応じて、データ取得頻度が変わる
- IoTデバイスの電源は車のバッテリー状況に応じて供給を受けたり、デバイス側のバッテリーを充電したり、デバイス側のバッテリーで稼働したりする
- 長らく車に乗らないと、データ記録頻度が落ちる仕組み
- 記録するデータは
- データ作成のtimestamp
- エンジンon/off状態
- 位置情報
- 累積距離
- 速度
- などなど…
車が停車状態から走り出したときのデータ
※記録時間は説明の都合上連番で記載します。
| 記録時間 | エンジン | 速度 | 累積距離 | 位置情報lat,lon |
|---|---|---|---|---|
| 1 | オフ | 0 | 10 | xxx |
| 2 | オン | 0 | 10 | xxx |
| 3 | オン | 10 | 11 | xxx |
サーバーへの取り込み
IoTデバイスが記録したデータは携帯通信網を用いてサーバーに送信されます。
管理上、サーバー記録時間を付与します。
| 記録時間 | サーバー記録時間 | エンジン | 速度 | 累積距離 | 位置情報lat,lon |
|---|---|---|---|---|---|
| 1 | 1’ | オフ | 0 | 10 | xxx |
| 2 | 2’ | オン | 0 | 10 | xxx |
| 3 | 3’ | オン | 10 | 11 | xxx |
通信が良好であれば、1と1’の差はほぼなしですが、圏外等の場合は1と1’の差は大きくなります。
データ基盤での加工
さて上記のIoTデバイスのデータを使って以下のような分析を行いたいです。どうすればよいでしょうか?
- 1日の走行距離
- 1日の走行時間
.
.
.
.
.
シンキングタイム
.
.
.
.
便利なデータをデータ基盤で用意します
| 記録時間 | diff_ts | サーバー記録時間 | エンジン | 速度 | 累積距離 | diff_odom | 位置情報lat,lon |
|---|---|---|---|---|---|---|---|
| 1 | - | 1’ | オフ | 0 | 10 | 0 | xxx |
| 2 | 2-1 | 2’ | オン | 0 | 10 | 0 | xxx |
| 3 | 3-2 | 3’ | オン | 10 | 11 | 1 | xxx |
- diff_ts
- 前回の記録時間との差
- diff_odom
- 前回の累積距離との差
それぞれSQLのLAGを使用して算出します。そのためデータ基盤では1時間に1回作成処理を行います。
.
IoTデバイスが累積距離ではなく、直接diff_odomの値を計算して記録した場合はどうなるでしょうか?(次項で解説します)
.
2つのカラムをデータ基盤側で加工することで簡単に出せるようになります。
- 1日の走行距離
- 記録時間を1日単位にし、diff_odomを合計して算出
- 1日の走行時間
- 記録時間を1日単位にし、エンジンがオンの時のdiff_tsを合計して算出
データ処理フロー
このアーキテクチャにより、リアルタイムのデータ収集とバッチ処理を組み合わせて、安定した時系列データの分析基盤を構築しています。
遅延データの発生ケースと対応策
通信断の一般的なケース
IoTデバイスの仕様では、瞬間的な圏外を除いて「最新の記録時間」から随時記録したデータを送信します。
イメージ
| 記録時間 | diff_ts | サーバー記録時間 | エンジン | 速度 | 累積距離 | diff_odom | 位置情報lat,lon |
|---|---|---|---|---|---|---|---|
| 1 | - | 3’’’ | オフ | 0 | 10 | 0 | xxx |
| 2 | 2-1 | 3’’ | オン | 0 | 10 | 0 | xxx |
| 3 | 3-2 | 3’ | オン | 10 | 11 | 1 | xxx |
このようなデータはどれくらいの頻度や、期間で発生するでしょうか?
真っ先に思い浮かぶのは、長いトンネルに入ったときです。
| 記録時間 | diff_ts | サーバー記録時間 | エンジン | 速度 | 累積距離 | diff_odom | 位置情報lat,lon |
|---|---|---|---|---|---|---|---|
| 1 | - | 1’ | オフ | 0 | 10 | 0 | xxx |
| 2 | 2-1 | 2’ | オン | 0 | 10 | 0 | xxx |
| 3 | 3-2 | 3’ | オン | 10 | 11 | 1 | xxx |
| 4 | - | 未送信 | オン | 30 | 12 | トンネル | |
| 5 | - | 未送信 | オン | 30 | 13 | トンネル | |
| 6 | 6-3 | 6’ | オン | 30 | 14 | 3 | xxx |
サーバーから見ると4と5の時のデータが未送信の瞬間が存在します。
diffの作成はデータ基盤で1時間に1回行うため、運悪く未送信になるタイミングもありえます。
重要な設計決定
IoTデバイス側では記録時間や累積距離など「絶対的な値」を送信します。これにより、歯抜けのデータがあってもデータ基盤で算出する「相対的な値」の意味は変わりません。
相対値データのリスク
IoTデバイスが累積距離ではなく、直接diff_odomの値を計算して記録した場合、以下の問題が発生します
注意点
前回からのデータ記録からの距離を送っていると、累積距離を計算する際に歯抜けのデータが考慮されなくなってしまいます。
.
.
.
.
.
他の圏外ケースではどうでしょうか
.
.
.
.
.
多いパターンは、地下駐車場です。
普段使いの駐車場が地下などで圏外の場合は、圏外は頻繁に乗る頻度に応じて半日〜1日以上の期間で発生します。
そのためサーバー記録時間が1日以上遅れることも車の利用状態によっては頻繁に発生します。
2~101の場所が圏外で、102の時点でデータ送信できた直後はこのような状態になります。
| 記録時間 | diff_ts | サーバー記録時間 | エンジン | 速度 | 累積距離 | diff_odom | 位置情報lat,lon |
|---|---|---|---|---|---|---|---|
| 1 | - | 1’ | オン | 10 | 11 | 0 | xxx |
| 2 | - | 未送信 | オフ | 0 | 11 | - | 地下駐車場 |
| … | - | 未送信 | オフ | 0 | 11 | - | 地下駐車場 |
| 100 | - | 未送信 | オフ | 0 | 11 | - | 地下駐車場 |
| 101 | - | 未送信 | オン | 0 | 11 | - | 地下駐車場 |
| 102 | 102-2 | 102’ | オン | 10 | 12 | 1 | xxx |
先述の通り、IoTデバイスの仕様で「最新の記録時間」から随時記録したデータを送信します。
103と101のデータが近しい時間で送信されたり、記録したデータが多い場合は、圏外復旧から全データを送信するまでそこそこ時間がかかるケースもあります。
今回の極端な例の場合、運悪くこのタイミングでデータ基盤の毎時の処理に重なると「運転時間」は誤った時間になってしまいます。
次項では圏外による遅延を考慮したデータ基盤の処理を紹介します。
データ基盤側の細かい処理
データ基盤では遅延するデータを考慮して、毎時の処理で7日分のデータを作り直します。
日数が経つに連れ遅延したデータが送信される割合が高くなります。
なお7日分を超えたデータは切り捨てます。
(以前元データと作成したdiffの差分を集計しましたが、切り捨てて良い程度の数でした)
アップデートではなくDelete & Insertを選ぶ理由
一般的にはUPDATE文を使うことも考えられますが、以下の理由でDelete & Insertを採用しています
- LAG関数の特性:差分データはLAG関数で算出しているため、部分的な更新では整合性が保てない
- データ依存関係:LAG関数の1件目はnullになるため、実際は8日分からdiffを算出して7日分を作り直している
運用上の教訓
このLAG関数の特性の考慮が漏れ、過去に中途半端なデータが作られてしまった経験があります。
後続の距離・時間集計も、若干変わるため更新します。
こちらはビジネス的に2日の遅延まで考慮し更新します。
※プラットフォームから出力する走行距離が7日間微量に変動しないほうがいいとカスタマーと調整が入りました。
時系列データ分析での実践的アプローチ
データ品質管理の考え方
IoTデバイスの異常調査や品質管理を行う際は、記録時間と送信時間の両方を考慮した分析が不可欠です。
通信品質の指標と監視
システムの品質管理では「通信率」を主要指標としており、以下の基準で通信状態を判定しています:
- 通信断判定:2日間連続で通信が確認できない状態
- 原因分析:圏外、車両バッテリー、デバイス故障などの区別
異常検知時の分析では、遅延データが後日届く可能性を考慮しつつ、過去のデータパターンを組み合わせた総合的な判断を行っています。
現在のデータ基盤では、これらの原因をSQLのクエリベースで機械的に判断し、原因を分類しています。
ざっくり書くと
- 記録時間が2日空いている かつ 車のバッテリー電圧が低い
- IoTデバイスのバッテリー状態が良い →車両バッテリー起因
- IoTデバイスのバッテリー状態が悪い →IoTデバイスのバッテリー起因
- サーバー送信時間が2日空いている →圏外起因
技術進化の影響
IoTデバイスも世代が上がる毎により省電力でバッテリー容量も向上しており、車両バッテリーが低下しても細く長く通信できるケースが増えています。
弊社はIoTデバイスの製造やファームウェアの開発も社内で行っているため、そこら辺の連携も強いです。
以前にはこういった会話の中で動作モードを記録データに付与しようとなり、ファームウェアがアップデートされ分析がかなり行いやすくなりました。
(今視点で見ると無いと分析が大変くらいの項目です)
更に分析の観点で載せて欲しい機能何かある?と聞かれ強いて言うなら…と
IoTデバイスがデータを記録する時点で未送信のデータが何件あるかも記録できると深い調査がしやすいと回答しました。
ファームウェア変更の負担が大きいかつ、最近は前述の通りバッテリー持ちが良くなり通信率も良い状態のため見送りとなりました。
そんな感じで実装負荷、あると便利な度合いでファームウェアの仕様でディスカッションできるのは、IoTデバイスがある企業ならではかと思います。
まとめ
本記事では、IoT環境で発生しやすい通信遅延を考慮した時系列データ基盤の設計と運用について、実際の事例を用いて解説しました。
主要なポイント
- データ設計:絶対値でのデータ送信で欠損耐性を確保
- バッチ処理:過去7日分の再処理で遅延データに対応
- 品質管理:記録時間と送信時間を区別した異常検知
- チーム連携:ファームウェアチームとの協力で分析品質を向上
他領域との違い
一方で、同じ車でもタクシー配車や動体管理など、リアルタイム性が重要な領域では本記事のアプローチをそのまま適用するのは難しいと思われます。
これらの領域では遅延耐性よりもリアルタイム性を重視したアーキテクチャが求められるため、より高度な応用や別のアプローチが必要になるでしょう。
弊社のビジネスはリアルタイム性が必要な部分が少ないため負担が少なく、システム側からすると助かりますし、うまい仕組みにしたなと感じます。
本記事が何かしらの参考になれば幸いです。