Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

PDFインポートの安定性を追求!ハッシュ化アルゴリズム刷新の舞台裏

私は技術本部 Contract One Engineering UnitでContract Oneの開発をしている松永俊と申します。

今回は、Contract OneのPDFインポート機能の安定性向上についてご紹介します。

    • -

1. PDFインポートにおける「稀な」エラーとの闘い

Contract Oneでは、契約書データをPDFインポートで作成する機能を主要な導線として提供しています。このPDFインポート機能には重複チェック機能があり、好評を得ています。Contract Oneの契約書の5割はこの機能により作成されています。

しかし、これまでごく稀に、PDFファイルのインポート時にエラーが発生し、「PDFファイルの容量を下げてから再度お試しください。」という表示がされていました。「70MBまでインポート可能」と記載しているにも関わらずそれ以下のファイルでエラーが発生し、圧縮を促すという矛盾があったのです。

ごく稀なエラーではあるものの、お客様の増加に伴い、発生件数が増えはじめていました。直接のお問い合わせは少なかったものの、多くのお客様がこのエラーに遭遇し、不便を感じたことを私は重く受け止め、この課題を解消してお客様の体験価値を向上するためこの問題の根本解決に乗り出しました。

    • -

2. なぜエラーが発生していたのか?:既存ライブラリの限界

PDFファイルの重複チェックでは、ファイルのMD5ハッシュ値の一致を確認します。
Contract OneにはPDFファイルのMD5ハッシュ化を行うJavaScriptライブラリがありますが、これには一定容量(約40MB)を超えるPDFファイルに対してMD5ハッシュ値の計算に失敗するという致命的な欠陥がありました。
問題の原因は、PDFページをデータストリームに変換する際RangeError: invalid array length - JavaScript | MDNエラーが発生するバグです。

    • -

3. 新しいアルゴリズムへの移行と大規模データへの挑戦

私たちはこの問題解決のため、より堅牢で信頼性の高いcryptoJS.MD5という別のMD5ハッシュ計算ライブラリの採用を決定しました。しかし、ここで新たな課題が浮上しました。

新しいライブラリでハッシュ値を計算したところ、既存のPDFファイルに計算されているハッシュ値が、新しいライブラリのアルゴリズムで計算した値と一致しない

既存ライブラリを調査した結果、ライブラリの内部でUnit8Arrayをサポートしていないことが分かりました。ArrayBufferを使った時と異なるアルゴリズムロジックになり、正しいMD5のハッシュ値の計算ができませんでした。ゆえに、正しいMD5を振り直す課題が浮上しました。

    • -

4. 効率的なデータ移行:コルーチンとGCSの活用

「今までアップロードされたPDFファイルに対して、どうやって正しいハッシュ値を再計算し、システムに反映するか?」

これが、私に残された最も大きな課題でした。私は複数のアプローチを検討しました。

案1. 全ファイルダウンロード方式

すべてのPDFファイルをローカルにダウンロードして再計算する方法です。これは膨大なネットワーク・コンピューティング費用が発生しますし、処理時間は検証結果9日の見込みでした。

案2. シーケンシャル処理方式

専用のバッチ処理ジョブをCloud run jobsに実装する方法です。
ローカルにダウンロードする必要はありませんし、同じネットワーク地域なので費用も掛からないですが、こちらも処理時間が現実的ではありませんでした。

案3. gsutilとコルーチン

専用のバッチ処理ジョブを開発することは案2と等しいですが、採用した案3には2つの大きな特徴があります。

GCS活用によるダウンロード不要化
gsutil hash コマンドでファイルをダウンロードすることなく、高速にファイルのMD5ハッシュ値を取得できます。これにより、ネットワークコストと処理時間を大幅に削減しました。

Kotlinコルーチンによる並行処理
過去にアップロードされた約80万件のPDFファイルに対し、正しいハッシュ値を効率的に再計算・移行するため、全データを1000件ずつのチャンクに分割し、各チャンクを独立したasyncコルーチンで並列処理します。並列度は2〜 10 の間で最適解を実験的に見つけ、synchronizedブロックで処理結果(成功とエラー)を集計しました。

新しいアルゴリズムへの移行は、サービス停止を伴わない形で実現しました。既存データはバッチ処理で順次更新をしながら、これからアップロードされるPDFは正しくハッシュ計算するようにしました。


5. まとめと今後の展望

これにより、Contract OneのPDFインポート機能が安定した状態でご利用できるようになりました。

今回はPDFインポート機能におけるハッシュ化アルゴリズムの刷新という裏側の改善についてご紹介しました。
既存ライブラリの課題特定からGCSの特性とKotlinコルーチンによる並行処理を活用した大規模データ移行まで、技術的なチャレンジを乗り越え、膨大な既存データに対するハッシュ値の更新を成功させることができました。

開発というものは常に発生する課題との戦いですね。一つひとつの課題を技術と工夫で解決しながら、さらなる成長を続けてまいります。Contract Oneは若手もベテランも垣根なくチャレンジし続ける組織であります。もし私たちと一緒に働くことに興味を持っていただけたら下記をご確認ください。ありがとうございました。

    • -

カジュアル面談を実施しています。

カジュアル面談を実施しています

Sansan技術本部では中途・新卒採用向けにカジュアル面談を実施しています。Sansan技術本部での働き方、仕事の魅力について、現役エンジニアの視点からお話しします。「実際に働く人の話を直接聞きたい」「どんな人が働いているのかを事前に知っておきたい」とお考えの方は、ぜひエントリーをご検討ください。

© Sansan, Inc.