医療AIスタートアップの一人目エンジニア始めました
こんにちは、株式会社メディキュー で CTO をしている大坪です。CTO といいつつ立ち上がったばかりのスタートアップでフルタイムのエンジニアは自分だけなので、一人目エンジニアと名乗るほうが適切かもしれません。この記事では「今年の最も大きなチャレンジ」として、スタートアップの基盤をゼロから作る過程で直面した「Webサービス開発の当たり前をデータウェアハウス開発で実現するために考えたこと」をまとめます。これから医療領域に足を踏み入れる人、スタートアップを始める人、データ領域に足を踏み入れていく人の参考になればと思います。
メディキューは医療データサイエンスの会社
メディキューは下記のポストをしている木下が創業した「データの力で医療の価値を最大化する」をミッションに、医療AIの開発と実装を行うスタートアップです。
フルタイムエンジニアが自分だけという事実からわかる通りまだ非常に小さい会社ですが、医師、薬剤師、看護師などの医療従事者やビジネスサイドの業務委託、インターン等様々な関わり方のメンバーがいて全員集めると20人を超えてくるくらいになりました。
届ける価値 - 高頻度高品質のデータクリーニング
メディキューが生み出す価値の源泉はデータ解析能力、AI開発能力等様々なものがあります。しかしながらまだ準備中のことが多いため、ここでは会社としての WHY や WHAT としてのミッション/ビジョン/作りたいものなどには触れず、HOW としてのエンジニアリングの役割に絞って記述します。
多施設医療データを高い頻度で高い質にクリーニングし続ける
メディキューのエンジニアリングで生み出す価値の源泉は多施設の電子カルテ[1]のクリーニング能力です。複数の病院から匿名加工された電子カルテデータを受け取り、それを研究やAI開発に利用しやすい状態に変換する技術です。どんな病院のどんな電子カルテでも統一されたメディキューの形式に正規化します。これによりこれまで難しかったスケールでの研究やAI開発ができるようになります。
クリーニングは大変
これを実現するために電子カルテデータを BigQuery にロードして dbt の SQL model で多段レイヤーで徐々に正規化していくデータウェアハウスを構築しています。これだけ書くといい感じの SQL を書くだけに見えますが、下のような課題が沢山あるのでなかなか大変です。
テーブル数が多い
メディキューが現在注力している領域は救急集中治療領域です。集中治療室で治療する症例は当然重症度が高く、単位時間あたりに記録される情報は多くなります。
分時のバイタル測定、頻回な血液検査、多数の薬剤の流量変更などが高い密度で記録されていきます。さらには人工呼吸器、透析などのデバイスを使った治療、さらには ECMO / IABP などおそらく多くの人が知る機会の少ない機器を用いた治療なども設定値を細かに記録されます。こういった生体情報 / 検査情報 / 介入情報をすべて記録していると多岐に渡るテーブルを扱うことになります。
テーブル形式が病院によって違う
電子カルテシステムごとにそもそも出力スキーマが異なります。さらに病院ごとにどこのテーブルに何が入っているかも異なります。そもそも導入時に様々なカスタマイズが入っていることが多く、その運用も異なります。
その結果下のようなことがよくあります。
- 注射と輸液[2]が同じテーブルに入っていたり別だったり
- 透析と人工呼吸器の同じテーブルだったり別だったり
- 薬剤が mL で記録されたり有効成分量で記録されたり
そもそも様々なカスタイマイズ要望に対応できるよう、あえて制約の少ないデータ管理方法を選ぶという電子カルテ開発者の工夫も感じ取れるのでこれを統一した形式するのはなかなか大変です。
入力形式が病院によって違う
仮にスキーマを頑張って揃えられたとしてもその中に入力されているデータの規約が異なります。
- 同一薬剤でも病院によって名称が異なる
- 簡単なものでも
生食
,生理食塩液
,<メーカー名>生食
など - 当然全角半角違いとかもある
- 簡単なものでも
- 人工呼吸器設定の名称違い
- フリーテキストの正規化
- フリーテキストで入力された病名一覧を構造化された病名一覧に変換
特にフリーテキストの正規化は最近特許出願した重要な技術です。ざっくりイメージしてもらうと「CSV か TSV か JSON かすらわからないし何なら混ざっていることもあるデータのパース」みたいな大変さがあります。
高頻度改善で精度を徐々に高める
上記のような問題は個別にマンパワーで対応付けていけばクリーニングは完了しますが全くスケールしません。この対応をエンジニアリングで解決していく事が必要です。この部分の工夫については技術的優位性にしたい部分なのですべての開示はできませんができる範囲で共有していけたらと考えています。今回は概要のみ解説します。
ドメインを深めてベースラインを確保
エンジニアは医学を学び、医師がエンジニアリングを学ぶことで社内で臨床現場の意思決定を最も正しく表現できるデータはどのようなものかを常に議論しています。これによって決めた厳しい制約が課されたスキーマにデータを落とし込むことでベースラインの品質を維持しています。
これを行うにはエンジニアが医療現場のことを細かに理解することが重要なので、定期的に病院を見学させてもらい、1行のレコードと1つの臨床現場の介入を基本的にすべて観察しています。逆に社内の医師にはリレーショナルデータベースの正規化の理論や、ドメインモデリングを学んでもらいました。
その技能交換の様子は下のポストでイメージできるかなと思います。(私のことが褒められていますが、木下をはじめとする社内の医療関係者のエンジニアリング知識吸収速度もなかなかすごいものがあります)
品質の単調増加
データベーススキーマによってベースラインの品質が確保できたところでそれを高めていくアクションが必要になります。この品質の確認は自動化とドメインエキスパートによる目視の2つを使い分けています。ドメインエキスパートとして医療従事者がデータの不整合を探し、発見できた場合はこれを二度と起こさないように自動化された dbt の data_test や constraint に書き起こします。現在2000件程度の品質チェック項目が存在しています。データ量とチェック項目数の両方に対して線形にテスト費用がかかっていくためこのコストを抑えるエンジニアリングも同時に行っていく必要があります。
高頻度な改善
メディキューではデプロイ頻度につながるケイパビリティの獲得を試みています。高頻度なデプロイは最終的に組織パフォーマンスにつながる指標の一つです[3]。具体的には1日10回程度の Pull Request の merge と自動デプロイでデータウェアハウスの更新をしています。これもテストと同様にコストにダイレクトに効いてくるので下げる戦略が必要になります。また、リードタイムも短く保っています。一度外部の方にデモしているときに発見したデータ不整合をそのデモの最中に直し切るくらいの速度が出せています。これもコストがかなり掛かるので工夫が必要です。
この高頻度かつ短時間のデータ更新のできる基盤、そして一度発見した問題は自動で検知できるようにするプラクティスによって「とにかく今よりも少しでも品質の良い状態にする」というインクリメンタルの品質向上が日々進めることができています。まだ荒いところはたくさんありますが、自社研究を進められるところまで積み上げきることができました。
Web と DWHの共通部分抽出
テストをしっかり書いてデプロイ頻度を高める、というプラクティスはWebサービス開発では当たり前に受け入れられていると思います。しかしながらWeb サービス開発の経験を持ってデータウェアハウスの開発を始めるといくつか既存のメンタルモデルを変えないといけない点があります。
ここからは Webサービスを Web、メイディキューで構築するデータ基盤を DWHと記載してそれぞれの処理の捉え方を説明します。DWHとしてはデータの正しさを重視するので、Web 対応はバックエンド[4]部分との対応を考えます。
まずは Web と DWH で同じ考えが使える場所とそうでない場所の整理がほしいので、同じだと感じることのできる抽象レベルを探します。その結果 input / process / output / state / cache の5つの要素では同一視できるという結論に至りました。
input は追加の生データ
Web においてこれがリクエストになることはおそらく簡単に同意できるでしょう。一方DWHでは追加される新しい生データが input です。調査クエリ、レポート作成クエリ、データ切り出しクエリなどが input ではないか?と思う人もいるかもしれませんがそれは output を考えることでそうではないことが理解できます。
output は transform 後テーブル
Web においてはレスポンスですがDWHにおいては出力されるテーブルです。transform を経て出力されるテーブルがある時、そのテーブルに対するクエリに対して DWH の管理者ができる介入はありません。select *
で全体をダウンロードして手元の PC で処理する、という方針を利用者が取ったとしても問題のないテーブルにする必要があります。システムとして自分たちが管理できる一番利用者に近いエッジの部分を output だと考えると、これはクエリ結果ではなくあくまでテーブルになります。
そこで、BigQuery という非常に強力なクライアントサイド処理実行基盤があるという整理をしています。Web においてもブラウザという強力なクライアントサイド処理実行基盤があるのと同様です。クエリやクエリ結果はシステムに対する input / output ではなく、Web で言うところのブラウザに対する入力、ブラウザから出力に対応します。
process は transform
process は input から output を計算する処理です[5]。したがって input と output の定義から自動的に決まります。Web においてはリクエストを受けてレスポンスを返すまでのバックエンドの処理が相当し DWH では transform が相当します。
state は生データ全部
state をざっくり「input 以外に output に影響を与えるデータ」と捉えます。このように考えた場合、Web においては state は基本的には DB の状態です。クッキーなども入れてもいいかもしれません。対して DWH では「生データ全部」になります。transform 後のテーブルは state ではないのか?という疑問は次の cache で答えます。
cache はテーブル
cache は「process の時間と計算資源を節約するためのデータ」と定義します。state ではないので、cache は失っても process の結果に影響を与えないはずです[6]。DWHでは cache がまさにテーブルです。技術的制約がなければすべてを view で管理してしまうのが複雑性がなく最も簡単です。ただしそうすると計算資源が足りなくなるからテーブルとして計算結果を保存していくということになります。仮にどんな計算も一瞬で終わらせる魔法のコンピュータがあればテーブルとしてデータを保管する必要はありません。
Web と DWH の相違点
以上 input / output / process / cache / state を定義したところで Web と DWH で考え方が異なる部分を整理していきます。
state 管理 vs cache 管理
サービス内容によっても変わってくる[7]のであくまで傾向の話ですが、基本的に Web では state 管理のほうが cache 管理より難しいでしょう。データの持ち方を一度間違えると将来的なサービスのあり方を狭めてしまう可能性があるため考えることが膨大です。
一方DWHでは逆です。先の state の定義を考えると、DWH の state はただ生データをためていればそれで完了です。むしろ生データに改変を加えないという制約が遡って分析し直せるなどメリットをもたらします。逆に DWH では生データから派生されて作られる任意のデータとしての cache 管理が非常に困難になります。cache の更新はダイレクトにコンピューティング費用に効いてくるのでどうしても一定の妥協をせざるを得ません。また性質によっては数分間から数時間のコンピューティングを行わなないと更新がうまくできないこともあります。
これまで state 管理に使ってきたエンジニアリングリソースを cache 管理にシフトさせる必要があります。BigQuery では materialized view を使うとこの管理を一部 Google Cloud に任せることができますが、現時点では nest できないなどの問題があるためまだ自分たちで管理する必要性が残っていると思います。
一括 input vs 逐次 input
バッチシステム vs オンラインシステムという言い方でもいいかもしれません。Web では過去の input の retry は不可能です。Web においては process は一瞬の操作であり、output を返しきったあとにはその process にどんな致命的なミスがあろうとやり直しはできません。逆に完全に同一のリクエストが来ても前回と全く同じレスポンスを返す必要はありません。このような意味で Web においては input は逐次的だと言えます。今この瞬間に来たリクエストにさえ対応できればいい代わりに、常に正しいレスポンスを返し続ける必要があります。
一方 DWH では retry が可能です。(もちろん頻発したくはないですが)ある transform クエリにバグがあった場合、それを直せば過去に受け取った全 input を一括して retry してすべての output を計算し直せます。この結果「過去に受け取った全 input に対してprocess結果が正しくなるか」という Web だと非常に困難な検証もできます[8]。
deploy がコスト vs deploy は実質無料
deploy は process 部分のプログラムを差し替える操作だと言えます。Web においては実質無料の操作として受け入れられていると思います。一方で DWH では一括して全ての input と全て output の対応が process によって対応できていることを期待するので、全ての cache 再計算が必要になります。これはデータ量に比例して deploy コストが上がっていくことを意味しています。当然これではコスト的にスケールが難しくなるので「一定以上古いデータの cache は更新しない」といった「一定以上の影響がある cache だけをうまく選択的に再計算するルール」が必要になります。Web では簡単に実現できる実質無料な deploy を DWH で実現するにはそのルールがうまく満たされる設計が必要になります。
テストが難しい vs テストが簡単
DWHの開発においては基本的にローカルでユニットテストが実行できません。Web 開発においてはアプリケーションもデータベースも本番と同じものを簡単に手元に用意できますが、BigQuery をオフラインで実現することは容易ではありません。エミュレーターは存在しますが確信を得るには実際にクラウド上で動かすしかないという判断をしました。
クラウド上で動かすと逆にテストのサイズを実データと同じところまで簡単にスケールさせるられるというメリットもあります。「クエリを変えたが、前後で全 input に対する output が一切変わらなかったのでこのリファクタリングにデグレはない」という非常に強い主張をすることができます。ただしこの部分もコストにダイレクトにきいてしまいます。また、メリットと表現しましたが、実は半分マストなところもあります。リファクタリングが過去の input に対する output にも影響を与えるため大掛かりなことをすると全データテストがすぐに欲しくなってしまうからです。したがって、うまく考えないとデータ量に対してテストコストが上がる、という事態になってしまいます。
今後の技術戦略
以上をまとめると、Web と DWH では基本的な部分でできることの違いはあるものの DWH で根本的に難しくなるのはコスト問題に収束すると考えています。
というのもざっくりクラウドインフラコストを考えてみると最も支配的な項は下のようになります。
Web開発運用コスト ~ input量
DWH開発運用コスト ~ state量 * テスト回数/deploy * deploy頻度 * cache更新量
自分の整理を正当化するために少し恣意的な式になってはいますが、いちばん大事なこととして Web ではテスト頻度とdeploy頻度がコストに直結しないのに対して DWH ではこの2つがコストに強く効いてきます。この部分を抑えるエンジニアリングができないとテストとデプロイを高頻度にすることは難しいですが、逆にこの部分を抑えられたら Webの開発体験をそのまま持ち込むことができるはずです。
Web と同じ考えをベースとして DWH の開発をしていくことに多少無理があるのではないかという不安は完全には消えていませんが、高頻度かつリードタイムの少ない deploy という web におけるマインドセットは実現可能だと考えています。したがって今後メディキューが今注目しているのは下の領域です。
- cache アーキテクチャ最適化による deploy コストの削減
- テストにおける実データ使用量と担保できる品質の分離
このあたりの課題はいくつか解けているものもありますしまだまだ未解決である部分もたくさんあります。今後この課題の解決状況をできる範囲でこの publication で共有していけたらと思います。
最後に
メディキューはまだ小さい会社ながら基盤投資をしっかり行っている会社です。もしかして話を聞いてみると面白いかも?と思った方はぜひ大坪のXなどにご連絡などいただけたらと思います。
-
現時点では正確には電子カルテではなく「集中治療室版電子カルテ」とも説明される重症部門システムと呼ばれるシステムに注力しています ↩︎
-
知らない人向けにすごくざっくり説明すると点滴みたいなもの ↩︎
-
ざっくり自分たちが管理する計算資源での処理と定義します。 ↩︎
-
実際には process の結果 state や cache が更新されることがありますが主たる目的としての output の出力であるとこの場では考えます。 ↩︎
-
実際には影響が出てしまうこともありますが、意図してそうした影響を出していることはないと思います。 ↩︎
-
特にコンテンツ配信系は cache を以下にうまく保つかが重要になるのでこの傾向からは例外的です。 ↩︎
-
これができるからついやってしまう、というところが DWH 管理コストが膨らんでいく要素という言い方もできます。DWH では process は絶対に一回しかやらない、retry できないという前提でやれば Web と同程度のコストに落ち着かせることができるはずです。 ↩︎
Discussion
はじめまして。
私は現在、機械工学を専攻している理系大学生です。
この記事を拝読し、最新の技術への挑戦や、課題解決へのアプローチに非常に感銘を受けました。
私は、現在大学での学びを活かしながら、現場で実際の技術開発に携わりたいと考えています。もし可能であれば、インターンシップとして貴社の活動に関わらせていただける機会があれば非常に嬉しく思います。
突然のご連絡となり恐縮ですが、一度お話しさせていただけると幸いです。
どうぞよろしくお願いいたします。