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
160
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
630
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
S3 Filesで挑む! 八戸せんべい汁の食べ頃問題
usanchuu
0
160
CTO Night|NotionのAIエージェントとFDE
kzkhykw1991
0
310
局所最適は悪ではない。壊れているのは指標です。量と質を同時に見る先行指標の設計
recruitengineers
PRO
2
610
LambdaWebFunctionsを試してみた / exploring-lambda-web-functions
koukihosaka
1
390
AWS Continuum for Penetration Testing に Deep Dive してみる
asanoharuki
0
350
React改造してみた
tsukina_7mochi
0
160
How to Design Configuration for Rails Applications
willnet
1
1.1k
AI駆動開発におけるハーネスエンジニアリングの勘所
tsukuboshi
1
590
Kiro Crewで「みのるん式」仕事術やってみた
minorun365
PRO
3
1k
CSS2026:OWS研究会・招待講演「世界観を、実装する」
atsush1_sada
2
240
Code for Security プロジェクト紹介 2026年10月
yu23ki14
0
120
日本語に強いオープンな大規模言語モデル「LLM-jp」
odashi
5
1.2k
Featured
See All Featured
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
3k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
740
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
860
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
530
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
20k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
68
59k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
420
Producing Creativity
orderedlist
PRO
348
41k
Between Models and Reality
mayunak
4
500
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3.1k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
1k
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 コンパイル で分析工程をドキュメントに記録