Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save takahashim/2ee8490fafec2ef297d551542fcc3c25 to your computer and use it in GitHub Desktop.

Select an option

Save takahashim/2ee8490fafec2ef297d551542fcc3c25 to your computer and use it in GitHub Desktop.

hierarchical_result.json スキーマ分析

(2026/04/06 commit: 53f12097e2d9f4f481ca90b7df2ccee994073a97 )

目的

hierarchical_result.json のスキーマ定義がプロジェクト内でどこに存在し、それぞれが一致しているかを調査した結果をまとめる。


既存の定義箇所

場所 役割 備考
packages/analysis-core/src/analysis_core/steps/hierarchical_aggregation.py (37-56行) 生成コードの TypedDict Argument / Cluster のみ。ルートオブジェクトの型定義は無い
packages/analysis-core/tests/e2e/schemas/hierarchical_result.py Pydantic スキーマ(テスト用) HierarchicalResult / Argument / Cluster。バリデーションロジック付き
apps/public-viewer/type.ts (61-99行) TypeScript 型定義 Result / Argument / Cluster / Config。API層の追加フィールドも含む
docs/development/plugin-output-data-structures.md (174-216行) ドキュメント JSON例付きのフィールド説明

統一的な JSON Schema ファイル(.json 形式)は存在しない。


定義の不一致

フィールド単位の差異一覧

フィールド TypeScript (type.ts) Python TypedDict Pydantic (テスト) 実データ (新) 実データ (旧)
Argument.comment_id number str 欠落 int int
Argument.attributes Record<string, string | number>? dict[str, str] | None dict[str, str] | None - -
Cluster.density_rank_percentile number (non-null) float | None float | None float None
Result.comments Comments (必須) コード上 {} で出力 欠落 無し (新版) 有り (旧版)
Result.comment_num number (必須) コード上出力 int (必須) 有り 無し (旧版)
Result.filteredArgumentIds string[]? - - - -
Result.visibility ReportVisibility? - - - -
Result.visualizationConfig ReportDisplayConfig? - - - -
Cluster.allFiltered boolean? - - - -
Cluster.filtered boolean? - - - -

問題の詳細

A. comment_id の型不整合(最も深刻)

  • 生成コード(Python)は str(comment_id) としている → str のはず
  • しかし実データは int → 旧コードで生成された例が残っている可能性
  • TypeScript側は number と定義
  • Pydanticスキーマには そもそもフィールドが無い

B. attributes の値型

  • Python側: dict[str, str](文字列のみ)
  • TypeScript側: Record<string, string | number>(数値も許容)
  • 実際の生成コード(hierarchical_aggregation.py 308-312行)は int/float もそのまま入れる → TypeScript側が正しい

C. density_rank_percentile のnull許容

  • Python側: float | None(正しい。ルートクラスタでは 0 を設定するが、旧データには無い)
  • TypeScript側: numbernullを許容していない → バグの可能性)

D. comments フィールドの扱い

  • 旧コードでは実データを入れていたが、現在のコードではコメントアウトされ常に {}
  • TypeScript側は型定義が残っている
  • Pydanticスキーマからは既に削除済み
  • → 非推奨化の過渡期

E. API層で追加されるフィールド

  • filteredArgumentIds, visibility, visualizationConfig, allFiltered, filtered はパイプライン出力にはなく、API/フロントエンド層で付加される
  • これらが TypeScript の Result 型に混在しているため、「パイプライン出力の型」と「API応答の型」の区別がない

推奨方針

Python側(生成側)を正とする

JSONを生成するのはPython側であり、型の実態を決めるのは書く側。TypeScript側は消費するだけなので、生成側に合わせるのが自然。

具体的なアクション案

  1. Pydanticスキーマを analysis-core/src/ に昇格させ、正式なスキーマとする

    • comment_id を追加
    • attributes の値型を str | int | float に修正
    • 生成コード(hierarchical_aggregation.py)でもこのスキーマでバリデーションする
  2. TypeScript側を2層に分離する

    • PipelineResult = パイプラインが出力する純粋なJSON構造(Python Pydantic と1:1対応)
    • Result = API経由で受け取る構造(PipelineResult + visibility + visualizationConfig 等)
  3. comments フィールドの廃止を明確化する

    • 現在は空オブジェクトを出力しているが使われていない

参考: hierarchical_result.json の全体構造

ルートオブジェクト

{
  "arguments": [],
  "clusters": [],
  "comments": {},
  "comment_num": 0,
  "overview": "",
  "propertyMap": {},
  "translations": {},
  "config": {}
}
フィールド 説明
arguments Argument[] 抽出された意見リスト
clusters Cluster[] 階層クラスタ構造
comments Record<string, {comment: string}> コメントマップ(現在は常に空)
comment_num int 元コメント総数
overview string LLM生成の全体概要
propertyMap Record<string, Record<string, any>> 属性マッピング(カテゴリ等)
translations Record<string, any> 翻訳データ(設定時のみ)
config Config パイプライン実行時の設定全体

Argument

{
  "arg_id": "A1_0",
  "argument": "意見本文",
  "comment_id": "1",
  "x": 0.123,
  "y": -0.456,
  "p": 0,
  "cluster_ids": ["0", "1_3", "2_7"],
  "attributes": {"author": "山田太郎"},
  "url": "https://..."
}
フィールド 説明
arg_id string "A{comment-id}_{index}" 形式の一意識別子
argument string 抽出された意見テキスト
comment_id string ※型不整合あり 元コメントID
x float UMAP X座標
y float UMAP Y座標
p float 常に0(将来用)
cluster_ids string[] 先頭は必ず "0"、以降 "{level}_{num}" 形式
attributes Record<string, string | number> | null attribute_ プレフィックスの属性(プレフィックス除去済み)
url string | null enable_source_link=true 時のみ

Cluster

{
  "level": 1,
  "id": "1_3",
  "label": "交通",
  "takeaway": "交通に関する意見",
  "value": 42,
  "parent": "0",
  "density_rank_percentile": 0.83
}
フィールド 説明
level int 0=ルート、1以上=子階層
id string "0" or "{level}_{num}" 形式
label string LLM生成のラベル
takeaway string LLM生成の要約
value int クラスタ内の意見数
parent string 親クラスタID(ルートは空文字 ""
density_rank_percentile float | null 密度パーセンタイル

階層構造のルール

  • レベル0のルートクラスタ(id="0", label="全体")が必ず1つ存在する
  • 非ルートクラスタの parent は有効なクラスタIDを参照する
  • 各 Argument の cluster_ids は先頭に必ず "0" を含む
  • クラスタIDの形式: "{level}_{cluster_number}"(例: "1_5", "2_9", "3_17"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment