qa-labo 2026年春: filter、join、calc、そして大量の新マテリアル
QA ZERO の重たい開発作業のほとんどは、qa-labo という兄弟リポジトリで行われています。新機能はまずここで実験的にインキュベートされ、その後プロダクションプラグインへと取り込まれていきます。この記事は、その作業から定期的に発信していきたいと考えているノートの第 1 弾です。
このブログが前回更新されて以降、qa-labo は元の QAL 2025-10-20 ガイドが「まだ利用できない」としていた機能のほとんどを埋めてきました。API バージョンは 変更されていません — これらはすべて後方互換な追加なので、?version=2025-10-20 を使い続けたまま新機能を使い始めることができます。
QAL の新機能
最初のリリースでは from + keep 程度しか提供されていませんでした。今では本格的なクエリを書くことができます。
filter— フラット形式で AND 結合される行フィルターで、10 種類の演算子(eq、neq、gt/gte、lt/lte、in、contains、prefix、between)が使えます。キーはソースマテリアルに属する素のカラム名なので、{ "device_type": ["SP"], "url": { "prefix": "/blog" } }のように書くだけで動きます。join— 1 つのビューにつき 1 回の等結合(equi-join)のみ、id カラム限定です。gscのような N:M マテリアルでは、結合先に対するフィルターが必須になりました(エグゼキューターがE_JOIN_FILTER_REQUIREDとして強制します)— これは、迷い込んだ join が 100 PV のページを 15,000 行に膨張させた本番事故を受けての仕様です。このルールは意図的に厳格になっています。calc— ホワイトリスト方式の集計(COUNT、COUNTUNIQUE、SUM、AVERAGE、MIN、MAX)で、引数は単一カラム限定です。COUNT(*)は引き続き禁止 — 必ずカラム名を指定する形で、オプティマイザに正直な情報を与える設計になっています。- ビューチェイニング — 同じ
makeブロック内でのfrom: ["<earlier_view>"]記法です。ここから QAL は本物のクエリ言語らしくなってきます。ベースビューで一度フィルターし、その結果を子ビューで 2 通りに集計する、といったことがカラム DB を再スキャンせずに書けます。 result.sort、result.sample、result.include_count— これらのキーは仕様として予約されていますが まだ実装されていません。sortは現在E_RESULT_FORBIDDEN_KEYとして拒否され、sample/include_countはバリデーションは通過しますが no-op です。/guideのfeaturesマップでオンになるまでは、ソートとサイズチェックはクライアント側で行ってください。
QAL とは何か? と なぜ QAL なのか? のコンセプトページがこれらを網羅しており、正本である qal-validation.yaml も、当初の「すべて無効」というスタブから、エグゼキューターの実際のルールを反映したものに更新されました。
新しいマテリアル
allpv と gsc だけではなくなりました。/guide では現在、以下が公開されています。
goal_1..goal_N— PV ごとのコンバージョンログで、設定されたゴールごとに 1 つのマテリアルが用意されます。「この PV はゴール 3 を達成したか?」を知りたい場合には、allpv上に 仮想 カラムis_goal_1..is_goal_10もあるので、マテリアルを切り替えずにフィルターできます。ga4_age_gender、ga4_country、ga4_region— T48 で GA4 の属性データが着地しました。これらは集計マテリアル(pv_idを持たない)で、ファーストパーティトラッキングでは見えないデモグラ情報をallpvに補完することを意図しています。page_version— ページごとのコンテンツバージョンを追跡するマテリアル(T53)です。version_idでallpvに 1:1 で結合されるため、行の爆発を気にせず PV にバージョンメタデータを付与できます。click_event— セレクター、要素テキスト、遷移先 URL、ページ相対座標を含むクリックイベントです。pv_idで結合できます。datalayer_event(+ 動的なevents.{name}) — dataLayer イベントを送出しているサイトでは、全イベントの統一インデックスに加え、そのイベントのパラメーターを反映した型付きのイベント別マテリアルの両方が利用できるようになりました。/guideのレスポンスには、そのサイトが公開しているすべてのevents.*マテリアルが列挙されます。
そして allpv 自身にも多数の新カラムが追加されました。行動メトリクス(depth_position、deep_read、stop_max_sec、stop_max_pos、exit_pos、is_submit、dead_click_image_count、irritation_click_count、scroll_back_count、content_skip_count、exploration_count)と、生成されるページタイプ判定フラグ(is_article、is_product、is_form、is_faq など)です。キュレーションされたリストは allpv マテリアルページ を、完全な正本スキーマは GitHub の ai/materials.yaml を参照してください。
なぜ「AI のためのナレッジベースとしてのドキュメント」なのか?
このブログは意図的に パブリック リポジトリに置かれています。QA ZERO の API ドキュメントは、人間の開発者だけでなく、これから QAL クエリを書こうとしている AI アシスタント のためにも最適化されています。LLM があなたのために有効なクエリを生成するには、次のものが必要です。
- 正確で機械可読なバリデーションルール(だからこそバリデーションマニフェストの YAML frontmatter は本文と一致しています)。
- マテリアルごとに許可されているカラム名の明確なリスト(だからこそすべてのマテリアルページは
/guideからリンクされています)。 - 原因まで含めた明示的なエラーコード(これによりアシスタントはハルシネーションではなく自己修正できます)。
ブログ自体はもっと気軽なチャンネルです。設計ノート、「なぜこう作ったか」というストーリー、開発日記など。更新は不定期になる予定です — 固定のペースではなく、qa-labo で面白いものが出たときに書きます。
次に来るもの
今デスクの上にあるショートリストはこんな感じです。
- フィルター条件をまたぐ
OR(filterが出てから一番多い要望です)。 - 集計結果に対する HAVING 形式のフィルタリング。
- 「500 万行ほしい」ケースのための、CSV と Parquet 出力に対応した
return.mode = "FILE"。 - 追加のソースが着地するのにあわせて、さらに属性マテリアルを増やしていく。
QA ZERO API を使って開発していて、新しい範囲の何かが不明瞭であれば、quarka-org/docs.qazero.com に issue を立ててください — このリポジトリがパブリックなのは、まさにドキュメントの問題をコードの問題と同じくらい気軽に報告できるようにするためです。
— Koji