Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
BlockNoteとDuckDB-WASMでつくる、ブラウザ内データ分析環境の設計
Search
Ryotaro Tamura
April 01, 2026
Technology
150
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
BlockNoteとDuckDB-WASMでつくる、ブラウザ内データ分析環境の設計
さくらインターネット研究所 テックトーク2026春(
https://sakura-tokyo.connpass.com/event/383699/
) の発表で使用した資料です。
Ryotaro Tamura
April 01, 2026
More Decks by Ryotaro Tamura
See All by Ryotaro Tamura
Prometheus setup with long term storage
tokibi
7
6.1k
nanafshiを使って簡単に作るFUSEの動的ファイル
tokibi
0
620
monotips #3 - fzfる
tokibi
0
180
IAMロールはどこから来て、どこへ行くのか / Where do IAM rolls come from and where to go?
tokibi
2
2.7k
Other Decks in Technology
See All in Technology
spanner-autoscalerに学ぶ CRD設計パターン 〜自動化と緊急時対応を両立する Kubernetesコントローラーの作り方〜
tkuchiki
0
220
サーバーフルコンピューティング?AWS Lambda
iwatatomoya
0
110
Account Factory for Terraformによる 標準化されたアカウント発行の自動化
pensuke628
0
120
オブザーバビリティを高める AI エージェント体験を考える / Designing AI Agent Experiences That Enhance Observability
aoto
PRO
1
130
猫でもわかるKiro Web
kentapapa
1
160
20260929_AmazonGuardDutyの検出通知メールにAWS DevOpsAgentの調査結果を追加する
yhana
1
400
HolmesGPTで始めるSREエージェント入門!プラットフォームの障害調査はAIにお任せ 〜
leveragestech
PRO
0
120
ビジネスを止めない技術的負債の返済のための戦略とその手法 - 技術的負債と向き合う / Complexity and Simplicity
soudai
PRO
2
320
なぜAI任せのゲームは面白くならないのか?
hirohasuyoutube
0
370
AI 時代の Azure エンジニアリング ~ 私たちは何を磨き、何を任せるのか ~
chack411
1
250
Meet AgentCore Identity Consent Portal
hironobuiga
2
140
10年欲しかった音楽管理アプリを、AIと一緒に作りはじめた
judau
1
200
Featured
See All Featured
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
380
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
440
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
3k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
68
58k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
250
Prompt Engineering for Job Search
mfonobong
0
470
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Context Engineering - Making Every Token Count
addyosmani
9
1.2k
Odyssey Design
rkendrick25
PRO
2
850
Test your architecture with Archunit
thirion
2
2.4k
Code Reviewing Like a Champion
maltzj
528
40k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
3
3.8k
Transcript
BlockNote と DuckDB-WASM でつくる、 ブラウザ内データ分析環境の設計 さくらインターネット研究所 田村 龍太郎 (X: @_tokibi)
目次 1. 背景と目指す体験 2. 中核モデル 3. 設計・実装 4. まとめ
1. 背景と目指す体験
1. 背景と目指す体験 背景 実験の記録に伴う様々な工程が複数のファイル・ツールに散逸しがち 分析: Excel, SQL, Python(Pandas, Polars), …
可視化: Excel, Python(Matplotlib, Seaborn), BI ツール, Origin, … 記録・共有: Word, PowerPoint, Notion, Markdown, … eureco が目指す体験 1 つのエディタ内でデータ分析の一連の工程が完結する データ読み込み → 集計・加工 → 表・グラフで確認 → 考察を記述 分析の結果だけでなく、工程がドキュメントに残る
2. 中核モデル
2. 中核モデル ブロックエディタ(BlockNote) を記録と分析の共通インターフェースとして利用 分析・可視化用のカスタムブロックを追加 ブロック間の依存関係をドキュメント構造内に定義 分析用ブロックはブラウザ上で動作する DuckDB-WASM に同期 データの前処理や集計などの分析処理をDuckDB
上で実行
2. カスタムブロック: データソース データテーブルブロック 手書きで分析に使用するテーブルデータを作成 CSV ブロック CSV ファイルのアップロード /
外部URL を参照
2. カスタムブロック: 分析・可視化 集計ブロック データソースを参照して、フィルタ・計算・グループ 集計などの分析パイプラインを構築 チャートブロック ドキュメント上の分析用ブロックの列を参照してチ ャートを描画
3. 設計・実装
3. 設計上の考慮事項 1. UI(BlockNote) と DuckDB-WASM の状態同期 BlockNote ドキュメントの状態変化をDuckDB にどう反映するか
DuckDB 上の状態変化をリアクティブにUI に反映させるには 2. 分析工程をドキュメントにどう記録するか
3-1. 状態同期
3-1. 全体構成の概観 基本ルール Read とWrite の経路を分ける ブロックとカタログの1:1 対応を保つ Editor TableStore
DuckDB-WASM BlockNote 同期⽤コンポーネント Catalog Snapshot snapshot.[contentHash] snapshot.[contentHash] snapshot.[contentHash] catalog.[blockID] catalog.[blockID] catalog.[blockID] データテーブル CSV 集計 チャート カタログ管理 カタログ管理 テーブル/ ビュー作成 EventHub Write: Read:
3-1. 状態同期: Editor → DuckDB BlockNote のイベントを起点に、DuckDB 上のテーブルやビューの状態を更新する同期用コンポーネントを実装 役割 BlockNote
のイベントを購読 (CSV アップロード、データテーブル編集、分析パイプライン変更など) ブロック種別に応じてテーブルデータ、ビュー用SQL に変換 TableStore を介してDuckDB に登録 Editor TableStore DuckDB-WASM BlockNote 同期⽤コンポーネント Catalog Snapshot snapshot.[contentHash] snapshot.[contentHash] catalog.[blockID] catalog.[blockID] データテーブル カタログ管理 カタログ管理 テーブル/ ビュー作成 Write: Read: 1. 操作 2. イベント購読 3. 変換 + 登録
3-1. 状態同期: DuckDB → Editor 自作のTableStore を中心に、DuckDB の状態をUI に反映する仕組みを構築 カタログ機能
ブロックID と、DuckDB 内のテーブル/ ビュー情報とのマッピングを管理するカタログ コンテンツハッシュを名前にしたスナップショットで実テーブルを保存 更新時は新スナップショット作成 → カタログの参照を切り替え ブロックからテーブル/ ビューへの安定参照に使用 イベントシステム カタログの更新時に各種イベントを発火 カタログ間の依存を見て、上流の変更で下流カタログの更新イベントも連鎖的に発火 最新のカタログ情報をUI コンポーネントに提供するためにReact フック内部で購読
3-1. 状態同期: DuckDB → Editor 各カスタムブロック(React コンポーネント) はブロックID に紐づくカタログを購読 カタログの状態が変わると、最新のテーブル情報をもとに自身を再描画
Editor CSV ブロックなど TableStore 2. コンテンツハッシュ計算 ( 例: def456) テーブル追加⽤ エントリーポイント 1. テーブル操作を実⾏ (CSV アップロード) 4. 参照切り替え スナップショット管理 DuckDB-WASM 新スナップショット snapshot.def456 旧スナップショット snapshot.abc123 カタログ管理 5. カタログ更新 カタログテーブル 3. 実テーブルを作成 参照 以前の参照 6. カタログを購読 + UI 再レンダリング 同期⽤コンポーネント イベント購読
3-1. 状態同期: DuckDB → Editor TableStore 内で依存関係を持つテーブルの更新を検知して下流のカタログにも反映 カスタムブロックは常に自身に対応するカタログ情報を購読するだけ
3-1. 状態同期: 依存関係の管理 データソースの変更や分析パイプラインの変更が下流ブロックに伝わり、UI がリアクティブに更新される 計算後の売上列を参照 価格と個数から 売上を計算 データテーブルブロック 集計ブロック
チャートブロック
3-2. 分析工程の記録
3-2. 分析工程の記録 集計ブロックのクエリを表現するデータ構造(JSON) をどう設計するか 開発初期 単一のクエリビルダーでJSON を構築してSQL に変換 前処理・集計・加工等の工程が混在 一部だけ変えたい・無効化したい場合、読み解く
のが大変 現在のアプローチ ステップを積み上げていくように分析工程を構築 1. フィルタ — 期間の絞り込み 2. 計算 — 売上を算出 3. 集計 — カテゴリ別に集計 4. ソート — 売上降順 5. フィルタ — 売上上位のみ絞り込み 各ステップの意図を把握しやすい構造に 並び替えや無効化を容易にして、探索的な分析を サポート SELECT category, SUM(price * qty) AS revenue FROM raw_sales WHERE date >= '2024-01-01' AND price > 0 AND qty > 0 GROUP BY category HAVING SUM(price * qty) > 10000 ORDER BY revenue DESC
3-2. 分析パイプラインの例 数量の絞り込み → 税込金額を計算 → 税込金額で降順ソート (※ 実際の構造とは異なります) 実行時にCTE
を使用したSQL へコンパイル { "base": { "table": "catalog.sales" }, "steps": [ { "op": "filter", "predicate": { "type": "binary", "op": "GT", "left": { "ref": { "name": "qty" } }, "right": 3 } }, { "op": "compute", "adds": [{ "alias": "tax_inc", "op": "MUL", "left": { "ref": { "name": "price" } }, "right": 1.1 { "op": "sort", "by": [{ "ref": { "name": "tax_inc" }, "order": "desc" }] } ] } WITH base AS (SELECT * FROM "catalog"."sales"), s0 AS (SELECT * FROM base WHERE "qty" > ?), s1 AS (SELECT *, ("price" * ?) AS "tax_inc" FROM s0), s2 AS (SELECT * FROM s1 ORDER BY "tax_inc" DESC) SELECT * FROM s2 -- params: [3, 1.1]
3-2. 実行までの流れ 各ステップで以下の処理を実行 1. 構造検証: ステップのJSON 構造を検証して、必要なフィールドの存在などをチェック 2. 名前解決: 式の中で使用されている列参照を、名前参照からID
参照に変換。以後の列参照はID で行う 3. 整合性検証: ステップに含まれる式が型や参照の整合性を満たすかをチェック 4. スキーマ導出: ステップ適用後に得られる新しいスキーマ情報を算出 ( 計算・集計後の列情報など) 5. コンパイル: 解決済みステップを SQL+ 実行パラメータ に変換する 6. 逆解決: 内部ID を元の列名に戻して編集操作に対応できる形に復元する
3-2. 列ID の用途 課題: 列名で参照すると壊れやすい 上流で列名を変更すると、それを参照している下流 のステップが壊れる 1. ステップ1 で
" 売上" 列を計算して追加 2. ステップ2 で " 売上" > 10000 でフィルタ 3. ステップ1 で " 売上" を "revenue" に列名変更 4. ステップ2 が壊れる(" 売上" が見つからない) 編集や入れ替えのたびに手動で直すのは大変 対応: 名前/ID の二層管理 保存時は列名参照、実行時は列の出自から生成した 決定論的なID で参照 JSON 上では "売上" > 10000 実行時は c_a3f8c2 > 10000 ID は正規化後の式などを用いて生成 列名を変更しても c_a3f8c2 は不変 実行後に現在の列名へ逆引きして、パイプラインを 自動更新
4. まとめ
4. 今後 足りない機能・やりたいことは山積み… 全体的なUI/UX の改善 ステップの意図を記録するためのメタデータ拡充 より多様なステップの提供 ( ピボット、条件分岐、ウィンドウ関数、…) ステップの入れ子構造やテンプレートのサポート
ステップ前後のテーブルプレビュー 計算式の手動入力対応 データリネージュの表示 複数ドキュメントを跨いだ参照 内部ID を利用した計算結果のキャッシュ 大規模データの扱い …
4. まとめ ブロック = table / view の 1:1 対応を設計の軸に
同期レイヤ + カタログ機能 + イベント通知 でリアクティブにUI を更新 パイプラインJSON + CTE コンパイル で分析工程をドキュメントに記録