TECH PLAY

株式会社G-gen

株式会社G-gen の技術ブログ

744

G-gen の藤岡です。2022年10月より提供が開始された Professional ChromeOS Administrator 試験は、管理コンソールの操作や ChromeOS の運用、管理方法を問う試験です。当記事では試験合格に役立つ内容をご紹介します。 はじめに Professional ChromeOS Administrator とは 難易度 学習方法 注意点・出題傾向 管理コンソール 管理コンソールとは ChromeOS デバイスポリシーとユーザーポリシー デバイスの登録 手動登録 ゼロタッチ登録 ワイプしたデバイスの再登録 運用・管理 OS のアップデート 自動更新 リリースチャンネル ライセンス シングルサインオン (SSO) セキュリティ ドメインの所有権 確認済みブート 新機能のリクエスト はじめに Professional ChromeOS Administrator とは Professional ChromeOS Administrator 試験は、Google の提供するコラボレーションツールである Google Workspace や ChromeOS デバイスの管理者向けの試験です。Google Workspace 管理コンソールの操作や ChromeOS の運用、管理方法が問われます。 当試験は Google Cloud の公式ブログ で紹介されているものの、 Google Cloud 認定試験一覧 には記載されていません。 試験申込時に Google Cloud 認定試験とは別のアカウントが必要です。 当試験は英語と日本語で受験できます。問題数は 50 問で、試験時間は 120 分です。試験の提供開始当初はハンズオンラボも含まれていましたが、2023年11月現在はハンズオンラボが廃止され、Google Cloud 認定試験と同様に複数選択式となっています。 当試験は 2024年1月まで無料で受験可能であり、それまでの間は受験費用125ドルを Google が負担するとされています。 参考 : Professional ChromeOS Administrator 難易度 当試験の難易度は 中程度 と言えます。 前提知識として、IPA の IT パスポート試験程度の IT 基礎知識に加え、PC や OS に関する基礎知識があると良いでしょう。 既に Professional Google Workspace Administrator を取得している人や、日常的に管理コンソールを触っている人、Chrome OS に関わらず情報システム部門などで PC 管理をしている人であれば、当記事を参考に知識をアドオンしていけば、合格は難しくありません。 学習方法 おすすめの学習方法は、以下です。 公式の 試験ガイド に掲載されている動画とドキュメントを確認する 試験範囲の中で理解できない内容や知らない単語を無くす 実際に管理コンソールを触る 管理画面をある程度自由に触れるのが理想的 自由に変更できない環境の場合は、閲覧権限だけでも手に入れ、各種設定画面を確認する 当記事を読んで知らない範囲を無くす 注意点・出題傾向 当試験の注意点として以下のようなものがあります。 日本語版試験は、英語版試験を翻訳したものですので、若干の違和感を感じる文章もあります。特に公式ドキュメントやコンソールの日本語訳と、試験の日本語訳が違う場合もあります 管理コンソールにおける細かい操作 (設定箇所) を問われる場合があります 出題傾向は、基本的には試験ガイドに沿うものになりますが、当記事ではより詳細に記載しますので、学習の参考にしてください。 当記事ではこれ以降、試験の出題傾向をジャンルごとに提示します。 管理コンソール 管理コンソールとは 管理コンソール とは、 Google Workspace サービスのユーザー追加や削除、デバイスの管理設定を行う画面です。 管理コンソールにログインするには管理者ロールが必要です。そのため既定の管理者ロールもしくはカスタム管理者ロールを作成し、システム管理者に付与します。 参考 : 管理コンソールについて ChromeOS デバイスポリシーとユーザーポリシー ChromeOS デバイスには、 デバイスポリシー と ユーザーポリシー を適用できます。 デバイスポリシーは、管理対象の ChromeOS デバイスに対して適用されます。そのため、ChromeOS デバイスにログインするユーザーアカウントの種類 (会社アカウントや個人 Gmail アカウント、ゲストなど) に関わらず適用されます。 それに対してユーザーポリシーは、Google アカウントに対しての適用となります。 これは Active Directory のグループポリシーで、ユーザーとコンピューターに対するポリシーの違いに似ています。 両者の違いと管理コンソールでの設定方法を押さえておきましょう。 また、これらのポリシーを使ってリモート管理するには、Chrome Enterprise Upgrade または Chrome Education Upgrade ライセンスが必要です。 参考 : Chrome ポリシー管理の概要 参考 : 概要: ChromeOS デバイスのポリシーの管理 参考 : ユーザーまたはブラウザに Chrome のポリシーを設定する デバイスで有効になっているポリシーは、管理対象デバイスで chrome://policy にアクセスすることで確認できます。 参考 : デバイスの現在の Chrome ポリシーを表示する デバイスの登録 手動登録 ポリシーを適用するには、ChromeOS デバイスを管理対象とする必要があります。ChromeOS デバイスを管理下とするには、「手動」または「自動」で ChromeOS デバイスを登録します。 それぞれの登録方法について押さえておきましょう。 参考 : 端末の登録と消去 ゼロタッチ登録 ゼロタッチ登録 とは、ChromeOS デバイスにメーカーや販売業者などが顧客ドメインを自動設定するサービスです。 通常、会社用端末として ChromeOS デバイスを使う場合にポリシーを適用するには、管理コンソールからデバイスを手動で登録する必要があります。しかしゼロタッチ登録を使うことで、システム管理者は大量のデバイスを手動で登録する必要がなくなります。利用者がデバイスをインターネットに接続すると、デバイスはドメインに自動登録されます。 この時、システム管理者がメーカーや販売業者に提供する情報や事前プロビジョニングトークンの生成方法を押さえておきましょう。 参考 : ゼロタッチ登録 ワイプしたデバイスの再登録 デバイスを出荷時の状態に戻すことを ワイプ と言います。 ChromeOS では、管理対象のデバイスを管理コンソールからワイプできます。これによってデバイスが紛失や盗難にあった場合に、データの悪用を防げます。 参考 : ChromeOS デバイスのデータをワイプする ワイプした ChromeOS デバイスは、デフォルトでは自動的に再登録されます。 参考 : ワイプした ChromeOS デバイスを自動的に再登録する 運用・管理 OS のアップデート 自動更新 ChromeOS は特定の周期でアップデートがリリースされます。アップデートにはセキュリティ修正も含まれているため、定期的にアップデートを適用する必要があります。手動での適用では、適用漏れも出てきてしまうため、 自動更新 が推奨されます。 参考 : ChromeOS デバイスの更新を管理する 自動更新がされない場合のトラブルシューティング方法も把握しておきましょう。 参考 : ChromeOS のバージョンが自動更新されない リリースチャンネル リリースチャンネル を設定することで、どのアップデートを展開するか制御できます。リリースチャンネルには以下の 5 つがあります。 Stable 長期サポート (LTS) 長期サポート候補 (LTC) Beta Dev 特に Stable と長期サポート (LTS) チャンネルのユースケースや展開時のベストプラクティスについて、以下のようなドキュメントを押さえておきましょう。 参考 : ChromeOS デバイスの更新を管理する 参考 : Chrome OS リリースのおすすめの使用方法 ライセンス 前述の通り、ChromeOS デバイスをリモート管理するには Chrome Enterprise Upgrade または Chrome Education Upgrade ライセンスが必要です。 ライセンスの割り当て状況の確認方法を押さえておきましょう。 参考 : Chrome のアップグレードを使用する シングルサインオン (SSO) Chrome アプリで SAML (Security Assertion Markup Language) シングルサインオン (SSO) を設定するには、 SAML SSO for Chrome Apps 拡張機能を使います。 この時、ユーザー情報である Cookie は許可リストに登録されたドメインにのみ渡されます。 参考 : Chrome アプリに SAML シングル サインオンを設定する 参考 : ChromeOS デバイスのポリシーを設定する > シングル サインオン Cookie の動作 セキュリティ ドメインの所有権 取得したドメインが第三者に利用されないようにするために、 ドメインの所有権を証明 する必要があります。Google Workspace を利用開始するには、ドメインの証明が必須です。 ドメインの所有権の証明方法、また DNS 設定時に TXT レコードが必要 な点を押さえておきましょう。 参考 : ドメインの所有権を証明して、さらに多くの機能を利用できるようにする(メール確認によるアカウント用) 参考 : ドメインの所有権を TXT レコードで証明する 確認済みブート ChromeOS は起動時に 確認済みブート (確認付きブート / Verified boot) と呼ばれるセルフチェックが行われます。この機能によってシステムの改ざんや破損が検出された場合、自動修復されます。 英語のドキュメントではありますが、以下のドキュメントを一読しておきましょう。 参考 : Verified Boot in Chrome OS and how to make it work for you 新機能のリクエスト Chrome Enterprise Trusted Tester に登録すると、Chrome の新機能のテストと Google のプロダクトチームへ直接フィードバックすることができます。 参考 : Chrome Enterprise Trusted Tester になる 藤岡 里美 (記事一覧) クラウドソリューション部 数年前までチキン売ったりドレスフィッティングしていました。2022年9月 G-gen にジョイン。 Google Cloud All Certifications Engineer / Google Cloud Partner Top Engineer 2024 Follow @fujioka57621469
アバター
G-gen の佐々木です。当記事では、Cloud Run などのサーバーレス サービスが VPC リソースにプライベート IP で接続するために使用する サーバーレス VPC アクセス のスケールインをダウンタイムなしで行う方法を解説します。 サーバーレス VPC アクセスとは コネクタインスタンスのスケールイン問題 問題 再作成を安全に行う方法 手順 前提条件 新コネクタインスタンスの作成 使用するコネクタインスタンスの切り替え 旧コネクタインスタンスの削除 サーバーレス VPC アクセスとは サーバーレス VPC アクセスとは、Cloud Run、Cloud Functions などのサーバーレスなサービスがプライベート IP を使用して Cloud NAT や Cloud SQL、Memorystore などの VPC リソースに接続するための機能です。 サーバーレス VPC アクセスでは、接続先となる VPC 内のサブネット、もしくは専用に確保した IP アドレス範囲を使用して VPC 内に サーバーレス VPC アクセスコネクタ と呼ばれるインスタンス(以下、 コネクタインスタンス )を作成します。 VPC の外にあるサーバーレスサービスは、このコネクタインスタンスを経由することで VPC 内リソースにプライベート IP アドレスで接続できるようになります。 参考: Serverless VPC Access サーバーレスVPCアクセスコネクタを使用したVPCリソースへの接続例 コネクタインスタンスのスケールイン問題 問題 サーバーレス VPC アクセスでは、VPC に接続するために作成するコネクタインスタンスの最小数(2~9)と最大数(3~10)をあらかじめ設定します。コンテナインスタンスの負荷が高まると、最大で設定した値までインスタンスがスケールアウトします。 このスケーリングの仕様として、一度スケールアウトしたインスタンス数は 二度とスケールインすることがありません 。 サーバーレス VPC アクセスの料金はコネクタインスタンスの数に比例して増加するため、一度のスパイクでスケールアウトしただけであっても、スケールアウト後のコストがずっと発生してしまうことになります。 コスト節約のため一度スケールアウトしたコネクタインスタンスを減らしたい場合、コネクタインスタンスを 再作成 する必要があります。 再作成を安全に行う方法 コネクタインスタンスを減らすためには一度削除してから再作成が必要ですが、コネクタインスタンスを一度削除すると、アプリケーションから Cloud SQL などへの接続は一時的にできなくなってしまいます。 この接続断の影響を最小限に抑えるためには、以下のような手順を踏みます。 旧コネクタインスタンスを残したまま新コネクタインスタンスを作成 接続元のサービス側設定において使用するコネクタインスタンスを新コネクタインスタンスに切り替え 旧コネクタインスタンスを削除 コネクタインスタンスはサブネット、もしくは IP アドレス範囲に紐づくリソースであり、VPC 内には複数のコネクタインスタンスを作成することができます(アドレス重複は不可)。これを利用して、サービスがコネクタインスタンスを使用できない時間が発生しないようにします。 手順 前提条件 当記事では、Cloud Run からコネクタインスタンスを経由して Cloud SQL に接続しているケースを例として使用します。 初期状態として、以下の図のようにコネクタインスタンスがスケールアウトした後の状況を想定します。 コネクタインスタンスがスケールアウトした後の状態 新コネクタインスタンスの作成 既存のコネクタインスタンスを残したまま 、任意のインスタンス数を設定したコネクタインスタンスを新規に作成します。 新規作成するために、コネクタインスタンス用のサブネット、もしくは IP アドレス範囲を新たに確保する必要があります。 コネクタインスタンスを新規作成する 使用するコネクタインスタンスの切り替え 接続元のサービス側でサーバーレス VPC アクセスの設定を修正します。 Cloud Run の場合はリビジョン機能を使用して、新規作成したコネクタインスタンスを使用するように設定し直した新しいリビジョンをデプロイします。 使用するコネクタインスタンスを切り替える 旧コネクタインスタンスの削除 最後に、無駄なインスタンス料金が発生しないように、古いコネクタインスタンスを削除します。 注意点として、 使用中のコネクタインスタンスも削除できてしまいます。 現在使用されているほうを削除してしまい、接続断が発生してしまうといったことが起こらないように気をつけましょう。 古いコネクタインスタンスを削除する 佐々木 駿太 (記事一覧) G-gen 最北端、北海道在住のクラウドソリューション部エンジニア。 2022 年 6 月に G-gen にジョイン。Google Cloud All Certifications Engineer。 好きな Google Cloud プロダクトは Cloud Run。 Follow @sasashun0805
アバター
G-genの田中です。当記事では、Cloud Storage を利用する中で、意図していない高額の請求が発生してしまった事例について解説していきます。 はじめに 背景 Cloud Storage とは Cloud Storage の料金 Storage Transfer Service とは 事件のあらまし 背景 落とし穴 莫大な課金の発生 後日譚 はじめに 背景 今回、G-gen でサポートさせて頂いているお客様が Storage Transfer Service を利用して Cloud Storage へデータ移行を行ったところ、 3日間で数十万円の課金が発生してしまった という事件があり、注意喚起のために記事化させて頂くことになりました。 本記事は、お客様名の許諾を得た上で、実際に起きた内容を少し改変して記事化しました。お客様の社内事情のため数値等を事実とは違うものにして記載していますが、記事の目的に沿うように、重要なエッセンスには影響しないよう改変してあります。 Cloud Storage とは Cloud Storage とは Google Cloud (旧称 GCP) の容量無制限・低価格・堅牢なオブジェクトストレージサービスです。Google Cloud Storage を略して GCS と呼ばれることもあります。 データは少なくとも 2 つ以上のゾーンで冗長化され 99.999999999%(イレブンナイン)の堅牢性を誇ります。詳細は以下の記事もご参照ください。 blog.g-gen.co.jp Cloud Storage の料金 Cloud Storage は、安価であることが特徴です。東京リージョンの Standard Storage のデータ保管料金は2023年11月現在で $0.023 (GB/月) です。ドル・円レートにもよりますが概ね 1 TB で3,000円〜3,500円程度と認識すれば良いでしょう。 ただし Cloud Storage の料金はデータ保管ボリュームだけでなく、API リクエスト回数など、複数の軸で課金されます。 最新の料金は以下の料金ページをご参照ください。 参考 : Cloud Storage の料金 Storage Transfer Service とは Storage Transfer Service は Google Cloud サービスの1つで、異なるストレージ間で自動的にデータを移行するためのツールです。 オンプレミスのデータセンター、他のクラウドプロバイダー等の異なるデータソースから、高い信頼性で迅速に Cloud Storage へデータを移行できます。 参考 : Storage Transfer Service とは 事件のあらまし 背景 本来実施したかったことは「 Google Drive 内の約 6TB のファイルを Cloud Storage にバックアップ したい」ということでした。 お客様は、当初は「データ量が 6TB なので、2万円程度のデータ容量課金が発生する程度だろう」と試算し、本作業を実施しました。 落とし穴 このバックアップ作業には、大きな落とし穴がありました。 それは ファイル数 です。これを課金体系の観点から正しい言い方をすると「 API コール数 」です。 前述の通り Cloud Storage ではデータサイズの他に、データの読み込みや書き込みといった API コールの数に応じて課金されます。今回のような作業では Storage Transfer Service が Cloud Storage にデータを書き込むため、その際に API コールと課金が発生します。 参考 : Cloud Storage の料金 - オペレーション料金 参考 : Storage Transfer Service の料金 - ファイル システム転送の料金の詳細 莫大な課金の発生 あとで分かったことですが、今回の件では Google Drive の中に1ファイルあたり数バイトのログファイルが 約8億個 ありました。 ファイルサイズは約 6TB のためデータ保管料金は当初見積もった通り「2万円程度」でしたが、約8億個のファイルを書き込むために約8億回の Cloud Storage API 書き込みオペレーション料金が発生してしまいました。 Standard Storarge への書き込みは、1,000回あたり$0.005です(Archive Storage への書き込み等であれば、さらに高価になります)。8億回であれば $4,000(約580,000円)となります。これが、課金の原因でした。 後日譚 後日お話をお伺いした所、この作業を行った担当者様は入社2ヶ月ほどで、前任担当者からは膨大なファイルサイズについては引き継ぎを受けていませんでした。データサイズから想像できないファイル数が存在したことが、この事案を引き起こしたと言えます。 Cloud Storage の利用料金はデータ保管ボリュームだけでなく、API リクエストの回数による課金も発生することを念頭に置いて利用することが大切だと、改めて実感する事例となりました。 田中 祐平 (記事一覧) ビジネス推進部 営業1課 2022年8月よりG-gen にジョイン。 大手製造の販売会社から、Google専業の営業へ。広島県在住でGoogle Workspaceをメインに活動中。週末はキャンプで山に籠もってます。
アバター
G-gen の堂原です。本記事では Google Cloud (旧称 GCP) の生成 AI サービスである Vertex AI Search の活用事例 として、技術サポート窓口支援ツールを紹介します。 はじめに 本ツールの概要 デモ 処理フロー 技術的ポイント Vertex AI text-bison model Vertex AI Search 生成 AI アプリケーションの開発 はじめに 当記事では、G-gen の技術サポート窓口にて実際に運用されている生成 AI アプリケーションである Tech Support Powered by Generative AI (以降、「本ツール」)について解説します。 G-gen では Google Cloud および Google Workspace の 請求代行サービス を契約いただいているお客様に、無償の技術サポート窓口を提供しています。この窓口では、Google Form にて問い合わせが投稿されると担当エンジニアが調査・検証を行い、メールで回答しています。 過去のケースにおけるメールのやりとりは蓄積されていますが、これまでは担当エンジニアが類似したケースを都度、手で検索して利用していました。そこで G-gen では生成 AI を活用して過去ケースや公式ドキュメント、G-gen Tech Blog からの情報抽出を効率的に行う本ツールを開発しました。本ツールについてはプレスリリースも公開しております。 g-gen.co.jp 本ツールの概要 本ツールは、お客様より Google Form で問い合わせが投稿されると「その問い合わせに類似する過去ケース」「関連する公式ドキュメント」「G-gen Tech Blog 記事」から検索を行い、関連情報を取得します。 検索後は Vertex AI Search により要約文の生成が行われ、最終的に Slack にメッセージとして投稿されます。 デモ 以下は本ツールのデモ動画です。 youtu.be 技術サポート用の Google Form から問い合わせが投稿されると、本ツールは「お問い合わせ内容詳細」に記載された文章に対して処理を行います。動画内では以下のような問い合わせを行っています。 Compute Engine から Cloud Storage のファイルにアクセスしたいです。 社内システムの開発がストップしており困っております。 試しに gsutil でバケットの一覧を 検索してみたのですが、 403 Permission 'storage.objects.list' denied on resource (or it may not exist) とエラーになってしまいます。 また、 gsutil で特定のオブジェクトをダウンロードする方法もご教授ください 上記の質問文は、質問内容と直接関係のない「困っております」といった文言や、文章の途中での改行など、機械的な検索の支障になりえる要素が含まれています。 フォーム投稿後、約 30 秒ほどで Slack に bot によるメッセージが投稿されます。 この際、先程の問い合わせ文章が 質問 と エラーメッセージ に分解されます。動画内では 2 つの質問と 1 つエラーメッセージが出力されています。 質問 Compute Engine から Cloud Storage のファイルにアクセスしたい gsutil で特定のオブジェクトをダウンロードする方法 エラーメッセージ 403 Permission 'storage.objects.list' denied on resource (or it may not exist) 最後に各質問とエラーメッセージについて 回答 (Vertex AI Search による要約文) 、 関連リンク および 類似過去ケース が出力されています。 処理フロー 本ツールでは、次のようなフローで処理が進められます。 フォーム投稿をトリガーとして Google Apps Script (GAS) が起動し Cloud Functions を呼び出す Vertex AI text-bison model を用いて、問い合わせ文章から質問とエラーメッセージを切り出す Vertex AI Search を用いてウェブサイト (公式ドキュメント、G-gen Tech Blog) および過去ケース (Cloud Storage に格納されたテキストファイル) の検索を行い、要約文の生成を行う Slack にメッセージとして出力する 技術的ポイント Vertex AI text-bison model 本ツールでは、 Vertex AI text-bison model による質問およびエラーメッセージの切り出しが行われています。 これは、問い合わせ文章そのままでは Vertex AI Search で十分な検索結果が得られないためです。 text-bison を用いることで、エラー解決には必要のない文や文章中の改行等がうまく処理され、必要な部分のみを綺麗に抽出することができます。 プロンプト設計においては Few-shot prompting を用いることで出力イメージのチューニングを行っています。 Vertex AI Search ウェブサイトや過去ケースからの検索と回答文の生成には Vertex AI Search を用いています。 Vertex AI Search の最大の強みは プロンプト設計やモデルチューニングが必要ない ことです。 過去ケースの検索は、テキストファイルを Cloud Storage にアップロードして非構造データのデータストアとしてを指定するだけで実装できます。この際、何かしらの制約に従ってテキストファイルを整形する等の前処理も必要ありません。 Vertex AI Search については、以下の記事で徹底解説していますのでご参照ください。 blog.g-gen.co.jp 生成 AI アプリケーションの開発 もし自組織で生成 AI アプリケーションの開発を検討中なら、G-gen 社の Generative AI 活用支援ソリューションをご検討ください。 プロフェッショナルが、貴社の生成 AI 活用を支援します。詳細は以下からお問い合わせください。 g-gen.co.jp 堂原 竜希 (記事一覧) クラウドソリューション部データアナリティクス課。2023年4月より、G-genにジョイン。 Google Cloud Partner Top Engineer 2023, 2024に選出 (2024年はRookie of the yearにも選出)。休みの日はだいたいゲームをしているか、時々自転車で遠出をしています。 Follow @ryu_dohara
アバター
G-gen の杉村です。2023/11/15から2023/11/16までの二日間、東京ビッグサイトにて4年ぶりの現地開催となる Google Cloud Next Tokyo '23 が開催されました。当記事ではその発表内容についてレポートします。 開催場所 展示内容 一日目 基調講演(キーノート) 二日目 基調講演(キーノート) Vertex AI におけるグラウンディング G-gen スポンサーセッション 動画の公開 開催場所 Google Cloud Next Tokyo '23 は4年ぶりの東京ビッグサイトにおける現地開催となりました。 展示内容 Google Cloud がホストする基調講演(キーノート)、ジャンルごとに分類されたブレイクアウトセッションをはじめ、G-gen も登壇したスポンサーセッションなど、多くの発表がされました。 また協賛企業が展示ブースを出展するスポンサーブース、Google Cloud の操作を体験できるハンズオンセッション、エンジニアのための Innovators Hive などの展示が行われました。 当社 G-gen も「G-gen Tech Booth」と称して出典しており、お客様をお呼びしたブース内セッションを行うなどして賑わいました。 基調講演会場 ブレイクアウトセッションルーム スポンサーブース Innovators Hive G-gen Tech Booth 一日目 基調講演(キーノート) 2023/11/15 (水) の朝10:00、Google Cloud Next Tokyo '23 は基調講演(キーノート)から始まりました。 同講演では、Google Cloud Japan の代表である平手 智行氏が、 AI First である従来からの姿勢を再度、強調しました。 ユーザーとして中外製薬株式会社 志済 聡子 氏が、同社での Google Cloud や生成 AI の利用事例に加え、医療機関向けの生成 AI モデルである Med-PaLM 2 を活用することなどを発表しました。また株式会社ZOZO 風間 昭男 氏が登壇し、ファッションコーディネートの紹介文等における生成 AI の活用について語りました。 技術的な目新しい発表内容としては、以下のようなものがありました。 Duet AI in Google Workspace 日本語対応(2024年を予定) Generative AI support on Vertex AI でグラウンディングが可能になる PaLM 2 各種モデルでファインチューニング方法の拡張 Duet AI in Google Workspace は既に英語版では GA(一般提供)されているサービスです。Google Workspace による人間の業務を生成 AI が補助するサービスです。通常の Google Workspace ライセンスとは別のアドオンライセンスとして提供されます。この Duet AI in Google Workspace の日本語対応が、2024年に予定されていることが発表されました。 また Generative AI support on Vertex AI におけるグラウンディング機能 の公開予定もデモを交えて発表されました。グラウンディングとは、生成 AI が事実と異なる結果を生成してしまう「ハルシネーション」を抑制するために、Web サイトやドキュメント類を引用して生成結果を補強する技術です。今回発表されたのは、Vertex AI 経由の PaLM 2 等生成 AI モデルの利用の際、Vertex AI Search に登録済みのデータストアを利用してグラウンディングを行うことができるようになります。Vertex AI Search は生成 AI を利用した検索機能を提供するサービスであり、既に GA されています。 PaLM 2 各種モデルでファインチューニング方法の拡張としては、少量のサンプルや人のフィードバックによる精度向上を可能にする機能の公開予定が発表されました。 二日目 基調講演(キーノート) 二日目のキーノートでは、Borg、Colossus といった Google の基盤技術について再確認するとともに、開発にフォーカスした発表がされました。 ユーザー事例として、株式会社カプコンの井上 真一 氏、北國フィナンシャルホールディングスの杖村 修司 氏、株式会社 TBSテレビの山本 善尚 氏、株式会社Luupの岡田 直道 氏らが登壇し、各社の Google Cloud や Google Workspace の活用事例が語られました。 2023年8月のGoogle Cloud Next in San Francisco でも発表された Duet AI in Google Cloud のデモも行われました。自然言語での指示に応じて自動的に BigQuery へのクエリが生成され、Looker Studio でデータが可視化される様子が実演されました。 Vertex AI におけるグラウンディング ここまで見たように、Google Cloud Next Tokyo '23 の基調講演の発表内容は概ね、これまで既に発表されている内容の再確認でした。 しかし生成 AI に関しては、一日目の基調講演で Generative AI support on Vertex AI に関するデモで新機能が実演されました。 同デモでは Vertex AI の生成 AI 開発のための Web UI である Generative AI Studio から Vertex AI Search の「データストア」をグラウンディング先として指定し、その情報に基づいてテキストが生成される様子が実演されました。 Vertex AI Search については以下の記事もご参照ください。 blog.g-gen.co.jp これは現在提供されていない新機能であり、公開されれば PaLM 2 API での生成時に、LangChain 等のフレームワークや独自実装を用いずに容易にグラウンディングを実装できるようになると考えられます。 具体的な機能の詳細や公開時期については発表されませんでしたが、進化する Google Cloud の生成 AI 関連機能の一端が垣間見えるものとなりました。 G-gen スポンサーセッション G-gen の CTO 杉村はセッション「11 冠エンジニアを輩出した組織とは?チーム立ち上げのための 6 つのキーポイント」で登壇しました。 G-gen が設立された2021年9月から2023年11月までに、Google Cloud 認定資格を11個コンプリートしたエンジニアを8人、Partner Top Engineer を9人輩出したエンジニア組織文化などについて紹介しました。 動画の公開 基調講演のアーカイブ動画は、以下の公式サイトから視聴可能です。 G-gen の CTO 杉村が登壇したセッション「11 冠エンジニアを輩出した組織とは?チーム立ち上げのための 6 つのキーポイント」を含む、その他のセッション動画は 12 月中旬に公開が予定されています。 cloudonair.withgoogle.com 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen 又吉です。当記事では、LangChain と Vertex AI Search で Google Cloud 公式ドキュメントから回答を生成する LLM を構築してみたいと思います。 はじめに Vertex AI Search and Conversation とは LangChain とは 今回の構成 環境構築 API の有効化 Vertex AI Search データストア アプリ 実行環境 初期設定 ライブラリインストール ユーティリティ関数 モデルの初期化 Vertex AI Search 関数 テキスト分割関数 RAG を実行する関数 実行 はじめに Vertex AI Search and Conversation とは Vertex AI Search and Conversation とは、Google の生成 AI 技術を簡単に利用するためのフルマネージドの Google Cloud プロダクトであり、インフラの構築・運用を意識する必要がなく、API 経由で自社の Web サイトやアプリから呼び出して利用します。 今回は Vertex AI Search and Conversation の「Vertex AI Search」を使って、Google Cloud の公式ドキュメント (Web サイト) を検索対象として検索を実装します。 Vertex AI Search and Conversation の詳細については、以下の記事をご参照ください。 blog.g-gen.co.jp LangChain とは LangChain とは、LLM を用いてアプリケーションを効率よく開発するためのフレームワークです。 今回は、LangChain を用いてテキスト分割を行ったり、ベクトルデータベースの構築とベクトル検索の実装などを行っていきます。 LangChain の詳細については、以下の記事をご参照ください。 blog.g-gen.co.jp 今回の構成 Web サイト検索結果の要約を行いたい場合、Vertex AI Search の「 Web サイト検索の検索要約 」という機能を使うことで Web サイト検索結果の要約が可能となります。 しかし、この機能を利用するためには Advanced website indexing というオプションを有効にする必要があり、この Advanced website indexing の有効には、その Web サイトのドメインに対する ドメイン所有権を確認 する必要があります。 つまり、自社の管理するドメインでサイトを運営していればいいが、Google Cloud 公式ドキュメント ( https://cloud.google.com/* ) などの外部 Web サイトでは通常このオプションを有効にできないため、Web サイト検索の検索要約機能を使うことができません。 そこで今回は、以下の構成で Google Cloud 公式ドキュメントを要約するアーキテクチャを実装してみたいと思います。 ユーザーの質問に対し類似する公式ドキュメントを上位 3 件抽出 1000 文字以下の Chank に分割 ユーザーの質問に対し類似する Chank を上位 3 件抽出 LLM で要約回答を生成 このアーキテクチャのポイントは、以下 2 点です。 LLM で要約を求める際の入力トークン制限に引っかからないように、最大 3,000 文字 (3 つの Chaink の最大文字数) の入力とした 分割した Chank に対しても再度ベクトル検索を行い、ユーザーの質問と類似しているテキストを部分的に抽出する 構成図 環境構築 API の有効化 対象プロジェクトで以下の API を有効化します。 discoveryengine.googleapis.com aiplatform.googleapis.com dataform.googleapis.com compute.googleapis.com Vertex AI Search データストア Web コンソールで [Vertex AI Search and Convasation] > [データストア] > [新しいデータストアを作成] から、以下のパラメータを設定してデータストアを作成します。 ソース [ウェブサイトの URL]を選択 データ [ウェブサイトの高度なインデックス登録]を "オフ" [インデックス登録する URL を指定] で cloud.google.com/* を入力 構成 [データストア名] に任意の名前を入力し "作成" を押下 作成後コンソール画面(データストア) アプリ Web コンソールで [Vertex AI Search and Convasation] > [アプリ] > [新しいアプリを作成] から、以下のパラメータを設定してアプリを作成します。 種類 [検索] を選択 構成 [Enterprise エディションの機能] を "オン" [アプリ名] は任意のアプリ名 [会社名] は任意の会社名 [アプリのロケーション] は "global" データ ${先ほど作成したデータストア} を選択して "作成" を押下 作成後コンソール画面(アプリ) 実行環境 当記事では、 Colab Enterprise の Notebook 上で Python を実行します。Colab Enterprise は、マネージドな Notebook のためインフラストラクチャを管理せず実装に注力できます。 Colab Enterprise の Notebook 作成方法は公式ドキュメントのクイックスタートをご参考下さい。 cloud.google.com 初期設定 ライブラリインストール Notebook が立ち上がり、ランタイムと接続できましたら以下のコードを実行してライブラリのインストールを行います。 # input:[1] !pip install google-cloud-discoveryengine langchain faiss-cpu ライブラリのインストールができたら、ランタイムを再起動してから以下を実行します。 # input:[2] import time from typing import List import vertexai from google.cloud import aiplatform from google.cloud.discoveryengine import SearchServiceClient, SearchRequest from google.protobuf.json_format import MessageToDict from pydantic import BaseModel from langchain.llms import VertexAI from langchain.embeddings import VertexAIEmbeddings from langchain.document_loaders import TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.document_loaders import WebBaseLoader from langchain.vectorstores import FAISS ユーティリティ関数 Vertex AI Embedding API for Text で使用するユーティリティ関数を定義します。 # input: [3] # レート制限 def rate_limit (max_per_minute): period = 60 / max_per_minute print ( "Waiting" ) while True : before = time.time() yield after = time.time() elapsed = after - before sleep_time = max ( 0 , period - elapsed) if sleep_time > 0 : print ( "." , end= "" ) time.sleep(sleep_time) class CustomVertexAIEmbeddings (VertexAIEmbeddings, BaseModel): requests_per_minute: int num_instances_per_batch: int # Overriding embed_documents method def embed_documents (self, texts: List[ str ]): limiter = rate_limit(self.requests_per_minute) results = [] docs = list (texts) while docs: # Working in batches because the API accepts maximum 5 # documents per request to get embeddings head, docs = ( docs[: self.num_instances_per_batch], docs[self.num_instances_per_batch :], ) chunk = self.client.get_embeddings(head) results.extend(chunk) next (limiter) return [r.values for r in results] モデルの初期化 モデルの初期化を行います。 # input: [4] # LLM model llm = VertexAI( model_name= "text-bison@001" , max_output_tokens= 1024 , temperature= 0.1 , top_p= 0.8 , top_k= 40 , verbose= True , ) # Embedding model EMBEDDING_QPM = 100 EMBEDDING_NUM_BATCH = 5 embeddings = CustomVertexAIEmbeddings( requests_per_minute=EMBEDDING_QPM, num_instances_per_batch=EMBEDDING_NUM_BATCH, ) Vertex AI Search 関数 プロジェクト ID と Vertex AI Search のデータストア ID を置き換えて以下を実行してください。 # input: [5] PROJECT_ID = ${プロジェクト ID} DATA_STORE_WEB = ${データストア ID} discov_client = SearchServiceClient() # Enterprise Search(Website)で各質問内容に関連する Web ページを検索 def search_questions_web (question: str ) -> dict : # 重要なキーワードを抽出 template = f "次の文から主要なキーワードやフレーズのみを抜き出してください: {question}" keyword = llm(template) serving_config = discov_client.serving_config_path( project=PROJECT_ID, location= 'global' , data_store=DATA_STORE_WEB, serving_config= 'default_config' ) # 検索の実行 results = discov_client.search( SearchRequest( serving_config=serving_config, query=keyword, page_size= 3 ) ) documents = [] # Web 検索の結果が 0 件だった場合の処理 if not results.results: print (f "0 search results" ) return else : for r in results.results: document_info = {} r_dct = MessageToDict(r._pb) document_info[ 'title' ] = r_dct[ 'document' ][ 'derivedStructData' ][ 'title' ] document_info[ 'link' ] = r_dct[ 'document' ][ 'derivedStructData' ][ 'link' ] documents.append(document_info) responses = { "question" : question, "keyword" : keyword, "answer" : documents } return responses 今回は、Vertex AI Search のクエリに、ユーザーの質問 (question) を直接入力させず、重要なキーワードのみを検索対象としました。 「重要なキーワードのみを検索対象とする」とはどのようなことかというと、以下に例と実行結果を記載します。 [原文] 「 BigQuery で行レベルセキュリティを実装する方法を教えてください 」の検索結果は以下のとおりです。 よくある質問 | Datastream | Google Cloud 料金 | BigQuery: クラウド データ ウェアハウス | Google Cloud リソースへのラベルの追加 | BigQuery | Google Cloud [重要なキーワードのみ] 「 BigQuery, 行レベルセキュリティ, 実装 」の検索結果は以下のとおりです。 BigQuery の行レベルのセキュリティの概要 | Google Cloud BigQuery の行レベルのセキュリティにより、データへのアクセスの ... BigQuery の行レベルのセキュリティに関するベスト プラクティス ... 重要なキーワードのみで検索した方が欲しい検索結果を得られているため、今回はこちらの方法で実装します。 参考: Python Client for Discovery Engine API テキスト分割関数 # input: [6] def text_split_func (search_res: dict ) -> list : text_li = [] for answer in search_res[ "answer" ]: url = answer[ "link" ] # web ページからテキストを取得 loader = WebBaseLoader(url) documents = loader.load() # テキスト分割してリストに格納 text_splitter = RecursiveCharacterTextSplitter(chunk_size= 1000 , chunk_overlap= 200 ) text_li.extend(text_splitter.split_documents(documents)) return text_li RecursiveCharacterTextSplitter を用いて、Vertex AI Search の検索結果で得られた Google Cloud 公式ドキュメントの本文を、1,000 文字 (オーバーラップ 200 文字) ずつの Chank (テキスト) に分割を行います。 RAG を実行する関数 # input: [7] def rag (question: str , text_li: list ) -> list : # 分割したテキストをエンベディングしてベクトルデータベースに保存 db = FAISS.from_documents(text_li, VertexAIEmbeddings()) # question に対し類似したテキストをベクター検索して上位 3 つのテキストを取得 docs = db.similarity_search(question, 3 ) # 上位 3 つのテキストを結合 facts = " \n " .join([doc.page_content for doc in docs]) # 次のquestionに対して、factsに基づいてanswerを生成してください。 final_prompt = f """ 次の質問については、事実に基づいて回答を作成してください。 質問: {question} 事実: {facts} 回答: """ print ( "LLM Output:" ) print (llm(final_prompt)) print ( "Reference URL:" ) print (search_res[ 'answer' ]) ベクトルベータベースには、 FAISS を用いて、LangChain で操作します。 from_documents メソッドでテキスト分割したリストを、Vertex AI Embedding API を用いてエンべディングしベクトルデータベースに格納しています。 また、similarity_search メソッドでベクトル検索を実行して、ユーザーの質問と類似しているテキストを抽出します。 最後に、上記で抽出したテキストをもとに LLM に回答を生成させることで、RAG を実現しています。 参考: langchain.vectorstores.faiss.FAISS 実行 それでは、以下を実行して動作確認してみます。 # input: [8] question = "BigQuery で行レベルセキュリティを実装する方法を教えてください" search_res = search_questions_web(question) text_li = text_split_func(search_res) rag(question, text_li) # output: [8] LLM Output: BigQuery で行レベルセキュリティを実装するには、次の手順に従います。 1 . ターゲット BigQuery テーブルに行レベルのアクセス ポリシーを作成します。 2 . ポリシーで、ユーザーまたはグループを許可リストに追加します。 3 . 許可リストに含まれていないユーザーまたはグループは、テーブルへのアクセスを拒否されます。 Reference URL: [ { ' title ' : ' BigQuery の行レベルのセキュリティの概要 | Google Cloud ' , ' link ' : ' https://cloud.google.com/bigquery/docs/row-level-security-intro?hl=ja ' } , { ' title ' : ' BigQuery の行レベルのセキュリティにより、データへのアクセスの ... ' , ' link ' : ' https://cloud.google.com/blog/ja/products/data-analytics/bigquery-provides-tighter-controls-over-data-access ' } , { ' title ' : ' BigQuery の行レベルのセキュリティに関するベスト プラクティス ... ' , ' link ' : ' https://cloud.google.com/bigquery/docs/best-practices-row-level-security?hl=ja ' } ] LLM Output には、最終的な LLM の要約が含まれております。 Reference URL には、Vertex AI Search で取得した検索結果 (上位 3 件) が取得されています。 別の質問でもいくつか実行してみます。 # input: [9] question = "Cloud Run と Cloud Functions の使い分けについて教えてください。" search_res = search_questions_web(question) text_li = text_split_func(search_res) rag(question, text_li) # output: [9] LLM Output: Cloud Functions は、プラットフォームの接続に適しています。Cloud Run は、サービスの実行に適しています。 Reference URL: [ { ' title ' : ' Cloud run vs cloud functions for serverless | Google Cloud Blog ' , ' link ' : ' https://cloud.google.com/blog/products/serverless/cloud-run-vs-cloud-functions-for-serverless ' } , { ' title ' : ' Cloud Functions と Cloud Run: それぞれの使いどころ | Google ... ' , ' link ' : ' https://cloud.google.com/blog/ja/products/serverless/cloud-run-vs-cloud-functions-for-serverless ' } , { ' title ' : ' Cloud Run: サーバーレス コンテナの話 | Google Cloud 公式ブログ ' , ' link ' : ' https://cloud.google.com/blog/ja/topics/developers-practitioners/cloud-run-story-serverless-containers ' } ] # input: [10] question = """ BigQuery で料金を制限したいです。いい方法を教えてください。 """ search_res = search_questions_web(question) text_li = text_split_func(search_res) rag(question, text_li) # output: [10] LLM Output: BigQuery の料金は、クエリの実行時間、使用したデータ量、保存したデータ量に基づいて計算されます。 料金を制限するには、次の方法があります。 * クエリをより効率的に実行する。 * 使用したデータ量を減らす。 * 保存したデータ量を減らす。 クエリをより効率的に実行するには、次の方法があります。 * クエリを最適化する。 * クエリを分割する。 * クエリを並列実行する。 使用したデータ量を減らすには、次の方法があります。 * 必要なデータのみをクエリする。 * クエリ結果をキャッシュする。 * クエリ結果を圧縮する。 保存したデータ量を減らすには、次の方法があります。 * 不要なデータを削除する。 * データを圧縮する。 * データをアーカイブする。 これらの方法を組み合わせることで、BigQuery の料金を大幅に削減することができます。 Reference URL: [ { ' title ' : ' コストの見積りと管理 | BigQuery | Google Cloud ' , ' link ' : ' https://cloud.google.com/bigquery/docs/best-practices-costs?hl=ja ' } , { ' title ' : ' 料金 | BigQuery: クラウド データ ウェアハウス | Google Cloud ' , ' link ' : ' https://cloud.google.com/bigquery/pricing?hl=ja ' } , { ' title ' : ' 割り当てと上限 | BigQuery | Google Cloud ' , ' link ' : ' https://cloud.google.com/bigquery/quotas?hl=ja ' } ] Vertex AI Search の単体の機能では外部サイトの要約は実装できませんが、このように LLM と組み合わせて RAG を構築することで外部サイトの要約を実装することができました。また、LangChain を用いることで、実装工数も大幅に短縮できますね。 又吉 佑樹 (記事一覧) クラウドソリューション部 はいさい、沖縄出身のクラウドエンジニア! セールスからエンジニアへ転身。Google Cloud 全 11 資格保有。Google Cloud Champion Innovator (AI/ML)。Google Cloud Partner Top Engineer 2024。Google Cloud 公式ユーザー会 Jagu'e'r でエバンジェリストとして活動中。好きな分野は AI/ML。 Follow @matayuuuu
アバター
G-gen の杉村です。Google Cloud のメタデータ管理ツールである Dataplex Universal Catalog (旧称 Dataplex Catalog)を解説します。 概要 Dataplex Universal Catalog とは 過去に存在した Data Catalog 改名 データカタログとメタデータ データカタログとは メタデータとは ビジネスメタデータとテクニカルメタデータ データ検索機能 検索方法 自然言語検索(セマンティック検索) 検索結果の表示 クエリの構文 メタデータの取り込み メタデータの自動収集 テクニカルメタデータの自動収集 サードパーティのメタデータ Dataplex Universal Catalog のリソース エントリ、エントリグループ、エントリタイプ アスペクト、アスペクトタイプ 必須アスペクト データの自動登録(Discovery) Data products 料金 アクセス制御(IAM) IAM の基本 メタデータの検索 カタログの管理 Dataplex による権限管理 監査ログ 概要 Dataplex Universal Catalog とは Dataplex Universal Catalog (旧称 Dataplex Catalog)とは Google Cloud のメタデータ管理サービスです。フルマネージドであり、インフラの管理は全く必要ありません。 参考 : Dataplex Universal Catalog の概要 Dataplex Universal Catalog では、BigQuery のテーブルや Cloud Storage バケット内の非構造化データなど、Google Cloud 上のデータにメタデータを付与して データカタログ 化し、ユーザーが検索できるようになります。BigQuery や Spanner、Bigtable、Dataproc、Pub/Sub など、多くの Google Cloud サービスのデータは何もしなくても 自動的にカタログに登録される ほか、Cloud SQL 上のデータも、明示的に有効化することで登録できます。 さらに、Google Cloud リソース以外にも、オンプレミスのデータベースや Snowflake、Databricks など、サードパーティのメタデータも、カスタムコネクタを開発することで管理対象にできます。 参考 : Dataplex Universal Catalog のデータカタログ管理について - サポート対象のソース なお Dataplex Universal Catalog は、Google Cloud のデータマネジメントサービスである Dataplex の一部です。Dataplex についての詳細は、以下の記事をご参照ください。 blog.g-gen.co.jp 過去に存在した Data Catalog 過去には、Google Cloud に Data Catalog というプロダクトが存在していました。Data Catalog はサービス終了が発表されており、2026年1月30日にシャットダウン予定です。 Data Catalog の利用者は、Dataplex Universal Catalog に移行する必要があります。BigQuery などのリソースのメタデータは自動的に Dataplex Universal Catalog に登録されますが、その他の Data Catalog リソースは、以下のドキュメントを参考に、移行を行う必要があります。 参考 : Data Catalog から Dataplex Universal Catalog に移行 Dataplex Universal Catalog と Data Catalog の機能は非常に類似しています。詳細な相違点については、以下のドキュメントを参照してください。 参考 : Dataplex Universal Catalog と Data Catalog 改名 Dataplex Universal Catalog は、かつて Dataplex Catalog という名称でした。2025年4月に米国ラスベガスで開催された Google Cloud Next '25 において、Dataplex Catalog という名称から BigQuery universal catalog への改名が発表されたあと、さらに現在の名称である Dataplex Universal Catalog に変更されました。 現在では、各種ドキュメントで Dataplex Universal Catalog という名称が使用されています。 参考 : BigQueryの新発表を解説(Google Cloud Next '25速報) - G-gen Tech Blog - Dataplex Catalog が BigQuery universal catalog に改名 データカタログとメタデータ データカタログとは データカタログ とは、メタデータをカタログ化し、利用者が必要なデータを探し出しやすくするためのツールです。データカタログは Google Cloud に特有の概念ではなく、メタデータを管理するためのツール全般を指す一般的な用語です。当記事で紹介する Dataplex Universal Catalog は、Google Cloud がフルマネージドで提供するデータカタログサービスであるとお考えください。 データカタログが無いと、従業員はデータが必要になったときに、BigQuery や Cloud Storage の専門知識を使って一つ一つの Google Cloud プロジェクトを開いてテーブル名やファイル名を確認し、設計書を漁ったり、システム管理者に質問して回る必要があります。 データカタログでメタデータを集約管理することで、このような無駄なコミュニケーションを節約し、組織(企業や官公庁)の従業員は、必要なデータを探し出しやすくなります。 メタデータとは そもそも メタデータ とは何でしょうか。以下のようなテキストデータがあったとします。 [Data] 吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当が...... このデータに、メタデータを付与すると以下のようになります。 [Metadata] Title: 吾輩は猫である Author: 夏目漱石 Page count: 380 [Data] 吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当が...... ここでは、小説の本文を データ として、タイトルや著者名、ページ数などを メタデータ としました。一般的にメタデータは「データ本体を説明するためのデータ」といえます。 データ分析基盤を構築しても、メタデータなしには、利用者が必要なデータを探し出すことは容易ではありません。メタデータがあるからこそ、データは活用されます。 現実世界の例でいうと、他に以下のようなものが挙げられます。 名前 データ メタデータ PC 上のファイル ファイルの中身 ファイル名、サイズ、作成日時、更新日時、アクセス権限 データベースのテーブル レコード テーブル名、列名、テーブルや列に関する説明 ビジネスメタデータとテクニカルメタデータ メタデータは、 ビジネスメタデータ と テクニカルメタデータ に分類されることがあります。 ビジネスメタデータとは、メタデータのうち、業務に関連するものを指します。そのデータの所有者、部門、業務上の意味、カラムの説明、利用上の注意などです。 テクニカルメタデータとは、メタデータのうち、より技術的な意味合いのものを指します。スキーマ定義、アクセス権限、パーティショニングやクラスタリングなどのテーブル属性などです。 なお、ここまで説明した「メタデータ」「テクニカルメタデータ」「ビジネスメタデータ」は、書籍や製品などによって独自の呼び方をしていることがありますのでご注意ください。 データ検索機能 検索方法 データに対する検索は、Google Cloud コンソール、あるいは API 経由で行うことができます。 Google Cloud コンソールは、Dataplex の画面と統合されています。Dataplex 画面で「検索」を選択するか、Web コンソール上部の検索ボックスに Catalog search と入力して表示されるサジェストをクリックすることでも、検索画面に遷移できます。 検索画面 検索可能な範囲は、検索を実行者の Google アカウントが持つ IAM 権限に応じて決まります。データそのものにアクセス権がなくても、メタデータへのアクセス権があれば検索結果として表示されます。また、複数のプロジェクトを横断した検索が可能です。ただし、検索結果に表示されるのは、同じ Google Cloud 組織内のリソースだけです。 権限があれば、BigQuery、Pub/Sub、Cloud Storage、Spanner など、Dataplex Universal Catalog でカタログ化された全てのデータが対象となって検索されます。テーブル名、列名、Description など広い属性が検索対象になるため、ある程度あいまいな語でもデータに辿り着くことが可能です。 また検索対象のサービスや、リソースのタイプ、Dataplex のレイク、ゾーン、Google Cloud プロジェクトなどで、検索対象をフィルタすることが可能です。 参考 : Dataplex Universal Catalog でリソースを検索する 自然言語検索(セマンティック検索) Dataplex Universal Catalog では、キーワード検索ができることに加えて、自然言語での検索も可能です。この機能では AI が検索をサポートし、自然言語(人間が普段使う言葉)で検索を行うことができます。 自然言語で入力した検索語句は意味として解釈され、セマンティック検索(意味論検索)が行われます。 検索結果の表示 以下のスクリーンショットは、検索結果に表示された BigQuery テーブルの詳細画面の例です。 BigQuery テーブルの検索結果 スクリーンショットでは「スキーマ」タブを表示しています。テーブルの所属データセット、プロジェクトや、スキーマ、そのスキーマに設定された説明(Description)などが表示されます。BigQuery のコンソール画面(BigQuery Studio)等でテーブルや列に設定した説明(Description)は、自動的に反映されて表示されます。 「詳細」タブには、Dataplex で設定したアスペクト(後述)なども表示されます。 その他のタブで、Dataplex によって作成されたデータリネージや、データ品質、データプロファイリングの結果も閲覧できます。 クエリの構文 Dataplex Universal Catalog では、単純に語を入れて検索することもできますし、記号を使った様々な構文も利用できます。 例えば name:foo とすると、エントリの名称に foo を含むエンティティを検索します。 : は部分一致ですが、 = だと完全一致になります。他にも column label location updatetime など、検索対象とする属性を指定することが可能です。 以下は、例です。 検索クエリ 意味 location=asia-northeast1 name:my-entry 東京リージョンにある、名称に my-entry を含むエントリ updatetime>=2025-04-04T06:00:00 2025-04-04T06:00:00 (GMT) 以降に更新されたエントリ (タイムゾーンは GMT のみサポート。+9時間で日本時間) 詳細は以下の記事も参考にしてください。 参考 : Dataplex Catalog の検索構文 メタデータの取り込み メタデータの自動収集 Dataplex Universal Catalog は、以下の Google Cloud プロダクトのメタデータを 自動的に取り込み 、検索可能にします。カタログ化されたメタデータは、すぐに Dataplex Universal Catalog の UI や API 経由で検索可能です。 プロダクト名 対象リソース BigQuery ・データセット ・テーブル ・BigQuery ML モデル ・ルーチン(ストアドプロシージャ、ユーザー定義関数、テーブル関数) ・接続 (Connections) ・リンクされたデータセット AlloyDB for PostgreSQL ・クラスタ、インスタンス(デフォルトで有効化) ・データベース、スキーマ、テーブル、ビュー(要有効化) Analytics Hub ・エクスチェンジ ・リスティング Bigtable ・インスタンス ・クラスタ ・テーブル Dataform ・リポジトリ ・コードアセット Cloud SQL ・インスタンス(デフォルトで有効化) ・データベース、テーブル、ビュー(要有効化) Pub/Sub ・トピック Dataproc Metastore ・サービス ・データベース ・テーブル Spanner ・インスタンス ・データベース ・テーブル ・ビュー Vertex AI ・モデル ・データセット ・特徴グループ ・特徴ビュー ・オンラインストアインスタンス 参考 : サポート対象のソース テクニカルメタデータの自動収集 前述の対応プロダクトのリソースのテクニカルメタデータは、自動的に収集されます。 BigQuery テーブルのテーブル名、カラム名、カラムの型や説明(description)など、リソースに付与されたテクニカルメタデータは、ユーザーが何もしなくても**自動的に収集され、すぐに検索可能です。 サードパーティのメタデータ Dataplex Universal Catalog では、前述の Google Cloud サービス以外にも、 カスタムエントリ (後述)を作成することで、オンプレミスや他クラウドのデータのメタデータを登録することが可能です。 また、サードパーティのデータソースから Dataplex にメタデータを継続的、自動的にインポートするには、 マネージド接続 (Managed connectivity)機能を使います。これには独自のカスタムコネクタの開発が必要です。カスタムコネクタは、PySpark 等を用いて、Dataproc Serverless で実行できる Artifact Registry イメージとして作成する必要があります。 参考 : マネージド接続の概要 参考 : メタデータのインポート用にカスタム コネクタを開発する マネージド接続用のカスタムコネクタとして、コミュニティによって開発されたコネクタを利用することもできます。これらのコネクタは Google によって公式にサポートされるものではありませんが、PostgreSQL、SQL Server、Oracle、Snowflake などに向けたコネクタが公開されています。 参考 : Managed connectivity overview - Community-contributed custom connectors Dataplex Universal Catalog のリソース エントリ、エントリグループ、エントリタイプ エントリ とは、BigQuery データセットやテーブル、Pub/Sub トピックなど、1つ1つのリソースを指します。メタデータは、エントリ内のアスペクト(後述)に記述されます。 エントリグループ は、エントリをグルーピングする管理単位です。 @bigquery や @pubsub などの Google Cloud リソースのエントリグループが、Dataplex Universal Catalog によって自動的に作成されます。 エントリタイプ は、エントリのテンプレート(雛形)です。Dataplex Universal Catalog によって定義済みのエントリタイプはシステムエントリタイプといい、例として BigQuery テーブルや Pub/Sub トピックなど、自動で登録されるエントリには、システムエントリタイプが適用されます。 参考 : Dataplex Universal Catalog のデータカタログ管理について - Dataplex Universal Catalog のメタデータ管理の仕組み ユーザー側で、カスタムエントリやカスタムエントリグループ、カスタムエントリタイプを作成することもできます。これにより、Dataplex Universal Catalog が自動的に取り込まないリソースのメタデータや、Google Cloud 外のデータのメタデータも、Dataplex Universal Catalog に登録することができます。 参考 : エントリを管理してカスタムソースを取り込む アスペクト、アスペクトタイプ エントリ内には アスペクト と呼ばれるフィールドがあり、メタデータはここに記述されます。 アスペクトには、キー(名前)とバリュー(値)を登録できます。これにより、ビジネスメタデータや、追加のテクニカルメタデータを記述できます。 アスペクトタイプ とは、複数のアスペクトのプリセットです。例えば、あらかじめ Data Governance というアスペクトタイプを定義しておき、その中にはデータの管理者や所有者の連絡先、機密レベル、保持期限などのエントリの名前を登録しておきます。アスペクトタイプは再利用できるので、統一したフォーマットでエントリにメタデータを登録することができます。 以下は、Data Governance というアスペクトタイプを BigQuery データセットに適用して、値を入力した例です。 アスペクト BigQuery の場合、テーブル全体にアスペクトを付与することもできますし、カラムに付与することもできます。 ユーザーで定義したアスペクトタイプは、組織内で公開できます。これにより、メタデータのフォーマットを統一できます。運用上は、組織でデータガバナンスルールを定義し、どのようなメタデータを必須として付与すべきかを定義することが望ましいといえます。 参考 : アスペクトを管理してメタデータを拡充する 必須アスペクト 例えば BigQuery テーブルのエントリには、Dataplex Universal Catalog によって予め「BigQuery Table」と「Storage」という 必須アスペクト が付与され、値が自動的に登録されます。 必須アスペクト データの自動登録(Discovery) Dataplex Discovery は、Dataplex にアセットとして登録されているデータレイク内のデータから、メタデータを自動でスキャンして抽出し、Dataproc Metastore、BigQuery、Dataplex Universal Catalog に登録して利用可能にする機能です。 Dataplex の機能の一部として提供されているので、詳細は以下の記事をご参照ください。 参考 : Dataplexを徹底解説! - Dataplex Discovery Data products Data products (データ製品)は、データの提供者が、組織内の利用者向けにデータアセット(BigQueryデータセットやテーブル)をパッケージして、キュレーションするための機能です。権限管理の運用もシンプルにすることができます。 1つの Data product は論理的なオブジェクトであり、中に BigQuery データセット、テーブル、ビューといったアセットを含むことができます。Data product には アクセスグループ として Google グループを設定でき、データへのアクセス管理を行うことができます。 参考 : About data products 料金 Dataplex Universal Catalog の料金として、メタデータストレージの料金が発生します。2025年11月現在、メタデータストレージ料金の単価は、$2/GiB/月です。 参考 : Dataplex Universal Catalog pricing また、Dataplex のデータリネージ機能の保存データも、このストレージ料金として加算されます。データリネージについては、以下を参照してください。 参考 : Dataplexを徹底解説! - G-gen Tech Blog - データリネージ アクセス制御(IAM) IAM の基本 メタデータの検索、エントリへのタグ付け、データリネージの閲覧などは、全て IAM (Identity and Access Management)によってアクセス制御されます。 「メタデータは検索可能で、リソース名称やメタデータまでは表示させて良いが、データそのものにはアクセスさせない」といった権限管理も可能です。 Google Cloud の IAM では、Amazon Web Services(AWS)と異なり、 リソースに対して 、誰が、何をできるかを設定します(IAM ポリシーをリソースが持ちます)。Google Cloud の IAM の基本は、以下の記事をご参照ください。 blog.g-gen.co.jp メタデータの検索 Dataplex Universal Catalog を使って検索を行う Google アカウントは、検索を実行するプロジェクトに対して、Dataplex Catalog 閲覧者(roles/dataplex.catalogViewer)ロール等を持っている必要があります。 ただし、検索結果に出てくるリソースは、検索を実行したアカウントがメタデータへのアクセス権限を持っているリソースだけです。 逆に、メタデータへのアクセス権限を持っていれば、検索を実行したプロジェクト以外のプロジェクトのリソースも、検索結果に表示されます(ただし、同じ Google Cloud 組織内のリソースのみ)。つまり、Dataplex Universal Catalog では、複数のプロジェクトを横断した検索が可能です。 参考 : Dataplex Universal Catalog でリソースを検索する - 必要なロール カタログの管理 Dataplex Universal Catalog のリソース(エントリやアスペクト等)の管理を行うには、操作者の Google アカウントがプロジェクト等に対して管理に関するロールを持っている必要があります。 プロジェクトレベルでオーナー( roles/owner )や編集者( roles/editor )を持っていれば、Dataplex Universal Catalog リソースの管理が可能です。また、Dataplex Catalog 管理者( roles/dataplex.catalogAdmin )、Dataplex Catalog 編集者( roles/dataplex.catalogEditor )などの事前定義ロールが用意されています。 参考 : Dataplex IAM ロール Dataplex による権限管理 Dataplex による権限管理と、カタログの検索権限に関するイメージは、以下の記事をご参照ください。 参考 : Dataplexによる権限管理の仕組みを徹底解説 - G-gen Tech Blog - リソースの検索(Dataplex Univeresal Catalog) 監査ログ Dataplex Universal Catalog では、 Cloud Audit Logs により、監査ログ(誰が、いつ、どこで、何をしたか)が Cloud Logging に記録されます。 デフォルトでは、カスタムアスペクトの作成や編集といった、管理アクティビティログが記録されます。 参考 : Dataplex 監査ロギング Cloud Audit Logs についての詳細は以下の記事をご参照ください。 blog.g-gen.co.jp 杉村 勇馬 (記事一覧) 執行役員 CTO 元警察官という経歴を持つ IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 認定資格および Google Cloud 認定資格はすべて取得。X(旧 Twitter)では Google Cloud や Google Workspace のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の神谷です。本記事では、Google Cloud のスケーラブルでサーバレスなデータ管理ツールである Dataplex を徹底解説します。 Dataplex の概要 Dataplex とは Dataplex Universal Catalog メリット データメッシュとは 構成とオブジェクト アクセス制御機能 認証・認可(IAM) IAM の基本的な理解 アセットと IAM プロジェクトをまたぐ権限管理 権限管理の詳細 VPC Service Controls データの品質チェック Dataplex におけるデータ品質の検証 自動データ品質 自動データ品質とは データ品質タスク データプロファイリング データリネージ データリネージとは 有効化 追跡可能な情報 保持期間 Dataplex Discovery Dataplex Discovery とは Discovery Action ロギングとモニタリング ロギング モニタリング 料金 その他の機能 メタデータのインポート(マネージド接続) ビジネス用語集 Gemini in Dataplex(分析情報) Dataplex の概要 Dataplex とは Dataplex は Google Cloud(旧称 GCP)で提供されている、 分散されたデータの統合・管理を自動化するためのサービス です。以下のことが実現できます。 組織内の複数の Google Cloud プロジェクトにまたがるデータを統合して データメッシュ (後述)を構築する データの 権限管理を一元化 する メタデータを付けることで データをカタログ化 し、検索しやすくする データの品質やライフサイクルを管理する Dataplex はフルマネージドサービスであり、インフラの管理は一切必要ありません。また、使用されたリソース量や保存データ量に応じた従量課金であり、一般的には安価に利用することができます。 参考 : Dataplex の概要 Dataplex Universal Catalog Dataplex には、 Dataplex Universal Catalog (旧称 Dataplex Catalog)というサービスも内包されています。Dataplex Universal Catalog は、BigQuery や Cloud Storage など、Google Cloud 環境にあるデータのメタデータを管理し、カタログ化するフルマネージドサービスです。 当記事では Dataplex Universal Catalog の詳細には触れません。詳細は、以下の記事を参照してください。 blog.g-gen.co.jp メリット Dataplex を使うことにより、組織内の散らばったデータを一箇所に集約せずに、そのままの状態で統合管理できます。データの移動やコピーは必要ありません。 具体的には、Cloud Storage や BigQuery に入っているデータがさまざまなプロジェクト、バケット、データセットに分散していても、統合管理をすることができるようになります。 「統合管理」にはデータの検索性のほか、データ品質の自動的なチェックやセキュリティ設定も含まれています。 Dataplex が管理対象にできるデータは、BigQuery、Cloud Storage、Dataproc Metastore などの Google Cloud サービスのほか、Apache Spark や Presto との統合も可能です。 データメッシュとは Dataplex は「ドメイン」を中心とした「 データメッシュ 」を提供するプロダクトです。 組織内で、各部署やシステムごとに個別にデータを持ってしまい、かつどこにデータがあるか分からないためにデータの活用ができない状態は データのサイロ化 と呼ばれ、組織のデータの課題として有名です。これを回避するために、従来は単一のデータ基盤にデータを収集することでこれを解決しようとしてきました。 しかしこのアプローチは、データの移動(コピー)が必要になります。この実現には複雑なデータパイプラインの構築が必要なことに加え、コンピュートやストレージリソース、そしてそれらを管理する人のリソースも必要となります。 このような中央集権的な方式とは一線を画する解決策が データメッシュ です。論理的な管理レイヤで仮想的にデータをグルーピングすることで、データを分散配置したままで統合管理を可能にするアプローチです。これにより、データのコピーは不要でありながら、データのサイロ化を回避して、また認証・認可やデータ品質のモニタリングなどを実現できます。 Dataplex で実現するデータメッシュを理解するには、併せて以下の用語も把握してください。 用語 説明 ドメイン ・特定の ビジネス分野や領域 を表す概念 ・企業内で共通の言語やルールで情報を管理するための基盤となる ・例えば「セールス」「小売」「財務経理」など また、以下は、データメッシュにおける登場人物に関する用語です。 用語 説明 データプロダクトオーナー データプロデューサーとも呼ばれる。データを生み出す人またはチームであり、ビジネスやデータのドメインに 最も詳しい 。売上や受発注データに詳しい販売部門、EC サイトのアクセスログや顧客情報に詳しいマーケティング部門等にそれぞれデータプロダクトオーナーが存在する データコンシューマー データアナリストやデータサイエンティスト、あるいはビジネス部門の従業員といった データを消費 (利用) する人またはチーム データスチュワード 組織全体のデータ基盤を管理 する人またはチーム。データの管理人であり、データ品質やガバナンス、権限管理、機密情報のマスキングなどを司る これらの登場人物が、ドメインごとにデータを生成・管理し、利用可能にする組織アーキテクチャがデータメッシュです。Dataplex はそのデータメッシュを実現するためのプロダクトであると言えます。 参考 : Build a modern, distributed Data Mesh with Google Cloud 参考 : データメッシュ内のアーキテクチャと機能 データメッシュの考え方 構成とオブジェクト Dataplex の主要オブジェクトは以下のとおりです。前述の用語は組織や概念に関するものでしたが、ここからは実際に Dataplex を触るとシステム的に登場します。 参考 : 用語 名称 説明 レイク データの論理的なまとまり。ドメインごとにレイクを持つことが想定されている ゾーン レイクの中に存在するサブドメイン。データレイク、DWH、データマートのような段階を表現したり、給与や人事情報といった機密性の度合いで分類する。ゾーンには以下の2タイプが存在する。  ・Raw zone : 無加工・未チェックの生データ  ・Curated zone : データクレンジング済みでいつでも分析できるデータ。Parquet や Avro などの構造化データ、BigQuery テーブルなどのアセットを含む アセット 実データであり、実体は Cloud Storage バケットや BigQuery データセット。実データが異なる Google Cloud プロジェクトに所属していても、単一ゾーンに所属することができる エンティティ 非構造化・半構造化・構造化データに対するメタデータ 上記のオブジェクトは、以下のように 階層構造 を構成します。 Dataplex のアセット管理方式 従来だとデータは、Google Cloud プロジェクトでグルーピングし、BigQuery のデータセット名や Cloud Storage のバケット名などの命名規則で管理していました。 しかし Dataplex では Google Cloud プロジェクトが何であろうと、リソース名が何であろうと、 レイクで階層化することで統合管理 できます。 レイクは複数のゾーンを含めることができますが、 ゾーンは1つのレイクにしか所属できない ため、ゾーンをドメインに対するタグのように扱うことはできません。また、ゾーンの下位リソースである アセットも、1つのゾーンにしか所属できません 。 アクセス制御機能 認証・認可(IAM) IAM の基本的な理解 当項目の内容を理解するには、以下の記事をお読みになり、Google Cloud の IAM の基礎的な理解をしていただくことが前提となります。Amazon Web Services(AWS)の IAM 等とは概念が異なりますため、以下の記事をぜひご参照ください。 blog.g-gen.co.jp アセットと IAM Dataplex では、Cloud Storage や BigQuery といった Dataplex アセットの上に 仮想化階層 を追加し、そこに対してユーザやサービスアカウントの IAM 権限を付与することで権限を管理します。 Dataplex でデータへのアクセス権限を管理するメリットとして、以下のようなものが挙げられます。 様々なプロジェクトに分散したデータの 権限管理を集約 ユーザーにとって 意味のある単位 (レイク、ゾーン等)で 権限を付与 できる レイクの IAM ポリシーはゾーンに 伝播 (継承)され、さらにはゾーンが保持するアセットに伝播されます。Dataplex 経由の IAM ポリシーは、リソースにもともとついている 通常の IAM ポリシーとは別 で管理されます。プロジェクトレベルでロールを管理しなくて良くなり、リソースレベルの IAM 管理になるため、 最小権限の原則 が守りつつ、管理工数を削減することができます。 参考 : IAM を使用したアクセス制御 なお、ある Google アカウントが例えば BigQuery データセットに IAM ロールを持っており、同時に Dataplex でも権限を持っている場合、 どちらかで権限が付与されていればアクセスが可能です 。つまり、通常の IAM と Dataplex のアクセス制御は、OR で評価されます。運用上は、どちらかに権限管理を寄せるのが理想的です。 プロジェクトをまたぐ権限管理 管理対象のアセットが Dataplex とは別の Google Cloud プロジェクトに存在している場合は、Dataplex のプロジェクトの「Dataplex サービスアカウント(サービスエージェント)」に対して、アセットが存在するプロジェクトの IAM 権限(Cloud Storage 管理者ロールや BigQuery 管理者ロール)を付与する必要があります。 Dataplex サービスアカウントは service-${プロジェクト番号}@gcp-sa-dataplex.iam.gserviceaccount.com という名称で、Dataplex のプロジェクトに存在しています。 このように、Dataplex サービスアカウントに IAM 権限を委任することで、Dataplex は仮想的な権限レイヤを実現できるのです。 参考 : レイク内のデータアセットを管理する - ロールの付与 権限管理の詳細 Dataplex による権限管理の仕組みは、以下の記事でサンプルアーキテクチャを用いて解説しています。 権限管理手法や、運用のイメージをつけたい場合にご参照ください。 blog.g-gen.co.jp VPC Service Controls VPC Service Controls を使って Dataplex に追加のアクセス制御層を作り、データ流出のリスクを軽減することができます。 VPC Service Controls は Google Cloud API へのアクセス制御を行うための独立した Google Cloud サービスです。以下の記事をご参照ください。 blog.g-gen.co.jp また以下の公式ドキュメントもご参照ください。 参考 : Dataplex で使用する VPC Service Control データの品質チェック Dataplex におけるデータ品質の検証 Dataplex には データの品質チェック機能 があり、以下の3種類の機能が用意されています。 自動データ品質 データ品質タスク データプロファイリング 自動データ品質 自動データ品質とは 自動データ品質 機能は、事前に定義したデータ品質に基づいてデータの品質をチェックし、品質要件を満たしていない場合にアラートを発報できる機能です。 ルールは以下の方法で定義できます。 Dataplex からサジェストされる推奨事項を利用 事前定義ルール カスタム SQL ルール 自動データ品質チェックをすることで、品質定義を自動化・簡素化することができ、また品質を満たしていない場合の初動対応も迅速に行うことができるようになります。 参考 : 自動データ品質の概要 データ品質タスク Dataplex データ品質タスク は、ユーザが独自にカスタマイズ可能なデータ品質チェックの機能です。BigQuery と Cloud Storage に対して実行できます。 データパイプラインに組み込んでデータ検証に用いたり、あるいは定期的なデータ品質チェックに用いることができます。 ルールは YAML で定義します。定義したルールは SQL に変換され、BigQuery 上で処理されるため、インフラ設定は不要です。また、スケジュールに基づいてチェックを実行できるほか、API 経由で呼び出し可能なため、既存のデータパイプラインに組み込むこともできます。 バックエンドではオープンソースの データ品質エンジン である CloudDQ が使われています。CloudDQ は BigQuery 用のデータ品質検証コマンドラインツールであり、クラウドネイティブ、宣言型、スケーラブルといった特性を持ちます。 参考 : データ品質タスクの概要 データプロファイリング データプロファイリング は、BigQuery テーブルの列の統計的特性をレポーティングする機能です。 テーブルの各列の「値の分布」「null の数」「ユニークな値の数(概算)」「最大値・最小値・平均値・標準偏差・近似中央値」などを出すことができます。 スキャンの対象テーブルを指定し、スケジュール実行することもできますし、結果を別の BigQuery テーブルにエクスポートすることもできます。 参考 : データ プロファイリングについて データリネージ データリネージとは Dataplex の データリネージ 機能とは、ある BigQuery テーブルのデータがどこから来て、どこに渡されているかなど、データの出自を特定できる機能です。 「リネージ(lineage)」とは、血統、系統などを指す英単語です。データの家系図のようなものを連想させます。 有効化すると、テーブルごとにグラフが生成され、BigQuery のコンソール画面(BigQuery Studio)からデータの流れをグラフィカルに確認することができます。 INSERT SELECT や CREATE TABLE AS SELECT などのジョブが追跡され、以下の画像のようなリネージグラフとして表示可能になります。 参考 : データリネージについて 参考 : BigQuery テーブルのリネージを追跡する 有効化 データリネージを有効化するには、プロジェクトで以下の3つの API を有効化するだけです。API 有効化後、リネージ情報の取得が開始されます。そのため、有効化前のリネージは確認できないことに注意が必要です。有効化すると、Dataplex 料金が発生することに留意してください。 Dataplex API BigQuery API Data lineage API 追跡可能な情報 データリネージは、BigQuery の以下の情報を自動的に記録します。 COPY ジョブ(テーブルの複製) Cloud Storage からの LOAD ジョブ 以下の QUERY ジョブ(DDL) CREATE TABLE CREATE TABLE AS SELECT CREATE TABLE COPY CREATE TABLE CLONE CREATE TABLE FUNCTION CREATE TABLE LIKE CREATE VIEW CREATE MATERIALIZED VIEW 以下の QUERY ジョブ(DML) SELECT(ビュー、マテリアライズドビュー、外部テーブル) INSERT SELECT MERGE UPDATE DELETE BigQuery Data Transfer Service による定期的な LOAD ジョブは自動記録されないので注意が必要です。 また、データリネージは他にも Cloud Data Fusion、Cloud Composer、Dataproc、Vertex AI に対応しています。 さらに、対応していないソースでも、Data Lineage API 経由で記録させることが可能です。 参考 : データリネージについて - データリネージの自動追跡 保持期間 リネージ情報の保持期間は30日間です。 なお、BigQuery テーブルなどを削除したとしても、リネージ情報は30日間は残り続けます。 参考 : 制限事項 Dataplex Discovery Dataplex Discovery とは Dataplex Discovery は、データレイク内のデータからメタデータを 自動でスキャン して抽出し、メタデータ化して Dataproc Metastore、BigQuery、Dataplex Universal Catalog に登録して利用可能にする機能です。 新しいゾーンやアセットを作成すると、自動で Dataplex Discovery が有効になりますが、オプショナルで無効にすることもできます。 Discovery が有効になっている Dataplex アセット(Cloud Storage バケット等)では、画像ファイルのような非構造化データや、Parquet / Avro / ORC / JSONL / CSV などの構造化ファイルが 自動でスキャンされます。テーブル名、スキーマ、パーティション定義などの テクニカルメタデータ が収集され、Dataproc Metastore に Hive-style テーブルとして、また BigQuery では 外部テーブル として登録されるため、自動的にデータがクエリ可能になります。 これによって、組織内で管理されるデータソースが増えた場合に、わざわざ BigQuery にロードまたは外部テーブル定義したり、Jupyter Notebook で読み込める形に整形加工したりといった作業をせずとも、すぐさまこれらのツールで分析ができます。 参考 : データを検出します Discovery Action データのスキャン中に問題が検出されると、 Discovery Action (検出操作)と呼ばれるアラートが上がります。以下のような問題が検出されたときに、Discovery Action が起票されます。 無効なデータ形式 互換性のないスキーマ 無効なパーティション定義 データの欠損 機能名的に誤解を招きそうですが、Discovery Action はあくまで問題のアラートを上げるだけで、実際の改善アクションはユーザが行う必要があります。 参考 : 検出操作 異なるシステムのインターフェースをつなぐデータパイプラインでは、関係者内であらかじめ設計・合意されたスキーマのデータソースが流れていくはずです。 前述のようなデータ不正は想定外の恒久的エラーであるケースが多く、クラウドリソースの枯渇のような一時的エラーとは異なります。システムの自動リトライによって回避できるものではないため、迅速に検知して人が対処する必要があります。Discovery Action はそのような事態の迅速な検知に役立ちます。 ロギングとモニタリング ロギング Dataplex のログは Cloud Logging に自動的に出力されます。アセットを検出したり、スケジューリングされたタスクが実行されると、Cloud Logging にログが出力されます。 また監査ログ(「誰が、いつ、どこで、何をしたか」)も同様に、Cloud Logging に出力されます。 参考 : Dataplex のログをモニタリングする 参考 : 監査ログの管理 モニタリング Dataplex は Cloud Monitoring と統合されており「アセットの合計サイズ」「ファイルセットの数」「テーブルの数」などに加え、未解決の管理アクションの有無などもメトリクスとして閲覧できます。 また、アプリケーションのパフォーマンスや稼働状況を視覚的に把握できます。Dataplex から収集した指標やメタデータを Cloud Monitoring のダッシュボードやグラフで表示し、詳細な分析情報を提供します。 これらの指標は自動的に有効化され、直感的にアクセスできます。 参考 : Dataplex の指標をモニタリングする 料金 Dataplex の料金は Dataplex が使った「コンピュートリソース」「ストレージ」によって課金されます。 コンピュート課金には Standard と Premium の2ティアがあり、例えば Dataplex Discovery 機能は Standard ティアの単価で課金され、データリネージやデータ品質タスクは Premium ティアの単価で課金されます。 どの機能にどの課金が適用されるか、詳細は以下をご参照ください。 参考 : Dataplex pricing その他の機能 メタデータのインポート(マネージド接続) マネージド接続 (Managed connectivity)機能を利用すると、サードパーティのソースからメタデータを Dataplex にインポートできます。 コネクタを開発することで、MySQL、SQL Server、Oracle、Snowflake、Databricks などのソースからメタデータを抽出できます。 コネクタは、Dataproc Serverless で実行できる Artifact Registry イメージとして、PySpark 等で開発する必要があります。 参考 : マネージド接続の概要 参考 : メタデータのインポート用にカスタム コネクタを開発する ビジネス用語集 ビジネス用語集 (Business glossaries)は、組織全体でビジネス関連の用語を定義して一元管理する機能です。 用語はカテゴリ分け・階層化することができ、また用語間の関係を定義することもできます。その用語の管理者を明記しておくことも可能です。 さらに定義された用語は、データエントリのカラムにアタッチすることができるため、メタデータ管理の際に表記の揺れを防ぐことにも繋がります。 参考 : Dataplex のビジネス用語集の作成と管理 Gemini in Dataplex(分析情報) Dataplex では、Google の生成 AI モデル Gemini を利用して、BigQuery テーブルや外部テーブル、ビューの データ分析情報 (data insights)を生成することができます。 この機能では、BigQuery テーブルに付与されたメタデータを使用して、テーブルとクエリに関する自然言語の質問を生成したり、その質問に回答するための SQL を生成できます。これにより、テーブルのデータから、パターンの検出、データ品質の評価、統計分析を行うことが可能です。 参考 : Dataplex のデータ分析情報にアクセスする Gemini が生成した質問とクエリ データ分析情報は、Gemini in BigQuery の機能です。Gemini in BigQuery については、以下も参照してください。 参考 : BigQueryを徹底解説!(基本編) - G-gen Tech Blog - Gemini in BigQuery 神谷 乗治 (記事一覧) クラウドソリューション部 クラウドエンジニア。2017 年頃から Google Cloud を用いたデータ基盤構築や ML エンジニアリング、データ分析に従事。クラウドエース株式会社システム開発部マネージャーを経て現職。Google Cloud Partner Top Engineer 2023,2024、Google Cloud Champion Innovators(Database)、 著書:「GCPの教科書III【Cloud AIプロダクト編】」  
アバター
G-gen 又吉です。当記事では、Google Cloud の LLM (Vertex AI PaLM API) と LangChain を組み合わせて、自然言語から BigQuery 上の統計データを取得する方法を紹介します。 はじめに 準備 実行環境 使用するデータ 実装 ライブラリのインストール 関数の定義 概要 解説 実行 はじめに LangChain とは、大規模言語モデル (LLM) アプリケーションを効率よく実装するためのフレームワークです。LangChain についての詳細は以下の記事をご参照ください。 blog.g-gen.co.jp LangChain にはさまざまな機能が提供されておりますが、今回は Agents 機能を用いて SQL データベースと対話するエージェントを作成します。 LLM の ハルシネーション (幻覚) を抑制する手法として、指定した情報源だけに基づいて LLM に回答を生成させることを グラウンディング といいます。 最近では、テキストや画像をエンべディング (ベクトル化) する技術とベクトル検索の技術を組み合わせて RAG (Retrieval Augmented Generation) を行うグラウンディング手法が人気となっています。 しかし、自社のデータベースに保存された構造化データに対し、LLM が自然言語を理解して SQL を生成し、最終的に分析結果 (統計データ) を取得して回答を生成させたい場合にはどうしたらよいでしょうか。 例えば「先月の売上を教えて」というユーザーの入力に対し、LLM がデータベースに対して適切な SQL を発行し、先月の売上を算出して回答を生成するなどです。この場合も、指定した情報源(自社の売上データ)を基に回答を生成しているため、グラウンディングにあたります。 今回は、この構成を LangChain を用いて実装してみたいと思います。 今回の構成図 準備 実行環境 当記事では、 Colab Enterprise の Notebook を使用します。Colab Enterprise は、マネージドな Notebook のためインフラストラクチャを管理せず実装に注力できます。 Colab Enterprise の Notebook 作成方法は公式ドキュメントのクイックスタートをご参考下さい。 cloud.google.com 使用するデータ 今回使用するデータは、架空の販売データ ( sample-data ) を使用します。 尚、BigQuery テーブルの作成は省略しますが、作成後のテーブルプレビューは以下になります。 sales_data テーブル 実装 ライブラリのインストール Notebook が立ち上がり、ランタイムと接続できましたら以下のコードを実行してライブラリのインストールとインポートを行います。 # input:[1] !pip install sqlalchemy sqlalchemy-bigquery google-cloud-bigquery langchain ライブラリのインストールができたら、ランタイムを再起動してから以下を実行します。 # input:[2] from google.cloud import bigquery from sqlalchemy import * from sqlalchemy.engine import create_engine from sqlalchemy.schema import * from langchain.agents import create_sql_agent from langchain.agents.agent_toolkits import SQLDatabaseToolkit from langchain.sql_database import SQLDatabase from langchain.llms import VertexAI from langchain.agents import AgentExecutor 関数の定義 概要 ユーザーの入力 (自然言語) を引数に、BigQuery 上のデータから分析結果を出力する関数を定義します。 # input:[3] project = ${PROJECT_ID} dataset = ${DATASET_ID} sqlalchemy_url = f "bigquery://{project}/{dataset}" # SQLAlchemy エンジンを初期化 db = SQLDatabase.from_uri(database_uri=sqlalchemy_url) # Vertex AI 基盤モデルを初期化 llm = VertexAI( model_name= "text-bison@001" , max_output_tokens= 1024 , temperature= 0.1 , top_p= 0.8 , top_k= 40 , verbose= True , ) # SQL データベースと対話するエージェントの初期化 toolkit = SQLDatabaseToolkit(db=db, llm=llm) agent_executor = create_sql_agent( llm=llm, toolkit=toolkit, verbose= True , top_k= 10 , ) def run_query (query): res = agent_executor.run(query) return res 解説 SQLAlchemy エンジンを初期化 8 行目で SQLAlchemy エンジンを初期化しています。 SQLDatabase オブジェクトの from_uri メソッドで URI から SQLAlchemy エンジンを初期化できます。 URI の記法については、 Python-bigquery-sqlalchemy のドキュメントをご参照ください。また、BigQuery への認証情報については、 google-api-core のドキュメントをご参照ください。 SQL データベースと対話するエージェントの初期化 20-26 行目でSQL データベースと対話するエージェントの初期化しています。 SQLDatabaseToolkit オブジェクトは、SQL データベースと対話するためのツールキットであり、 create_sql_agent でエージェントを初期化しています。 このエージェントによって、ユーザーの入力から「次にどのようなアクションを取るか」を考え、実行、観測して答えがでるまで繰り返します。今回の場合は、ユーザーの入力に対して、SQL を生成して BigQuery にジョブを実行する操作を、最終的な結果を得るまで繰り返してくれます。 実行 それでは、実行してみましょう。 # input:[4] run_query( "プロダクト別の売上の上位10位を教えてください。" ) # output:[4] > Entering new AgentExecutor chain... Action: sql_db_list_tables Action Input: Observation: sales_data Thought:I found the table sales_data. I should query the schema of this table to see what columns I can use in my query. Action: sql_db_schema Action Input: sales_data Observation: CREATE TABLE `sales_data` ( `ctm_id` STRING, `ctm_name` STRING, `ctm_gender` STRING, `ctm_birthdate` DATE, `ctm_age` INT64, `ctm_postcode` STRING, `ctm_prefecture` STRING, `ctm_prefecture_code` INT64, `ctm_phone` STRING, `ctm_email` STRING, `ctm_ip_address` STRING, `sls_date` DATE, `sls_product` STRING, `sls_amount` INT64 ) /* 3 rows from sales_data table: ctm_id ctm_name ctm_gender ctm_birthdate ctm_age ctm_postcode ctm_prefecture ctm_prefecture_code ctm_phone ctm_email ctm_ip_address sls_date sls_product sls_amount C1000000044 矢部 剛 男 1996-07-07 25 134-5508 北海道 1 080-5565-3368 GCK5pwtZy@ test .jp 168 . 52 . 65 . 10 2021-02-28 Chromebook 3631 C1000000044 矢部 剛 男 1996-07-07 25 134-5508 北海道 1 080-5565-3368 GCK5pwtZy@ test .jp 168 . 52 . 65 . 10 2020-02-28 Chromebook 3631 C1000000044 矢部 剛 男 1996-07-07 25 134-5508 北海道 1 080-5565-3368 GCK5pwtZy@ test .jp 168 . 52 . 65 . 10 2022-02-28 Chromebook 3631 */ Thought:The table sales_data has the columns sls_product and sls_amount. I can use these columns to query the product and amount of sales. Action: sql_db_query Action Input: SELECT sls_product, SUM ( sls_amount ) FROM sales_data GROUP BY sls_product ORDER BY SUM ( sls_amount ) DESC LIMIT 10 Observation: [ ( ' Chromebook ' , 19160341 ), ( ' Mac ' , 11702719 ), ( ' マウス ' , 8605347 ), ( ' iPhone ' , 8178375 ), ( ' Windows ' , 5620327 ), ( ' HDD ' , 5419557 ), ( ' Android ' , 4475812 ), ( ' キーボード ' , 4391927 ), ( ' SSD ' , 3995346 ), ( ' 充電器 ' , 2162517 ) ] Thought:I now know the final answer Final Answer: The top 10 products by sales are: Chromebook, Mac, マウス, iPhone, Windows, HDD, Android, キーボード, SSD, 充電器. > Finished chain. The top 10 products by sales are: Chromebook, Mac, マウス, iPhone, Windows, HDD, Android, キーボード, SSD, 充電器. 処理の流れを一部見てみます。 [3 行目] Action : BigQuery データセットのテーブル一覧を取得 [5 行目] Observation : sales_data テーブルを検出 [6 行目] Action : sales_data テーブルのスキーマを取得して列を確認する [33 行目] Thought : sales_data テーブルには、sls_product 列と sls_amount 列があり、これらの列を使用してプロダクトと売上高をクエリできます。 [35 行目] Action Input : SELECT sls_product, SUM(sls_amount) FROM sales_data GROUP BY sls_product ORDER BY SUM(sls_amount) DESC LIMIT 10 上記のように、ユーザーの入力に対して、「次にどのようなアクションを取るか」とエージェントが考えて実行しています。 そして最終的なアプトプットが Finished chain として 40 行目に出力されてます。なお、統計結果は正しいものでした。 せっかくなので、別のクエリも試してみます。 # input:[5] run_query( "2020年9月1日から2020年9月30日までの売上合計を教えてください。" ) # output:[5] > Entering new AgentExecutor chain... Action: sql_db_list_tables Action Input: Observation: sales_data Thought:I found the table sales_data. I should query the schema of this table to see what columns I can use in my query. Action: sql_db_schema Action Input: sales_data Observation: CREATE TABLE `sales_data` ( `ctm_id` STRING, `ctm_name` STRING, `ctm_gender` STRING, `ctm_birthdate` DATE, `ctm_age` INT64, `ctm_postcode` STRING, `ctm_prefecture` STRING, `ctm_prefecture_code` INT64, `ctm_phone` STRING, `ctm_email` STRING, `ctm_ip_address` STRING, `sls_date` DATE, `sls_product` STRING, `sls_amount` INT64 ) /* 3 rows from sales_data table: ctm_id ctm_name ctm_gender ctm_birthdate ctm_age ctm_postcode ctm_prefecture ctm_prefecture_code ctm_phone ctm_email ctm_ip_address sls_date sls_product sls_amount C1000000044 矢部 剛 男 1996-07-07 25 134-5508 北海道 1 080-5565-3368 GCK5pwtZy@ test .jp 168 . 52 . 65 . 10 2021-02-28 Chromebook 3631 C1000000044 矢部 剛 男 1996-07-07 25 134-5508 北海道 1 080-5565-3368 GCK5pwtZy@ test .jp 168 . 52 . 65 . 10 2020-02-28 Chromebook 3631 C1000000044 矢部 剛 男 1996-07-07 25 134-5508 北海道 1 080-5565-3368 GCK5pwtZy@ test .jp 168 . 52 . 65 . 10 2022-02-28 Chromebook 3631 */ Thought:The table sales_data has the columns sls_date and sls_amount. I can use these columns to query the total sales for the period 2020-09-01 to 2020-09-30. Action: sql_db_query Action Input: SELECT SUM ( sls_amount ) FROM sales_data WHERE sls_date BETWEEN ' 2020-09-01 ' AND ' 2020-09-30 ' Observation: [ ( 997305 ,) ] Thought:I now know the final answer Final Answer: The total sales for the period 2020-09-01 to 2020-09-30 is 997305 . > Finished chain. The total sales for the period 2020-09-01 to 2020-09-30 is 997305 . こちらも最終的なアプトプットは正しいものでした。 このような LangChain を用いることで、自然言語によるインプットから LLM が自社の構造化データから統計的な分析結果を返してくれるグラウンディング手法も容易に実装ができますね。 又吉 佑樹 (記事一覧) クラウドソリューション部 はいさい、沖縄出身のクラウドエンジニア! セールスからエンジニアへ転身。Google Cloud 全 11 資格保有。Google Cloud Partner Top Engineer 2024。Google Cloud 公式ユーザー会 Jagu'e'r でエバンジェリストとして活動中。好きな分野は AI/ML。 Follow @matayuuuu
アバター
G-gen の佐々木です。当記事では Cloud Run jobs のジョブ実行時に利用できる、 ジョブ構成のオーバーライド について解説します。 Cloud Run jobs とは ジョブ構成のオーバーライド 必要な権限 ジョブ構成のオーバーライドを試してみる 使用するコード(Go) Cloud Run ジョブのデプロイ デフォルトのジョブ構成でジョブを実行する ジョブ構成をオーバーライドしてジョブを実行する トラブルシューティング (CLI) Cloud Run jobs とは Cloud Run jobs は、サーバーレス コンテナコンピューティング サービスである Cloud Run の 1 機能です。Cloud Run services が HTTP リクエストを処理の起点とするのに対して、Cloud Run jobs はコンテナイメージとして実装したジョブを、手動、スケジュール、ワークフローなど、ユーザの任意タイミングで並列して実行することができます。 Cloud Run jobs の詳細については、以下の記事で解説しています。 blog.g-gen.co.jp ジョブ構成のオーバーライド Cloud Run jobs では、ジョブの作成時に環境変数、タスク数(処理を並列実行する数。各実行は タスク と呼ばれる)、タイムアウトなどの値をジョブ構成として設定します。 これらのジョブ構成のうちのいくつかは、ジョブを実行する際にオーバーライドすることが可能です。つまり、 ジョブ構成として設定された値を変更することなく、一度のジョブ実行でのみ有効な値を設定する ことができます。 ジョブ構成のうちオーバーライド可能なパラメータは以下の 4つです。 コンテナのエントリポイントとなるコマンドに渡す引数 ジョブの環境変数 タスク数(タスクの並列実行数) タスクのタイムアウト(最大実行時間) ジョブ構成のオーバーライドは以下のようなユースケースが考えられます。 日付や処理対象テーブルなどを引数や環境変数に設定し、ジョブに処理させるデータの範囲を実行ごとに切り替える ジョブに処理させるデータ量が通常より多い場合に、並列実行数やタイムアウトの値を増やす 参考: ジョブを実行する | 特定の実行のジョブ構成をオーバーライドする 必要な権限 ジョブ構成のオーバーライドには、ジョブの実行に必要な run.jobs.run 権限に加えて run.jobs.runWithOverrides 権限が必要となります。 当該権限は Cloud Run 開発者(roles/run.developer) ロールのほか、ジョブの実行に必要な最小権限であれば オーバーライドを使用する Cloud Run ジョブ エグゼキュータ(roles/run.jobsExecutorWithOverrides) という事前定義ロールを利用することができます。 オーバーライドを使用する Cloud Run ジョブ エグゼキュータ ロール ジョブ構成のオーバーライドを試してみる 使用するコード(Go) 当記事では、オーバーライド可能な各種パラメータを標準出力するだけのシンプルな処理を実行するコードを使用し、ジョブ構成のオーバーライドを試してみます。 コード内でオーバーライドの対象となっているのは、ジョブ実行時の引数となる --user の値と、ジョブ自体に設定する TARGET_ENV 環境変数の値です。これらを標準出力するだけのシンプルな処理となっています。 また、ジョブの実行時に タスク数 と タイムアウト の値もオーバーライドします。Cloud Run jobs でタスクを並列実行する際、 CLOUD_RUN_TASK_INDEX 環境変数からタスク番号を取得できるため、これもあわせて出力します。 package main import ( "flag" "fmt" "os" ) func main() { // 引数の定義と値の取得 var u = flag.String( "user" , "unknown" , "user name" ) // --userオプション(デフォルト値:unknown) flag.Parse() taskNum := os.Getenv( "CLOUD_RUN_TASK_INDEX" ) // 並列実行タスクのタスク番号(インデックス) userName := *u // ジョブ実行時に与えた引数 targetEnv := os.Getenv( "TARGET_ENV" ) // ユーザーが設定した環境変数 // タスク番号、引数、環境変数を標準出力 fmt.Printf( "TASK#%v USER:%v TARGET:%v \n " , taskNum, userName, targetEnv) } Cloud Run ジョブのデプロイ gcloud run jobs deploy コマンドで Cloud Run jobs のジョブをデプロイします。 以下のコマンドを使用することで、Dockerfile を用意することなくソースコードからジョブをデプロイすることができます( 参考 )。 当記事では「run-jobs-override」という名前でジョブをデプロイします。 # ソースコードから Cloud Run ジョブをデプロイする $ gcloud run jobs deploy { ジョブ名 } \ --source . \ --tasks 1 \ --set-env-vars TARGET_ENV =dev \ --region asia-northeast1 \ --project { プロジェクトID } ---出力例--- $ gcloud run jobs deploy run-jobs-override \ --source . \ --tasks 1 \ --set-env-vars TARGET_ENV =dev \ --region asia-northeast1 \ --project myproject This command is equivalent to running `gcloud builds submit --pack image = [ IMAGE ] .` and `gcloud run jobs deploy run-jobs-override --image [ IMAGE ] ` Building using Buildpacks and deploying container to Cloud Run job [ run-jobs-override ] in project [ myproject ] region [ asia-northeast1 ] ✓ Building and creating job... Done. ✓ Uploading sources... ✓ Building Container... Logs are available at [ https://console.cloud.google.com/cloud-build/builds/2350151f-1af8-4ef8-99b4-980ce5f761ea?project = xxxxxxxxxxxx ] . Done. Job [ run-jobs-override ] has successfully been deployed. To execute this job, use: gcloud run jobs execute run-jobs-override なお、上記のコマンドでジョブをデプロイすると、ビルドされたコンテナイメージは「cloud-run-source-deploy」という名前の Artifact Registry リポジトリに格納されます。このリポジトリがプロジェクトにまだ存在していない場合、ジョブのデプロイ時にリポジトリを新規作成するかどうか確認されます。 Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [ cloud-run-source-deploy ] in region [ asia-northeast1 ] will be created. Do you want to continue ( Y/n ) ? Y デフォルトのジョブ構成でジョブを実行する まず、デプロイしたジョブをそのまま実行してみます。 ジョブの実行には gcloud run jobs execute コマンドを使用し、ジョブをデプロイしたリージョンのみオプションに指定して実行します。 # ジョブ構成の通りにジョブを実行する $ gcloud run jobs execute { ジョブ名 } --region asia-northeast1 ---出力例--- $ gcloud run jobs execute run-jobs-override --region asia-northeast1 ✓ Creating execution... Done. ✓ Provisioning resources... Done. Execution [ run-jobs-override-94g9h ] has successfully started running. View details about this execution by running: gcloud run jobs executions describe run-jobs-override-94g9h Or visit https://console.cloud.google.com/run/ jobs /executions/details/asia-northeast1/run-jobs-override-94g9h/tasks? project =xxxxxxxxxxxx 出力内の View details about this execution by running: に記載されている gcloud run jobs executions describe コマンドで、実行したジョブの詳細を確認します。 以下のように、並列実行タスク数( Tasks )、タイムアウト( Task Timeout )がそれぞれデフォルトの値に、 TARGET_ENV 環境変数( Env vars: TARGET_ENV )がデプロイ時に指定した値になっていることがわかります。 項目 値 Tasks 1 Task Timeout 600s Env vars: TARGET_ENV dev $ gcloud run jobs executions describe { ジョブの実行ID } ---出力例--- # 実行したジョブの詳細を確認する $ gcloud run jobs executions describe run-jobs-override-94g9h --region asia-northeast1 ✔ Execution run-jobs-override-94g9h in region asia-northeast1 1 task completed successfully Elapsed time: 12 seconds Log URI: https://console.cloud.google.com/logs/viewer? project =myproject& advancedFilter =resource. type %3D%22cloud_run_job% 22 %0Aresource.labels.job_name%3D%22run-jobs-override% 22 %0Aresource.labels.location%3D%22asia-northeast1% 22 %0Alabels.%22run.googleapis.com/execution_name% 22 %3D%22run-jobs-override-94g9h% 22 Image: asia-northeast1-docker.pkg.dev/myproject/cloud-run-source-deploy/run-jobs-override Tasks: 1 Memory: 512Mi CPU: 1000m Task Timeout: 600s Max Retries: 3 Parallelism: 1 Service account: xxxxxxxxxxxx-compute@developer.gserviceaccount.com Env vars: TARGET_ENV dev 出力されたジョブ詳細の Log URI: に記載されている URL から Cloud Logging のコンソールに遷移してログ出力を確認します。 タスクが 1つしか実行されていないため、コード内の fmt.Printf 関数から出力されたログは以下の 1件のみとなっています。 TASK#0 USER:unknown TARGET:dev ジョブ構成をオーバーライドしない場合の実行ログ タスクが 1つなので TASK# (タスク番号)は 0 、 TARGET_ENV 環境変数の値として TARGET が dev になっています。 USER はジョブ実行時に --user 引数を指定しなかったため、デフォルトに設定しておいた unknown になっていることがわかります。 ジョブ構成をオーバーライドしてジョブを実行する 次に、ジョブ構成をオーバーライドしてジョブを実行してみます。 以下のオプションを使用して各種パラメータをオーバーライドすることができます。 オプション 説明 --args コンテナのエントリポイントとなるコマンドに渡す引数 --update-env-vars ジョブの環境変数 ( {KEY1}={VALUE1},{KEY2}={VALUE2} の形式で指定) --tasks タスクの並列実行数 --task-timeout タスクの最大実行時間 (たとえば 10分の場合、 10m もしくは 600s の形式で指定) --user 引数に sasashun を指定し、TARGET_ENV 環境変数を prod 、並列実行タスク数を 3 、タイムアウトを 10m30s でオーバーライドしてジョブを実行します。 # ジョブ構成をオーバーライドしてジョブを実行する $ gcloud run jobs execute { ジョブ名 } \ --region asia-northeast1 \ --args =" --user=sasashun " \ --update-env-vars TARGET_ENV =prod \ --tasks 3 \ --task-timeout 10m30s ---出力例--- $ gcloud run jobs execute run-jobs-override \ --region asia-northeast1 \ --args =" --user=sasashun " \ --update-env-vars TARGET_ENV =prod \ --tasks 3 \ --task-timeout 10m30s ✓ Creating execution... Done. ✓ Provisioning resources... Done. Execution [ run-jobs-override-cd2f8 ] has successfully started running. View details about this execution by running: gcloud run jobs executions describe run-jobs-override-cd2f8 Or visit https://console.cloud.google.com/run/ jobs /executions/details/asia-northeast1/run-jobs-override-cd2f8/tasks? project =xxxxxxxxxxxx gcloud run jobs executions describe コマンドで実行したジョブの詳細を確認します。 出力例にあるように、実行時にオーバーライドした値が反映されていることがわかります。 項目 ジョブ構成の値 オーバーライドした値 Tasks 1 3 Task Timeout 600s 10m30s Env vars: TARGET_ENV dev prod # 実行したジョブの詳細を確認する $ gcloud run jobs executions describe run-jobs-override-cd2f8 --region asia-northeast1 ---出力例--- $ gcloud run jobs executions describe run-jobs-override-cd2f8 --region asia-northeast1 ✔ Execution run-jobs-override-cd2f8 in region asia-northeast1 3 tasks completed successfully Elapsed time: 18 seconds Log URI: https://console.cloud.google.com/logs/viewer? project =myproject& advancedFilter =resource. type %3D%22cloud_run_job% 22 %0Aresource.labels.job_name%3D%22run-jobs-override% 22 %0Aresource.labels.location%3D%22asia-northeast1% 22 %0Alabels.%22run.googleapis.com/execution_name% 22 %3D%22run-jobs-override-cd2f8% 22 Image: asia-northeast1-docker.pkg.dev/myproject/cloud-run-source-deploy/run-jobs-override Tasks: 3 Args: --user = sasashun Memory: 512Mi CPU: 1000m Task Timeout: 10m30s Max Retries: 3 Parallelism: 3 Service account: xxxxxxxxxxxx-compute@developer.gserviceaccount.com Env vars: TARGET_ENV prod ジョブ詳細の Log URI: に記載されている URL から Cloud Logging のコンソールに遷移してログ出力を確認します。 オーバーライドされたタスク数である 3タスクが実行され、 --user 引数と TARGET_ENV 環境変数の値がジョブに反映されていることがわかります。 TASK#0 USER:sasashun TARGET:prod TASK#1 USER:sasashun TARGET:prod TASK#2 USER:sasashun TARGET:prod ジョブ構成をオーバーライドした場合の実行ログ トラブルシューティング (CLI) ジョブ構成のオーバーライドは 2023年 10月に GA となった機能であり、使用している gcloud CLI のバージョンによっては各種オプションが指定できない場合があります。 gcloud CLI のバージョンが古くオプションが指定できない場合、以下のようなエラーメッセージが出力されます。 ERROR: ( gcloud.run. jobs .execute ) unrecognized arguments: --args flag is available in one or more alternate release tracks. Try: gcloud alpha run jobs execute --args gcloud beta run jobs execute --args --args = --user = sasashun ( did you mean ' --async ' ? ) このようなエラーにより CLI からのジョブ実行が上手くいかない場合、まずは gcloud run jobs execute --help でオーバーライドに関するオプション( --args など)が表示されているか確認してください。 # 使用できるオプションを確認する $ gcloud run jobs execute --help NAME gcloud run jobs execute - qexecute a job SYNOPSIS gcloud run jobs execute [ JOB ] [ --args =[ ARG,... ]] [ --region = REGION ] [ --task-timeout = TASK_TIMEOUT ] [ --tasks = TASKS ] [ --update-env-vars =[ KEY = VALUE ,... ]] [ --async | --wait ] [ GCLOUD_WIDE_FLAG ... ] ~~~以下省略~~~ オプションが無い場合、使用している gcloud CLI のバージョンによっては gcloud bata run jobs execute もしくは gcloud alpha run jobs execute コマンドでオプションを指定して実行することができますが、可能であれば gcloud CLI をアップグレードすることを推奨します。 佐々木 駿太 (記事一覧) G-gen最北端、北海道在住のクラウドソリューション部エンジニア 2022年6月にG-genにジョイン。Google Cloud Partner Top Engineer 2025 Fellowに選出。好きなGoogle CloudプロダクトはCloud Run。 趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。 Follow @sasashun0805
アバター
G-gen の杉村です。2023年10月のイチオシ Google Cloud アップデートをまとめてご紹介します。記載は全て、記事公開当時のものですのでご留意ください。 はじめに Looker Studio と BigQuery のさらなる統合 (Private Preview) Cloud SQL で異エディション間でバックアップ→リストアが可能に Looker Studio Pro がユーザ単位で利用可能に BigQuery のリージョン間テーブルコピーが Private Preview 一部リージョンの Spanner がパフォーマンス改善 Colab Enterprise が Preview -> GA Cloud Domains の一部機能が廃止 Regional external Application Load Balancer で Cloud Armor が使用可能に プロジェクト管理者が予算アラートを作れるように (Preview => GA) BigQuery change data capture (CDC) が Preview => GA Cloud Run jobs の実行時のジョブ設定オーバーライドが Preview => GA はじめに 月ごとの Google Cloud アップデートのうち、特にイチオシなものをまとめています。 ある程度の事前知識が必要な記載となっています。サービスごとの前提知識は、ぜひ以下の記事もご参照ください。 blog.g-gen.co.jp またリンク先の公式ガイドは英語版にしないと最新情報が反映されていない場合がありますためご注意ください。 Looker Studio と BigQuery のさらなる統合 (Private Preview) BigQuery native integration in Looker Studio preview (2023/10/02) Looker Studio と BigQuery の間で INFORMATION_SCHEMA 、 execution graph 、 Cloud Monitoring メトリクス との統合が強化。BigQuery のシステムビューである INFORMATION_SCHEMA.JOBS には looker_studio_report_id や looker_studio_datasource_id が記録されるようになる。 すなわち、どの Looker Studioレポートからクエリが発行されたかが分かるようになった。 どのレポートがどのくらい課金に影響しているか、の可視化が容易になる。 Cloud SQL で異エディション間でバックアップ→リストアが可能に About restoring an instance (2023/10/02) Cloud SQL で異なるエディション間 (Enterprise <-> Enterprise Plus) でバックアップ→リストアが可能になった。 既存の Enterprise インスタンスを容易に Enterprise Plus にアップグレードする一つの手段として考えられる。 Looker Studio Pro がユーザ単位で利用可能に Looker Studio release notes (2023) - October 2, 2023 (2023/10/02) Looker Studio Pro がユーザ単位で利用可能になった。従来は「組織単位で有効化」のみであり、MAU 全員に課金されてしまった(MAU = Monthly Active User)。 料金は $9 / user / month。 さらに従来はオフラインオーダー(都度、営業を介して注文)だったが、、コンソールからユーザ自身で Looker Studio Pro へアップグレード可能になった。 Looker Studio Pro の詳細な解説は以下を参照。 blog.g-gen.co.jp BigQuery のリージョン間テーブルコピーが Private Preview リージョン間でテーブルをコピーする (2023/10/04) BigQuery でテーブルのリージョン間コピーが Private Preview に。 Private Preview のため、利用には申込みが必要。 これまでは同一リージョン間でしかテーブルをコピーできないため BigQuery Data Transfer Service を使うなど工夫する必要があった。 一部リージョンの Spanner がパフォーマンス改善 Cloud Spanner is now half the cost of Amazon DynamoDB, and with strong consistency and single-digit ms latency (2023/10/12) 大阪リージョンを含む一部のリージョンの Spanner が、コスト据え置きのままパフォーマンスが向上。Read & Write の QPS が従来の 1.5 倍になる。 対象リージョンは大阪、台湾、ムンバイ、オランダ等で、今後拡大予定。 Cloud Spanner の詳細な解説は以下を参照。 blog.g-gen.co.jp Colab Enterprise が Preview -> GA Introduction to Colab Enterprise (2023/10/11) Colab Enterprise が Preview -> GAに。 Colab Enterprise はフルマネージドな Notebook。Vertex AI や BigQuery とのシームレスな統合や Duet AI によるコーディング補助などが最低限の管理コストで手に入る。類似サービスで Vertex AI Workbench がある。 なお Colab Enterprise と Vertex AI Workbench のどちらを選ぶかは 公式ドキュメント )に以下のように記載されている。 Colab Enterprise: 優先事項が他のユーザーとコラボレーションし、インフラストラクチャの管理に時間を費やすことを避けることである場合、Colab Enterprise が最適な選択肢となる可能性があります。 Vertex AI Workbench: 優先事項が制御とカスタマイズ性である場合、Vertex AI Workbench が最適な選択肢となる可能性があります。 Cloud Domains の一部機能が廃止 Cloud Domains feature deprecation (2023/10/20) Squarespace 社が Google Domains を買収したため Google Cloud プロダクトである Cloud Domains も影響を受ける。 ドメインの管理機能は引き続き利用できるが、主に DNS 関連機能が影響を受ける。以下のドキュメントで、いつ何の機能が影響されるのか確認可能。 参考 : Cloud Domains feature deprecation Regional external Application Load Balancer で Cloud Armor が使用可能に Regionally scoped security policies (2023/10/20) Cloud Armor (Google Cloud のフルマネージド WAF) が Regional external Application Load Balancer でも使えるようになった (Preview => GA)。 これまで Cloud Armor は Global なロードバランサでしか利用できなかったが、今後はネットワーク料金を抑えつつWebアプリをセキュアにできる。 プロジェクト管理者が予算アラートを作れるように (Preview => GA) Create, edit, or delete budgets and budget alerts (2023/10/23) プロジェクト管理者・編集者が予算アラートを作れるように (Preview => GA)。 これまでは「請求先アカウント管理者」でないと予算アラートが作れなかったが、今後はプロジェクトレベルで予算アラートが作成できるようになった。 請求先アカウントの仕組みについては以下を参照。 blog.g-gen.co.jp BigQuery change data capture (CDC) が Preview => GA Stream table updates with change data capture (2023/10/31) BigQuery change data capture (CDC) が Preview => GA。 BigQuery にリアルタイムでデータを流し込む際、複雑な MERGE 構文を使わなくとも UPSERT/DELETE を含む更新が可能に。 max_staleness 設定により反映インターバルを調整し、パフォーマンス調整も可能。 ※名称から誤解しやすいが BigQuery のデータ変更をキャプチャする仕組み、ではないため注意。 Cloud Run jobs の実行時のジョブ設定オーバーライドが Preview => GA Override job configuration for a specific execution (2023/10/31) Cloud Run jobs が、ジョブ実行にジョブ設定をオーバーライドできるように(Preview => GA)。オーバーライド可能なパラメータは以下の 4つ。 コンテナのエントリポイントとなるコマンドに渡す引数 環境変数 タスク並列実行数 タスクのタイムアウト 当アップデートは以下の記事で詳細に解説している。 blog.g-gen.co.jp 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の佐々木です。当記事では Cloud Run 上のアプリケーションで Cloud SQL Auth Proxy を使って Cloud SQL へ接続する際に接続が失敗した事象と、その対策について解説します。 はじめに 前提知識 各種サービスについて Cloud Run から Cloud NAT を使用するケース 事象 発生した事象 想定していた通信経路 実際の通信経路 原因 解決策 余談 はじめに Cloud Run 上のアプリケーションから Cloud SQL への接続に Cloud SQL Auth Proxy を利用している状況において、意図せず通信が Cloud NAT を経由してしまったことにより、Cloud NAT のポート数上限に抵触して DB 接続が失敗する事象がおきました。 その原因と対策について解説します。 前提知識 各種サービスについて 当記事内に出てくる各種サービスの内容については説明を割愛します。 それぞれ以下の記事で詳細に解説されているので、こちらをご一読ください。 ■ Cloud Run blog.g-gen.co.jp ■ Cloud SQL blog.g-gen.co.jp ■ Cloud NAT blog.g-gen.co.jp Cloud Run から Cloud NAT を使用するケース Cloud Run ではサーバーレスの仕様により、処理を行っていないときはインスタンスを終了してインフラリソースを解放してしまうため、インスタンスが使用する IP アドレスは都度変わってしまいます。 Cloud Run 上のアプリケーションから アクセス元 IP を制限するような外部サービスに接続する必要がある場合 には、Cloud Run からインターネットへのアウトバウンド接続は Cloud NAT を経由するようにすることで、接続元 IP アドレスを Cloud NAT の静的 IP アドレスに固定できます。 Cloud Run から Cloud NAT のような VPC リソースにアクセスするためには、 サーバーレス VPC アクセス を構成する必要があります。詳細は以下の記事で解説しています。 blog.g-gen.co.jp 事象 発生した事象 ある Cloud Run 上のアプリケーションは、Cloud NAT を経由して外部サービスの API にアクセスする必要があります。外部サービス側で接続元 IP アドレスをホワイトリスト制限しているため、Cloud NAT を経由することで接続元 IP を固定したいためです。 またそのアプリケーションはデータベースとして Cloud SQL を利用しており、Cloud SQL への認証をシンプルにするため Cloud SQL Auth Proxy を使っていました。 このアプリにおいて、リリースに向けた負荷試験を実施したとき、以下のようなエラーメッセージが出力されました。 "Cloud SQL connection failed. Please see https://cloud.google.com/sql/docs/mysql/connect-run for additional details: connection to Cloud SQL instance at {Cloud SQLインスタンスのパブリックIP}:3307 failed: timed out after 10s" 想定していた通信経路 この構成で当初想定していた通信経路は以下のようなものでした。 Cloud Run から Cloud SQL と Cloud NAT に接続する構成(想定しているもの) サーバーレス VPC アクセスのコネクタインスタンスは、負荷によってスケールアウトすると、その後一切スケールインできない仕様があります(スケールインするためには作り直しが必要です)。 そのためサーバーレス VPC アクセスは外部 API へのアクセスのみで使用し、Cloud SQL への接続は Cloud SQL Auth Proxy を使用してパブリック IP で接続したいと考えていました。Cloud SQL Auth Proxy を使うと接続先は Cloud SQL のパブリック IP アドレスとなるため、直感的には Cloud Run から Cloud SQL への接続は VPC (サーバーレス VPC アクセス) を通らず、直接 Cloud SQL に届くようなイメージでした。 実際の通信経路 しかしその想定は、実際には異なっていました。前述のエラーメッセージが出力されたことから詳細に調べた結果、実際の通信経路は以下のようなものでした。 実際の通信経路 Cloud Run から Cloud SQL にパブリック IP で直接接続してほしかったのですが、実際には サーバーレス VPC アクセスのコネクタインスタンスと Cloud NAT を経由して 接続されていました。 これにより、想定していなかった負荷がコネクタインスタンスや Cloud NAT にかかってしまい、コネクタインスタンスのリソース不足や Cloud NAT のポート数制限などがデータベース接続に影響を及ぼしていました。 原因 Cloud SQL への通信がサーバーレス VPC アクセスと Cloud NAT を経由してしまう原因は、Cloud Run から送信されるトラフィックのルーティングの仕様にあります。 Cloud Run でサーバーレス VPC アクセスを使用する際、どのトラフィックをサーバーレス VPC アクセスコネクタに送信するかを設定する項目があります。外部 API のようなパブリック IP へのリクエストを Cloud NAT 経由で行うには、ここで「 すべてのトラフィックを VPC にルーティングする 」を選択する必要があります。 Cloud Run のアウトバウンド通信をすべてサーバーレス VPC アクセスコネクタに送信する設定 これにより、Cloud Run は全てのアウトバウンド通信を VPC へルーティングしてしまい、よって Auth Proxy を使った Cloud SQL への通信であっても、Cloud NAT 経由となってしまったのでした。 Cloud Run の仕様からすると当然の挙動なのですが、Cloud SQL Auth Proxy を使うことで Cloud SQL に直接接続すると直感的に感じてしまったことが、原因へ気がつくことを遅らせました。 解決策 仕様上、Cloud SQL に対する通信だけを Cloud NAT を使わない直接通信とすることはできません。 妥協案となってしまいますが、すべての通信がサーバーレス VPC アクセスコネクタを経由することは許容し、プライベート IP を使用して Cloud SQL に接続することで、データベース接続が Cloud NAT を経由してしまうことを防ぐことができます。 これにより、少なくとも Cloud NAT の上限に抵触することでデータベース接続が失敗してしまうような状況は回避できます。 Cloud SQL への接続にプライベート IP を使用し、Cloud NAT を経由しないようにする 余談 Cloud NAT 同様、Cloud Run からの接続にサーバーレス VPC アクセスが必要となるサービスとして Memorystore などがありますが、こちらはプライベート IP 接続以外の選択肢がないため、Cloud Run で「プライベート IP へのリクエストのみを VPC にルーティングする」の設定がされていれば、Cloud SQL への接続はパブリック IP で行うことが可能です。 プライベート IP へのアウトバウンド接続のみサーバーレス VPC アクセスコネクタに送信する設定 佐々木 駿太 (記事一覧) G-gen 最北端、北海道在住のクラウドソリューション部エンジニア。 2022 年 6 月に G-gen にジョイン。Google Cloud All Certifications Engineer。 好きな Google Cloud プロダクトは Cloud Run。 Follow @sasashun0805
アバター
G-gen の佐々木です。当記事では Cloud Run や Cloud Functions などで使用する サーバーレス VPC アクセス のコネクタインスタンスで発生するメンテナンスと、それに関する注意点を記載します。 はじめに 前提知識 サーバーレス VPC アクセスとは コネクタインスタンスのスケーリングについて コネクタインスタンスのメンテナンス メンテナンス時に何が起こるのか メンテナンスの注意点 はじめに 長期起動とする Cloud Run サービスがサーバーレス VPC アクセスを使う場合は、コネクタインスタンスの突発メンテナンスに備えて、データベース接続断を検知して再接続を行う処理をアプリケーション側に実装する必要があります。 その理由と仕組みについて、詳述していきます。 前提知識 サーバーレス VPC アクセスとは サーバーレス VPC アクセス とは、Cloud Run、Cloud Functions、Google App Engine(Standard 環境)などのサーバーレスなサービスがプライベート IP を使用して VPC 内リソースに接続するための方法です。 サーバーレス VPC アクセスでは、各種サービスから接続したい VPC に サーバーレス VPC アクセスコネクタ と呼ばれるインスタンス(以下、 コネクタインスタンス )を作成します。このコネクタインスタンスを経由することで、Compute Engine VM や Cloud SQL などの VPC 内リソースにプライベート IP で接続することができるようになります。 参考 : Serverless VPC Access サーバーレス VPC アクセスを使用した Cloud SQL への接続例 Cloud Run では、VPC 内リソースにプライベート IP で接続する方法として、サーバーレス VPC アクセスのほかに Direct VPC Egress があります。Direct VPC Egress の詳細、およびサーバーレス VPC アクセスとの違いについては以下の記事をご一読ください。 blog.g-gen.co.jp コネクタインスタンスのスケーリングについて サーバーレス VPC アクセスでは、VPC に接続するために作成するコネクタインスタンスの最小数(2~9)と最大数(3~10)をあらかじめ設定します。 コンテナインスタンスの負荷が高まると、最大で設定した値までインスタンスがスケールアウトしますが、その後負荷が解消されてもインスタンスがスケールインすることはありません。 たとえば、最小数 2、最大数 5の設定でコンテナインスタンスが 5までスケールアウトすると、その後インスタンスの数が 4以下にスケールインすることはありません。インスタンス数を減らしたい場合、サーバーレス VPC アクセスを再設定(削除→新規作成)する必要があります。 コネクタインスタンスのメンテナンス メンテナンス時に何が起こるのか サーバーレス VPC アクセスにおけるコネクタインスタンスの裏側では Compute Engine VM インスタンスが実行されており、Google によるセキュリティアップデートなどのメンテナンスが数分間行われる場合があります。 メンテナンスが発生すると、利用できるコネクタインスタンスの数を維持するために、 最大数に設定されているコネクタインスタンス数を一時的に超過してスケールアウトする場合 があります。 参考 : Throughput and scaling たとえば、コネクタインスタンスの数が 3つであり、それが設定している最大数だった場合、メンテナンス時にインスタンス数が 6までスケールアウトする可能性があります。メンテナンスが終了すると、インスタンスの数は 3にスケールインされます。 したがって、 コネクタインスタンスのメンテナンス時には、設定値を超過するスケールアウトと本来起こらないはずのスケールインが起こる 可能性があります。Cloud Monitoring などの監視ツールで、メンテナンス時の一時的なインスタンス数増加を確認することができます。 メンテナンスの注意点 メンテナンス時に発生するスケールアウトは、利用可能なコネクタインスタンスの数を保ち、コネクタインスタンスを使用するサービスが中断しないようにするための仕様です。しかし、これまで接続していたメンテナンス対象のインスタンスに接続できなくなることで、サービス中断が発生する可能性があります。 以下の例では、Cloud Run 上のアプリケーションからサーバーレス VPC アクセスを使用して Cloud SQL に接続しています。 サーバーレス VPC アクセスを使用した Cloud SQL への接続 メンテナンスが発生してコネクタインスタンスがスケールアウトし、元々あったインスタンスに接続できなくなったとします。 このとき、Cloud Run 上のアプリケーションから Cloud SQL への接続を維持できず、サービス中断が発生する可能性があります。 メンテナンスによるコネクタインスタンスのスケールアウト サービス中断を防ぐためには、データベース接続のエラーを検知して再接続を行う処理をアプリケーション側に実装する必要があります。 再接続により正常なコネクタインスタンスへの接続が行われ、Cloud SQL への接続を継続することができます。 再接続ロジックにより新しいコネクタインスタンスに接続する 佐々木 駿太 (記事一覧) G-gen最北端、北海道在住のクラウドソリューション部エンジニア 2022年6月にG-genにジョイン。Google Cloud Partner Top Engineer 2024に選出。好きなGoogle CloudプロダクトはCloud Run。 趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。 Follow @sasashun0805
アバター
G-gen の杉村です。BigQuery の特殊な GROUP BY 構文である GROUP BY GROUPING SETS GROUP BY CUBE GROUP BY ROLLUP について解説します。 はじめに GROUP BY GROUPING SETS GROUP BY CUBE GROUP BY ROLLUP はじめに BigQuery で以下の特殊な GROUP BY 構文が、2023年10月9日に Preview 公開、2024年2月26日に一般公開(GA)されました。 GROUP BY GROUPING SETS GROUP BY CUBE GROUP BY ROLLUP (以前からあったが groupable items sets を指定できるようになった) これらの構文は他の分析用データベース製品でも一般的なものです。改めて、どのように使うのかを確認してみました。 参考 : Group rows by GROUPING SETS 参考 : Group rows by CUBE 参考 : Group rows by ROLLUP GROUP BY GROUPING SETS GROUP BY GROUPING SETS は GROUP BY 句で列を複数指定して、それぞれの集計結果を合わせて一つの結果として返すための構文です。 実例を見てみましょう。 WITH Products AS ( SELECT ' shirt ' AS product_type, ' t-shirt ' AS product_name, 3 AS product_count UNION ALL SELECT ' shirt ' , ' t-shirt ' , 8 UNION ALL SELECT ' shirt ' , ' polo ' , 25 UNION ALL SELECT ' pants ' , ' jeans ' , 6 ) SELECT product_type, product_name, SUM (product_count) AS product_sum FROM Products GROUP BY GROUPING SETS (product_type, product_name) ORDER BY product_name; 出力結果 product_type product_name product_sum shirt ( null ) 36 pants ( null ) 6 ( null ) jeans 6 ( null ) polo 25 ( null ) t-shirt 11 このように、異なる列をキーとした集計結果が一つの結果テーブルとなって返ってきました。使わない列には null が入っています。つまり出力結果には product_type ごとの集計 (product_name 列が null ) product_name ごとの集計 (product_type 列が null ) が入っています。 これは、以下のように通常の GROUP BY を使った集計クエリを2つ実行して UNION ALL した結果と全く同じです。 WITH Products AS ( SELECT ' shirt ' AS product_type, ' t-shirt ' AS product_name, 3 AS product_count UNION ALL SELECT ' shirt ' , ' t-shirt ' , 8 UNION ALL SELECT ' shirt ' , ' polo ' , 25 UNION ALL SELECT ' pants ' , ' jeans ' , 6 ) SELECT product_type, NULL AS product_name, SUM (product_count) AS product_sum FROM Products GROUP BY product_type UNION ALL SELECT NULL AS product_type, product_name, SUM (product_count) AS product_sum FROM Products GROUP BY product_name ORDER BY product_name; GROUP BY CUBE GROUP BY CUBE は GROUP BY 句で複数列を指定し、指定された全ての列の全ての組み合わせの集計結果を返す構文です。 WITH Products AS ( SELECT ' shirt ' AS product_type, ' t-shirt ' AS product_name, 3 AS product_count UNION ALL SELECT ' shirt ' , ' t-shirt ' , 8 UNION ALL SELECT ' shirt ' , ' polo ' , 25 UNION ALL SELECT ' pants ' , ' jeans ' , 6 ) SELECT product_type, product_name, SUM (product_count) AS product_sum FROM Products GROUP BY CUBE (product_type, product_name) ORDER BY product_type, product_name; 出力結果 product_type product_name product_sum ( null ) ( null ) 42 ( null ) jeans 6 ( null ) polo 25 ( null ) t-shirt 11 pants ( null ) 6 pants jeans 6 shirt ( null ) 36 shirt polo 25 shirt t-shirt 11 出力結果には 全ての行の集計 (product_name 列も product_type 列も null ) product_name ごとの集計 (product_type 列が null ) product_type ごとの集計 (product_name 列が null ) product_type + product_name の集計 ( null が無い) が含まれています。つまり GROUP BY CUBE (product_type, product_name) の括弧内で指定した列 (+ 列なし) の全ての組み合わせで集計をしています。 GROUP BY ROLLUP GROUP BY ROLLUP は集計に使う列を複数指定して、その列で合計結果を積み上げて一つの結果として返す構文です。 実例を見てみましょう。 WITH Products AS ( SELECT ' shirt ' AS product_type, ' t-shirt ' AS product_name, 3 AS product_count UNION ALL SELECT ' shirt ' , ' t-shirt ' , 8 UNION ALL SELECT ' shirt ' , ' polo ' , 25 UNION ALL SELECT ' pants ' , ' jeans ' , 6 ) SELECT product_type, product_name, SUM (product_count) AS product_sum FROM Products GROUP BY ROLLUP (product_type, product_name) ORDER BY product_type, product_name; 出力結果 product_type product_name product_sum ( null ) ( null ) 42 pants ( null ) 6 pants jeans 6 shirt ( null ) 36 shirt polo 25 shirt t-shirt 11 出力結果には 全ての行の合計 (product_name 列も product_type 列も null ) product_type ごとの集計 (product_name 列が null ) product_type + product_name の集計 ( null が無い) が含まれています。考え方としては「積み上げ」で、細かい集計から次々により大きい項目へ集計している、と考えることができます。 次の例のほうが分かりやすいかもしれません (数字はでたらめです)。 WITH cities AS ( SELECT ' 日本 ' AS nation, ' 東京 ' AS prefecture, ' 新宿区 ' AS city, 100 AS population UNION ALL SELECT ' 日本 ' , ' 東京 ' , ' 豊島区 ' , 80 UNION ALL SELECT ' 日本 ' , ' 東京 ' , ' 品川区 ' , 50 UNION ALL SELECT ' 日本 ' , ' 埼玉県 ' , ' ふじみ野市 ' , 60 UNION ALL SELECT ' 日本 ' , ' 埼玉県 ' , ' さいたま市 ' , 70 UNION ALL SELECT ' アメリカ合衆国 ' , ' カリフォルニア州 ' , ' サンディエゴ市 ' , 50 ) SELECT nation, prefecture, city, SUM (population) AS population_sum FROM cities GROUP BY ROLLUP (nation, prefecture, city) ORDER BY prefecture, city; 出力結果 nation prefecture city population_sum ( null ) ( null ) ( null ) 410 日本 ( null ) ( null ) 360 アメリカ合衆国 ( null ) ( null ) 50 アメリカ合衆国 カリフォルニア州 ( null ) 50 アメリカ合衆国 カリフォルニア州 サンディエゴ市 50 日本 埼玉県 ( null ) 130 日本 埼玉県 さいたま市 70 日本 埼玉県 ふじみ野市 60 日本 東京 ( null ) 230 日本 東京 品川区 50 日本 東京 新宿区 100 日本 東京 豊島区 80 GROUP BY ROLLUP (nation, prefecture, city) の括弧の中で指定したのと逆順に、積み上げて合計しています。 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の藤岡です。当記事では Atlantis を使って GitHub のプルリクエスト上で Terraform を実行する方法を紹介します。 当記事で扱うツール Terraform 概要 ローカルから実行する場合の注意点 自動化ツール Atlantis 概要 アーキテクチャ 構築方法 ロック機能と Web UI 構築にあたり アーキテクチャ 前提と注意点 事前準備 GitHub App の作成 Terraform ファイル Atlantis サーバーの構築 Terraform の実行 動作確認 サービスアカウントへ権限付与 プルリクエストを作成 適用 当記事で扱うツール Terraform 概要 Terraform は Infrastructure as Code (IaC) を実現する OSS のツールです。 IT インフラをコードによって構築、管理し CI/CD (継続的インテグレーション / 継続的デリバリ) を可能にします。IT インフラをコードで定義できることのメリットの1つとして、Git によるバージョン管理ができる点が挙げられます。 Terraform を Google Cloud で使う際は、以下の記事をご参照ください。 blog.g-gen.co.jp ローカルから実行する場合の注意点 複数のエンジニアによって開発される場合、どこから Terraform を実行するか注意が必要です。 例えばそれぞれのローカルマシンから Terraform を実行する運用では、ヒューマンエラーによる実行ミスのリスクや実行結果の履歴が残らない等の課題があり、チームでの作業の見える化や過去の変更を追いにくくなる恐れがあります。 自動化ツール Terraform 実行の自動化ツールとして、当記事で紹介する Atlantis の他にも Terraform Cloud や GitHub Actions 等があります。 Atlantis ではプルリクエスト上で Terraform の実行ができるため、前述のローカルマシンから実行する時に生じる課題を解消できます。 GitHub Actions を使った自動化は以下の記事をご参照ください。 blog.g-gen.co.jp Atlantis 概要 Atlantis は プルリクエストを使って Terraform の実行を自動化する OSS ツールです。 以下のように、プルリクエストを作成すると自動で terraform plan が実行され、実行結果がプルリクエストのコメントに記載されます。 そのプルリクエストで atlantis apply をコメントすると terraform apply が実行され、その結果が同じようにコメントに記載されます。 実行イメージ ( 公式ドキュメント より引用) また、 atlantis コマンドの実行条件 (main ブランチへマージ可能な状態であることやプルリクエストが Approve されていること等) を定義できます。 例えば、Terraform で IT インフラを構築する際に、 terraform plan は通ったとしても terraform apply で失敗することもあります。 GitHub でコードを管理している場合に、 terraform plan が通ったものを main ブランチにマージして terraform apply を実行するような運用フローでは、 terraform apply で失敗した時に再度ブランチを切るなど手戻りが発生します。 Atlantis では、プルリクエストのコメント上で Terraform の実行ができるため、実環境へ適用されたものを main ブランチにマージすることができ手戻りが発生しにい等のメリットもあります。 アーキテクチャ Atlantis は以下のように動作します。 アーキテクチャ Atlantis は セルフホスト型 のため、自身で Atlantis サーバーを構築しなければなりません。 Google Cloud の場合、Compute Engine と Google Kubernetes Engine のモジュールが提供されているため、必要な設定を入れるだけで容易に構築ができます。 当記事では 公式から提供されているモジュール を使って Compute Engine 上に Atlantis サーバーを構築し、動作を確認します。 参考: Deployment 構築方法 基本的には公式の インストールガイド に従って構築します。 Git Host のアクセス資格情報を作成 アクセス資格情報は Atlantis が Git Host の API を呼び出す際に使います Git Host には GitHub や GitLab 等が使えます GitHub を Git Host として使う場合、Personal Access Token (PAT) ではなく GitHub App が推奨されます Webhook Secret を作成 Atlantis が Git Host からの Webhook が正しいものかを判別するために設定します 24文字以上である必要があります Atlantis サーバーを構築 Webhook を構成 Git Host に GitHub、アクセス資格情報に GitHub App を使っている場合は Webhook が自動生成されるため不要です プロバイダーの資格情報を構成 Google Cloud の場合、Atlantis サーバーを構築する基盤 (Compute Engine 等) のサービスアカウントが使われます ロック機能と Web UI Atlantis は、Terraform の ロック機能 とは別に独自のロック機能を持っています。 複数のプルリクエストが同一のディレクトリや Terraform Workspaces を変更している場合、最初のプルリクエストがマージされるまで他のプルリクエストの変更は実行できないようになっています。 Atlantis は Web UI も提供しており、ここからロックの確認や解除ができます。 Web UI 但し、この Web UI にはデフォルトでは認証機能がありません。 そのため、Atlantis がデプロイされるとインターネット上からこの Web UI が閲覧できてしまいセキュリティリスクが高まります。 Atlantis からは Basic 認証 が提供されており、また Google Cloud の場合は Identity-Aware Proxy (IAP) と組み合わせることで閲覧制限がかけられます。 また、このロック機能の実現には外部データベース (永続ディスク) が必要です。 Atlantis は外部データベースに terraform plan やプルリクエストのマージ情報などを保存します。 当記事で使う モジュール でも Compute Engine に永続ディスクがアタッチされています。 以下は atlantis apply をした時にプルリクエストのコメントに記載されたエラーログです。Atlantis は /home/atlantis/.atlantis 配下に情報を保存しています。 running " /usr/local/bin/terraform apply -input=false -no-color \" /home/atlantis/.atlantis/repos/REPO_OWNER/REPO_NAME/5/default/default.tfplan \" " in " /home/atlantis/.atlantis/repos/REPO_OWNER/REPO_NAME/5/default " : exit status 1 google_compute_network.vpc_network: Creating... Error: Error creating Network: googleapi: Error 409: The resource ' projects/PROJECT_ID/global/networks/atlantis-vpc ' already exists, alreadyExists with google_compute_network.vpc_network, on main.tf line 12 , in resource " google_compute_network " " vpc_network " : 12: resource " google_compute_network " " vpc_network " { 構築にあたり アーキテクチャ 当記事で作成する構成と、Atlantis サーバーによって作られるリソースは以下の通りです。 アーキテクチャ 前提と注意点 当記事では検証目的のため簡易的な構成としています。本番運用する際は、以下の前提と注意点を踏まえて構築してください。 提供されているモジュール の examples/complete を使用します examples/complete/main.tf では 106 行目 で Cloud DNS へ Cloud Load Balancing の IP アドレスを A レコードに登録しています そのため、既にドメインを取得しており、Cloud DNS でゾーンを管理していることが前提となります Web UI の認証はかけていません 前述の通り、Atlantis には Web UI が提供されますが当記事では認証を設定していません examples/complete/main.tf は以下の点を踏まえ一部変更します Git Host アクセス資格情報 に Personal Access Token (PAT) ではなく GitHub App を使用します (PAT は個人に紐づく点や有効期限がある等の観点から望ましくありません) GitHub App の Private Key を main.tf の local 変数として記載していますが、実際はセキュリティ上の観点から Secret Manager 等で管理することが推奨されます 事前準備 GitHub App の作成 ドキュメント に従って GitHub App を作り、対象のリポジトリへインストールします。 固有の設定箇所は以下の通りです。 項目 設定値 備考 Webhook URL https:// ドメイン名>/events Atlantis は Webhook を /events で受け付ける Webhook secret (optional) 24 文字以上 の任意の文字列 Permissions Administration : Read-only Checks : Read and write Commit statuses : Read and write Contents : Read and write Issues : Read and write Metadata : Read-only (default) Pull requests : Read and write Webhooks : Read and write Members : Read-only ドキュメント に記載 Subscribe to events Check run / Create / Delete / Issue comment / Issues / Pull request / Pull request review / Pull request review comment / Push Atlantis によって自動生成 した際の項目を手動でも設定 作成後、Private keys を生成します。 GitHub App の App ID、Installations ID、Private keys は Terraform で使います。 参考: Git Host Access Credentials Terraform ファイル 公式モジュールの main.tf を以下のように変更します。 # main.tf locals { project_id = "<your-project-id>" region = "<your-region>" zone = "<your-zone>" domain = "<example.com>" managed_zone = "<your-managed-zone>" github_repo_allow_list = "github.com/<repo-owner>/<repo-name>" github_app_id = "<your-github-app-id>" github_app_installation_id = "<your-github-app-installation-id>" github_webhook_secret = "<your-github-webhook-secret>" github_app_key = <<-EOT -----BEGIN RSA PRIVATE KEY----- <your-github-app-private-key> -----END RSA PRIVATE KEY----- EOT services = toset ( [ "compute.googleapis.com" , ] ) } # Enable APIs resource "google_project_service" "service" { for_each = local.services project = local.project_id service = each.value disable_dependent_services = false disable_on_destroy = false } # Create a service account and attach the required Cloud Logging permissions to it resource "google_service_account" "atlantis" { account_id = "atlantis-sa" display_name = "Service Account for Atlantis" project = local.project_id } resource "google_project_iam_member" "atlantis_log_writer" { role = "roles/logging.logWriter" member = "serviceAccount:$ { google_service_account.atlantis.email } " project = local.project_id } resource "google_project_iam_member" "atlantis_metric_writer" { role = "roles/monitoring.metricWriter" member = "serviceAccount:$ { google_service_account.atlantis.email } " project = local.project_id } resource "google_compute_network" "default" { name = "example-network" auto_create_subnetworks = false project = local.project_id } resource "google_compute_subnetwork" "default" { name = "example-subnetwork" ip_cidr_range = "10.2.0.0/16" region = local.region network = google_compute_network.default.id project = local.project_id private_ip_google_access = true log_config { aggregation_interval = "INTERVAL_5_SEC" flow_sampling = 0 . 5 metadata = "INCLUDE_ALL_METADATA" } } # Create a router, which we associate the Cloud NAT too resource "google_compute_router" "default" { name = "example-router" region = google_compute_subnetwork.default.region network = google_compute_network.default.name bgp { asn = 64514 } project = local.project_id } # Create a NAT for outbound internet traffic resource "google_compute_router_nat" "default" { name = "example-router-nat" router = google_compute_router.default.name region = google_compute_router.default.region nat_ip_allocate_option = "AUTO_ONLY" source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES" project = local.project_id } module "atlantis" { source = "bschaatsbergen/atlantis/gce" name = "atlantis" network = google_compute_network.default.name subnetwork = google_compute_subnetwork.default.name region = local.region zone = local.zone service_account = { email = google_service_account.atlantis.email scopes = [ "cloud-platform" ] } # Note: environment variables are shown in the Google Cloud UI # See the `examples/secure-env-vars` if you want to protect sensitive information env_vars = { ATLANTIS_ATLANTIS_URL = "https://$ { local.domain } " ATLANTIS_REPO_ALLOWLIST = local.github_repo_allow_list ATLANTIS_WRITE_GIT_CREDS = true ATLANTIS_REPO_CONFIG_JSON = jsonencode ( yamldecode ( file ( "$ { path.module } /server-atlantis.yaml" ))) ATLANTIS_GH_APP_ID = local.github_app_id ATLANTIS_GH_INSTALLATION_ID = local.github_app_installation_id ATLANTIS_GH_WEBHOOK_SECRET = local.github_webhook_secret ATLANTIS_GH_APP_KEY = local.github_app_key } domain = local.domain project = local.project_id } # As your DNS records might be managed at another registrar's site, we create the DNS record outside of the module. # This record is mandatory in order to provision the managed SSL certificate successfully. resource "google_dns_record_set" "default" { name = "$ { local.domain } ." type = "A" ttl = 60 managed_zone = local.managed_zone rrdatas = [ module.atlantis.ip_address ] project = local.project_id } resource "google_compute_ssl_policy" "default" { name = "example-ssl-policy" profile = "RESTRICTED" min_tls_version = "TLS_1_2" project = local.project_id } Atlantis サーバーの構築 Terraform の実行 Atlantis サーバーと必要なリソースを作成します。 # 初期化 fujioka@penguin:~$ terraform init Initializing the backend... ... fujioka@penguin:~$ # 適用確認 fujioka@penguin:~$ terraform plan ... Plan: 23 to add, 0 to change, 0 to destroy. ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Note: You didn ' t use the -out option to save this plan, so Terraform can ' t guarantee to take exactly these actions if you run " terraform apply " now. fujioka@penguin:~$ # 適用 fujioka@penguin:~$ terraform apply ... Apply complete! Resources: 23 added, 0 changed, 0 destroyed. fujioka@penguin:~$ 動作確認 サービスアカウントへ権限付与 Terraform の実行により、 atlantis-sa@PROJECT_ID-prj.iam.gserviceaccount.com のサービスアカウントが作られます。 GitHub のプルリクエスト上で atlantis コマンドを実行すると Atlantis サーバー (Compute Engine) のサービスアカウントの権限で Terraform が実行されます。 今回は Atlantis サーバーが構築されたプロジェクトとは異なるプロジェクトに対して VPC を作ります。 そのため、VPC を作成するプロジェクトで atlantis-sa@PROJECT_ID-prj.iam.gserviceaccount.com のサービスアカウントに編集者 (roles/editor) ロールを付与して動作を確認します。 プルリクエストを作成 GitHub App をインストールしたリポジトリで main.tf を作成し、プルリクエストを作成します。 今回は検証目的のため、ルートに main.tf を置いています。 main.tf プルリクエストを作成するとリポジトリにインストールされた GitHub App の Subscribe to events に該当するため、Atlantis サーバーへ Webhook され terraform plan の結果がコメントされます。 プルリクエストを作成 適用 プルリクエスト上で atlantis apply をコメントすると、実環境へ適用されリソースが作られます。 適用 藤岡 里美 (記事一覧) クラウドソリューション部 接客業からエンジニアへ。2022年9月 G-gen にジョイン。Google Cloud 認定資格は全冠。ラーメンと甘いものが好きです :) Follow @fujioka57621469
アバター
G-gen タナです。Google Cloud (旧称 GCP) の生成 AI チャットモデルである PaLM 2 の chat-bison モデルを使い、運用を考慮に入れたチャットツールを作成してみましたのでご紹介します。 はじめに 前提知識 Vertex AI PaLM API サンプルコード (Python) ステートフルとステートレス 運用化のポイント ポイント1: チャットボットをステートレスにする 課題 解決策 運用性の検証 応用 ポイント2: 回答スタイルを指定 概要 やり方 動作確認 トラブルシューティング 初期設定 ロジック適用 FastAPI を App Engine でデプロイ PaLM 2 の chat-bisonモデルの運用化のコツ はじめに 先日、「Googleの生成AI、PaLM 2をSlack連携して社内ツールとして導入してみた」というブログ記事で、PaLM 2 の text-bison (テキスト生成用モデル) を使用した簡易的なチャットボットアプリの開発について語りました。 blog.g-gen.co.jp その時、私は PaLM 2 の text-bison が1問1答形式の入力出力にしか対応できないと理解し、その改善点について同記事の「アプリケーションの改善」の章で取り上げました。 この課題を解決するために、当記事では使用モデルを PaLM 2 の chat-bison (チャットモデル) に切り替えましたのでご共有します。前述の記事をまだお読みになっていない方でも、本記事の内容を理解できるように、可能な限り PaLM 2 の chat-bison の説明に焦点を当てて記述します。 前提知識 Vertex AI PaLM API PaLM 2 は Google が開発した生成 AI モデルであり、一般向けチャットツール「Bard」のバックエンドでも使用されています。モデルは Vertex AI の PaLM API として公開されており、Google Cloud 経由で有償で利用できます。 我々開発者はこの Vertex AI PaLM API を使うことで、自社アプリに生成 AI 機能を追加することができます。 今回は Vertex AI PaLM API の中でも、会話に特化した chat-bison を使用します。 Vertex AI PaLM API の詳細については、以下の記事をご確認ください。 blog.g-gen.co.jp サンプルコード (Python) chat-bison モデルのサンプルコード (Python) は以下のリンクをご参照ください。 Test chat prompts https://github.com/GoogleCloudPlatform/python-docs-samples/blob/d5ca4a4518cb20040287129624466fd36b5a646a/generative_ai/chat.py ステートフルとステートレス 当記事では「アプリケーションの状態を維持する」という課題について述べます。アプリケーションのステートフルとステートレスについては以下のリンクをご参照ください。 ステートフル (stateful) とステートレス (stateless) | Red Hat 運用化のポイント 運用化する際に考慮すべきポイントを2つまとめました。1つ目は、インフラの課題を解消するためにチャットボットをステートレスにすること、そして2つ目は回答を改善するためのコツです。 ポイント1: チャットボットをステートレスにする 課題 chat-bison モデルの簡単なサンプルコードは Vertex AI の Web コンソール画面 の右上にある「VIEW CODE」から確認できます。 import vertexai from vertexai.language_models import ChatModel, InputOutputTextPair vertexai.init(project= "thanab" , location= "us-central1" ) chat_model = ChatModel.from_pretrained( "chat-bison" ) parameters = { "max_output_tokens" : 1024 , "temperature" : 0.2 , "top_p" : 0.8 , "top_k" : 40 } chat = chat_model.start_chat( context= """my context""" , ) response = chat.send_message( """my message no. 1""" , **parameters) print (f "Response from Model: {response.text}" ) response = chat.send_message( """my message no. 2""" , **parameters) print (f "Response from Model: {response.text}" ) このコードでは、会話履歴(以下、会話のステート)は chat オブジェクトに格納されます。それにより、再度 chat.send_message 関数を呼び出した際に、過去の会話を考慮した回答が PaLM 2 から得られます。 会話のステートはこのコードを実行するインスタンスのメモリに保存されているため、ステートフルなアプリケーションになります。それにより、運用時に以下の課題が生じます。 1. スケーラビリティ ユーザー数が増えると、会話のステートのボリュームが大きくなり、コストの高い資源であるメモリが多く必要となります。 2. フェイルオーバーと復旧 インスタンスが停止した場合、以前の会話のステートは消えてしまい、インスタンスを再開した後に会話を継続することが難しくなります。 以下のようにこの課題を再現してみます。まず chat_1 チャットセッションで私の名前を覚えさせます。その後、このコードを実行するインスタンスが停止するシナリオを再現するために、関連オブジェクトを削除しました。インスタンスが再開し、同じ会話を続けようとしたところ chat_2 チャットセッションでは私の名前は忘れられてしまいました。 ステートフルの場合、インスタンスが停止した後、チャットセッションが再開したときの動作 解決策 考え方 以下のコードのように、チャットオブジェクトの ._message_history 属性を何処かに保存しておき、再度チャットのオブジェクトを作成する際に chat_model.start_chat 関数の引数として用いることで、会話を再開した後も会話を継続することが可能になります。 Python SDK においては、チャット履歴の内容はチャットオブジェクトの ._message_history 属性に保存されています。これはドキュメントには明記されていません (当記事を書いた理由の一つは、この発見のご共有です)。 ここでは、可読性のために会話のステートを my_historical_chat という変数に保存しました。 ステートレスの場合、インスタンスが停止した後、チャットセッションが再開したときの動作 変数 my_historical_chat の内容はこのようになります。 chat-bisonのチャット履歴の内容 運用性の検証 では、次に外部のデータストレージに会話のステートを保存し、それを復元してみましょう。 データを保存できるサービスは様々ありますが、今回は安価に利用できる Cloud Storage (以下、GCS) に保存し、ステートレス化します。会話のステートを GCS バケットに書き込み、後で読み込む動作を次のように行います。GCS バケットは事前に作成済みの前提です。 まず、以下のように会話のステートをシリアル化してから、GCS バケットに書き込みます。ここで利用している pickle は、Python オブジェクトをシリアル化 (シリアライズ = 直列化。バイト列に変換することでファイル保存等を可能にする) するための Python 標準モジュールです。 import pickle from google.cloud import storage import vertexai from vertexai.language_models import ChatModel # パラメータ設定 bucket_name = "historical-chat-object" destination_blob_name = "会話識別番号_001.pkl" parameters = { "max_output_tokens" : 1000 , "temperature" : 0.2 , "top_p" : 0.95 , "top_k" : 40 } # 関数宣言 def upload_blob (bucket_name, source_file_name, destination_blob_name): """Uploads a file to the bucket.""" storage_client = storage.Client(credentials = credentials) bucket = storage_client.bucket(bucket_name) blob = bucket.blob(destination_blob_name) blob.upload_from_string(source_file_name) def serialize_to_pickle (python_object): # Serialize the Python object to a pickle serialized_object = pickle.dumps(python_object) return serialized_object # アプリ vertexai.init(project= "thanab" , location= "us-central1" , credentials = credentials) # あるユーザーがチャットセッションを開始 chat__1 = chat_model.start_chat() response = chat__1.send_message( """my name is thana""" , **parameters) response = chat__1.send_message( """my age is 30""" , **parameters) response = chat__1.send_message( """what is my name""" , **parameters) print (f "Response from chat__1: {response.text}" ) my_historical_chat = chat__1._message_history # 会話のステートをシリアル化 serialized_chat_state = serialize_to_pickle(my_historical_chat) # GCSへアップロード upload_blob(bucket_name, serialized_chat_state, destination_blob_name) 上記のコードを実行すると、このように GCS バケットに会話のステートがアップロードされました。 次は、このステートを読み込んで会話を再開するコードです。 import pickle from google.cloud import storage import vertexai from vertexai.language_models import ChatModel bucket_name = "historical-chat-object" source_blob_name = "会話識別番号_001.pkl" def download_blob (bucket_name, source_blob_name): """Downloads a blob from the bucket.""" storage_client = storage.Client(credentials = credentials) bucket = storage_client.bucket(bucket_name) blob = bucket.blob(source_blob_name) return blob.download_as_bytes() def deserialize_from_pickle (serialized_object): # Deserialize the object from a pickle python_object = pickle.loads(serialized_object) return python_object # GCS から会話のステートをダウンロード serialized_object = download_blob(bucket_name, source_blob_name) # シリアル化された会話のステートを逆シリアル化し、使える形にする my_loaded_historical_chat = pickle.loads(serialized_object) vertexai.init(project= "thanab" , location= "us-central1" , credentials = credentials) # インスタンス再開 chat_model = ChatModel.from_pretrained( "chat-bison@001" ) # ユーザーが続いて会話する chat__2 = chat_model.start_chat(message_history = my_loaded_historical_chat) response = chat__2.send_message( """what is my name""" , **parameters) print (f "Response from chat__2: {response.text}" ) 上記のコードを実行すると、私の名前を覚えていて会話を継続できることが確認できます。 応用 チャットボットに適用するシナリオを以下のように考えてみます。会話識別番号ごとに、会話のステートを管理します。そのために、会話の識別番号を GCS オブジェクト名にして会話のステートを保存します。 過去の会話ステートの有無の確認は、会話の識別番号に一致する GCS オブジェクトの有無で確認します。Slack でチャットボットを開発する場合、Slack のスレッド番号を会話識別番号として利用できるでしょう。 運用時のロジックの例 ポイント2: 回答スタイルを指定 概要 PaLM 2 のデフォルトの出力スタイルは簡潔なものです。より記述的な回答が望ましい場合は、入出力の例を指定することで、希望に近い出力スタイルを引き出すことができます。 入力出力例の有無によって、回答がどのように変わるか見てみましょう。 入出力例がない場合 入力出力の例 (example)がない場合のchat-bisonの回答 入出力例がある場合 入力出力の例 (example)がある場合のchat-bisonの回答 やり方 Google Cloud 公式の GitHub レポジトリ を参考にして以下のように試しました。 1. 入出力例を用意 オリジナルで作成しても構いませんが今回は Hugging Face からいくつかのサンプルを拾って利用しました。一つをピックアップすると、以下のようなものです。 example_1_ja_output = """印刷された新聞とオンラインニュースメディアの強みと弱みは、多くの面で比較することができます。以下にそれぞれの面について詳しく説明します。 内容 印刷された新聞は、選択された記事を深く言及し、詳細な調査報告を提供することができます。一方、オンラインニュースメディアは、新しい情報にアクセスする速度が速く、即座に編集することができます。また、オンラインニュースメディアは、読者が自由に記事を共有できるため、より幅広い読者層に到達することができます。 配信方法 印刷された新聞は、紙を介して届けられるため、読者が手に取って読むことができます。しかし、紙のニュースメディアは、定期的な配信サイクルに従う必要があります。一方、オンラインニュースメディアは、広範なデバイスで直接アクセスでき、随時更新されます。また、オンラインニュースメディアは、記事を即座に共有することができるため、情報の速度が向上します。 対象読者 印刷された新聞は、購読者を対象にしています。しかし、オンラインニュースメディアは、より広範な読者層に到達することができます。特に、若い読者は、オンラインニュースメディアを使用することが多いです。 広告モデル 印刷された新聞は、大部分の収益を広告から得ています。しかし、紙のニュースメディアは、競合が増える中で広告料が下がっています。一方、オンラインニュースメディアは、デジタル広告モデルを使用して収益を得ています。これは、読者層に対するターゲット広告を提供することができるためです。 社会への影響 印刷された新聞は、コミュニティとのつながりにおいて重要な役割を果たしています。また、新聞社による深く詳細な調査報道は、社会問題の解決に役立ちます。一方、オンラインニュースメディアは、情報へのアクセス性が向上することで、より多くの読者層を影響することができます。 バイアスの可能性 印刷された新聞には、報道規模の制限があります。報道の範囲や、編集方針によっては、バイアスが生まれる可能性があります。一方、オンラインニュースメディアは、より多岐にわたる記事を提供しており、バイアスの可能性を減らすことができます。 第2のJSONコードを使用することで、デジタルジャーナリズムの移行の影響を評価することができます。多段階の推論プロセスを組み込むことで、印刷メディアが直面する課題について検討し、競争力を維持するための新しい戦略を探索することができます。このプロセスには、将来の印刷メディアの不確実性とイノベーションの必要性についても認識することが含まれます。""" 上記の入出力例をチャットモデルが使える形にします。 from vertexai.language_models import InputOutputTextPair examples = [ InputOutputTextPair( input_text=example_1_ja_input, output_text=example_1_ja_output, ), InputOutputTextPair( input_text=example_2_ja_input, output_text=example_2_ja_output, ), InputOutputTextPair( input_text=example_3_ja_input, output_text=example_3_ja_output, ), ] 2. examples を chat_model.start_chat 開始時に渡す 上記コードで作成した examples 配列オブジェクトを chat_model.start_chat 関数に引き渡します。 chat = chat_model.start_chat(examples = examples) response = chat.send_message( """円高とは""" , **parameters) print (f "Response from Model: \n {response.text}" ) 動作確認 前回の記事「 Googleの生成AI、PaLM 2をSlack連携して社内ツールとして導入してみた 」を書く際に開発したアプリへ、上記のロジックを適用してみました。会話が継続しており、かつ記述的な回答が得られている様子が確認できました。 PaLM 2のchat-bisonを運用化してみた 上記の例では、私の2つ目のプロンプトでは「 それを 」という曖昧な表現を使いました。それでも PaLM 2 の chat-bison がちゃんと過去の会話の内容を考慮して回答を返してくれました。 トラブルシューティング 読者が再現する際に起こり得る他のトラブルシューティングを以下のようにまとめました。 初期設定 Slack チャットボットのアーキテクチャや初期設定に興味がある方は以下のリンクをご参照ください。 blog.g-gen.co.jp ロジック適用 開発コードに興味がある方は、以下のレポジトリを確認することができます。 github.com バックエンドフレームワークはSlackと連携する専用のPythonライブラリを利用しています。該当ライブラリについては以下のURLをご覧ください。 Slack | Bolt for Python GitHub - slackapi/bolt-python: A framework to build Slack apps using Python FastAPI を App Engine でデプロイ FastAPI のアプリを開発環境で実行する際、次のコマンドで実行できます。 uvicorn app:api --port 8080 しかし App Engine などの運用環境では、uvicorn でアプリをデプロイするとエラーが発生することがあります。その解決策として App Engine の app.yaml を用意する際に次のコマンドを entrypoint として指定すると、無事にアプリをデプロイすることができます。 gunicorn -w 2 -k uvicorn.workers.UvicornWorker -b 0 . 0 . 0 .0:8080 app:api -w と uvicorn.workers.UvicornWorker は それぞれワーカー数とワーカークラス を指定するものです。 また instance class が F1 の場合、ワーカー数を2個に指定すれば無事に動作することを確認しました。その値を超えた場合、リソースが不足し、アプリがダウンする可能性があります。 当記事についてご興味を持たれ、自社でも実装してみたい場合は、G-gen の Web サイトからお気軽にお問い合わせください。 タナ (記事一覧) データアナリティクス準備室 データエンジニア バックエンド開発を含むデータ分析とデータエンジニアの経験を持つ。AIの活用にも関心がある。Professional Machine Learningを取得。出身地はタイのバンコクで、現在は広島在住。
アバター
G-gen の杉村です。BigQuery は通常の運用データベースと異なり、分析用データベースであることから、非正規化したテーブルを扱うことが多くなります。そのための独特のデータ型として、ARRAY (配列) と STRUCT (構造体) があります。これらについて解説します。 概要 ARRAY (配列) ARRAY とは サンプルテーブル SELECT SELECT 〜 WHERE SELECT 〜 CROSS JOIN SELECT (SELECT ~ UNNEST) CREATE TABLE / INSERT 制限 STRUCT (構造体) STRUCT とは サンプルテーブル SELECT SELECT 〜 WHERE CREATE TABLE / INSERT 制限 ARRAY<STRUCT> (ネストされた繰り返し列) ARRAY<STRUCT> とは サンプルテーブル SELECT SELECT 〜 WHERE (エラー) SELECT 〜 CROSS JOIN SELECT (SELECT ~ UNNEST) CREATE TABLE / INSERT 実践 : Google Analytics 4 データへのクエリ 概要 テーブル例 クエリ例1: 特定ページの PV 数を集計 クエリ例2 : string_value を取り出す関数を作る スキーマ表記 概要 ARRAY STRUCT ARRAY<STRUCT> 概要 BigQuery は Google Cloud (旧称 GCP) の提供するサーバーレスな分析用データベースのサービスです。列志向 (カラムナ) の特徴を持ち、料金プランの選択にもよりますが、デフォルトではスキャンしたデータ量に応じた従量課金です。 クラウド上の分析用データベースのベストプラクティスとして、テーブルを非正規化することでデータ読み取りや結合のコストを下げ、パフォーマンス向上を図ることがあります。今回ご紹介する ARRAY (配列) と STRUCT (構造体) は、いずれもデータを非正規化して持つ型です。これらのデータ型には、Google Analytics 4 や Google Analytics for Firebase、Google Cloud の Billing Export などでデータを BigQuery にエクスポートするとよく出会います。 その独特のクエリの仕方に苦しめられた人も多いのではないでしょうか。当記事ではこれらについて解説し、また組み合わせて使う ARRAY<STRUCT> についてもご紹介します。 また、最後には Google Analytics 4 のデータを模したテーブルに対するクエリの方法も例示します。 参考 : ネストされ繰り返されているフィールドを使用する ARRAY (配列) ARRAY とは ARRAY (配列) とは「ゼロ個以上の同じデータ型の値で構成された順序付きリスト」のことです。以下のようなものを指します。 # INT64 の配列 [ 2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 ] # STRING の配列 [" 国語 " , " 算数 " , " 理科 " , " 社会 "] 配列の型を持つテーブルは以下のようなものになります。 (行番号) name subjects 1 田中 太郎 国語 算数 理科 社会 2 鈴木 二郎 国語 算数 ※ (行番号) 列は一行のまとまりを示すために便宜的に割り振ったものであり、テーブル内のデータではありません。 上記のテーブルの subjects 列は ARRAY であり、 1行に2つ以上の値 が入っています。 これはリレーションの第1正規形に違反しており、通常のリレーショナル・データベースではこのようなデータの持ち方をしません。しかし BigQuery のような分析用データベースではこのような配列型を使いリレーションを維持したまま、マスタとトランザクションを分けない大福帳的なテーブル構成にすることで、JOIN のコストが下がりパフォーマンス向上を図ることができます。 参考 : Array type 参考 : 配列リテラル 参考 : 配列の操作 サンプルテーブル ここからは実際の SQL を紹介しながらイメージを掴んでいきます。以下の WITH 句を仮想的なサンプルテーブルとして使います。 name 列が通常の STRING 型で、subjects 列は STRING 型の値を要素に持つ配列型です。 WITH t0 AS ( SELECT " 田中 太郎 " AS name, [ " 国語 " , " 算数 " , " 理科 " , " 社会 " ] AS subjects UNION ALL SELECT " 鈴木 二郎 " AS name, [ " 国語 " , " 算数 " ] AS subjects ) SELECT * FROM t0; (行番号) name subjects 1 田中 太郎 国語 算数 理科 社会 2 鈴木 二郎 国語 算数 SELECT まず SELECT 文の例を見ることでイメージを掴みます (以降、WITH 句は省略します。先ほどの SQL 文後半の SELECT 以降を書き換えてお試しください)。 SELECT name, subjects FROM t0; 上記のように、SELECT 文は通常の列をクエリするときと何ら代わりありません。出力結果は以下のようになり、配列内の全ての値が返ります。 (行番号) name subjects 1 田中 太郎 国語 算数 理科 社会 2 鈴木 二郎 国語 算数 SELECT 〜 WHERE WHERE 句でフィルタをしようと考えたとき、最初の壁に当たります。 SELECT name, subjects FROM t0 WHERE subjects = " 理科 " ; この SQL は、以下のようなエラーになります。 No matching signature for operator = for argument types: ARRAY<STRING>, STRING. Supported signature: ANY = ANY at [17:3] = の左辺と右辺で異なる型 (左辺は ARRAY である subjects 列、右辺は STRING) を指定していることからエラーになっています。なお右辺を ["国語", "算数"] のように配列にしてもエラーになります ( Equality is not defined for arguments of type ARRAY<STRING> at [7:5] )。 = 演算子はそもそも配列型をサポートしていません。 一方で、以下のクエリは成功します。 SELECT name, subjects FROM t0 WHERE " 理科 " IN UNNEST(subjects); (行番号) name subjects 1 田中 太郎 国語 算数 理科 社会 ここでは UNNEST 関数を用いています。UNNEST() は配列内の全要素を各行に割り振った「テーブル」を返します。以下の例を見てください。 SELECT * FROM UNNEST([ 1 , 2 , 3 ]); (行番号) f0_ 1 1 2 2 3 3 このように配列が UNNEST() されると、各要素が1行1行に割り振られた「テーブル形式」になることが分かります。先程の WHERE 句では UNNEST() で subjects 列の中身を分解してテーブル化し、その結果の中に "理科" が含まれているかを IN 演算子で検査して、TRUE となった行だけを返したのです。 参考 : 配列内の要素をテーブル内の行に変換する SELECT 〜 CROSS JOIN 配列型を含むテーブルに自在にフィルタを行うには、UNNEST() と CROSS JOIN を使いこなす必要があります。 一例を示します。 SELECT name, unnested_subject FROM t0 CROSS JOIN UNNEST(subjects) AS unnested_subject; (行番号) name unnested_subject 1 田中 太郎 国語 2 田中 太郎 算数 3 田中 太郎 理科 4 田中 太郎 社会 5 鈴木 二郎 国語 6 鈴木 二郎 算数 上記のクエリでは元テーブルの全行に対して1行ずつ「subjects を UNNEST して返ってきたテーブル」を CROSS JOIN しています。これにより、配列が分解されて通常の第1正規化されたテーブルのようになり、WHERE でフィルタできます。 SELECT (SELECT ~ UNNEST) 以下のようなクエリも用いることができます。 SELECT name, ( SELECT * FROM UNNEST(subjects) AS u WHERE u = " 理科 " ) AS subject_science FROM t0; (行番号) name subject_science 1 田中 太郎 理科 2 鈴木 二郎 null SELECT 句内のサブクエリの SELECT は、UNNEST() した subjects 列を対象としており、その結果は WHERE で "理科" だけに絞られています。 subjects 列が "理科" の値を持っていない行は null として返ります。 ただしこの例は、 (SELECT * FROM UNNEST(subjects) AS u WHERE u = "理科") の結果が単一行だけ返る (スカラ値である) ことが前提です。もし配列に "理科" が複数ある場合、 Scalar subquery produced more than one element エラーが生じてしまいます。 例えば以下のように、データが重複してしまっているテーブルの場合です。 (行番号) name subjects 1 田中 太郎 国語 算数 理科 社会 2 鈴木 二郎 国語 算数 3 三中 三郎 国語 理科 理科 三中 三郎の subjects 列に理科が2行あるため、UNNEST に対する SELECT 結果が2行になってしまい、クエリが失敗します。 このようなデータの不整合がある可能性に対応するには、以下のようにします。 SELECT name, ( SELECT DISTINCT * FROM UNNEST(subjects) AS u WHERE u = " 理科 " ) AS subject_science FROM t0; (行番号) name subjects 1 田中 太郎 理科 2 鈴木 二郎 null 3 三中 三郎 理科 DISTINCT することで返却結果が一意に絞られ、エラーになりません。 CREATE TABLE / INSERT 順序としてはあべこべですが、ARRAY を持つ表の CREATE TABLE および INSERT 文も紹介します。 CREATE TABLE はシンプルです。ARRAY の列を ARRAY<(型名)> として定義するのみです。 CREATE TABLE `my-project.my_dataset.t0` ( name STRING, subjects ARRAY<STRING> ); INSERT 文は以下です。 INSERT `my-project.my_dataset.t0` VALUES ( " 鈴木 二郎 " , [ " 国語 " , " 算数 " ]); 上記の ["国語", "算数"] を ARRAY["国語", "算数"] や ARRAY<STRING>["国語", "算数"] のように表現することもできます (意味は変わりません)。 制限 配列の配列を作ることはできません。つまり、以下のようにネストした配列は作れません。 SELECT [ " hogehoge " , [ " foo " , " bar " ]]; Cannot construct array with element type ARRAY<STRING> because nested arrays are not supported at [2:16] 一方で配列の中に、後に紹介する STRUCT 型は入れることができます。これが Google Analytics 4 の BigQuery Export 等で見られる独特な構成です。これについては後に解説します。 SELECT [ STRUCT( " hoge01 " AS f1, " fuga01 " AS f2), STRUCT( " hoge02 " , " fuga02 " ) ] AS arrayed_struct; (行番号) arrayed_struct.f1 arrayed_struct.f2 1 hoge01 fuga01 hoge02 fuga02 STRUCT (構造体) STRUCT とは BigQuery の STRUCT (構造体) 型は、構造を持った型で、一つ以上のフィールドを持つことができます。 例えば以下の表では、item という列が STRUCT 型で、id という INT64 型のフィールドと、name という STRING 型のフィールドを持っています。 price item.id item.name 3000 10001 T-shirt 8000 20001 jacket STRUCT はデータを構造的に整理するために有用です。 参考 : Struct type 参考 : 構造体リテラル サンプルテーブル STRUCT 型を持つテーブルの例として、以下の WITH 句を仮想的なサンプルテーブルとして使います。 school 列が STRUCT 型で、フィールドとして year (INT64 型) と class (STRING 型) を持っています。 WITH t1 AS ( SELECT " 田中 太郎 " AS name, STRUCT( 1 AS year, " B " AS class) AS school UNION ALL SELECT " 鈴木 二郎 " AS name, STRUCT( 2 AS year, " C " AS class) AS school ) SELECT * FROM t1; (行番号) name school.year school.class 1 田中 太郎 1 B 2 鈴木 二郎 2 C SELECT STRUCT 型に対する SELECT は、他の通常の型と大きく変わらないため、直感的に理解できます。 このようなテーブルに対するクエリは以下のようになります。 SELECT name, school FROM t1; (行番号) name school.year school.class 1 田中 太郎 1 B 2 鈴木 二郎 2 C school という列名を指定するだけで、配下のフィールドの全てが選択されます。 以下のように、フィールド名を明示して SELECT することも可能です。 SELECT name, school.year FROM t1; (行番号) name year 1 田中 太郎 1 2 鈴木 二郎 2 なおこの場合、返却結果の列名はフィールド名だけになります。 SELECT 〜 WHERE ARRAY と異なり、STRUCT 型への WHERE 句の使用は直感的です。 SELECT name, school FROM t1 WHERE school.year = 1 ; (行番号) name school.year school.class 1 田中 太郎 1 B WHERE 句でフィールドに対して条件を指定するだけで、フィルタをすることができます。 CREATE TABLE / INSERT STRUCT 型を持つテーブルの CREATE TABLE 文は、以下のように記述します。STRUCT<(フィールド名) (型名), (フィールド名) (型名), ...> のように各フィールドの名前と型を指定します。 CREATE TABLE `my-project.my_dataset.t1` ( name STRING, school STRUCT<year INT64, class STRING> ); INSERT 文は以下です。 INSERT INTO `my-project.my_dataset.t1` VALUES ( " 鈴木 二郎 " , STRUCT( 2 AS year, " C " AS class)); なお AS year AS class のようなフィールド名指定は省略可能で、実は可読性を高める以外の意味はありません。フィールド名を指定したところで記載順番が優先されます。すなわち上記を "C" AS class, 2 AS year と書き換えると、型エラーになります。逆に、型が同じだと意図しない列に値が入ってしまいます。 以下のように簡易的に記述することもできます。 INSERT INTO `my-project.my_dataset.t1` VALUES ( " 鈴木 二郎 " , ( 2 , " C " )); 制限 STRUCT 型はネストすることができますが、最大で15段階までです。 ネストした STRUCT 型の例は以下です。 SELECT STRUCT( 1001 AS f_int, " hoge " AS f_string, STRUCT( " foo " AS f1, " bar " AS f2 ) AS f_struct ) AS root; (行番号) root.f_int root.f_string root.f_struct.f1 root.f_struct.f2 1 1001 hoge foo bar ARRAY<STRUCT> (ネストされた繰り返し列) ARRAY<STRUCT> とは ARRAY<STRUCT> (ネストされた繰り返し列) とはここまで紹介した ARRAY と STRUCT を組み合わせたものです。 ARRAY の列の中に、要素として STRUCT 型が入っているものです。Google Analytics 4 (Firebase) や Google Cloud の Billing Export でこの形式が見られます。 実例としては、以下のようなものです。 (行番号) name classes.subject classes.teacher 1 田中 太郎 国語 斉藤 三郎 英語 伊東 四朗 2 鈴木 二郎 英語 伊東 四朗 classes 列は ARRAY (配列) 型ですが、その各要素は subject と teacher というフィールドを持つ STRUCT 型です。 参考 : テーブル スキーマでネストされた列と繰り返し列を指定する サンプルテーブル サンプルテーブルとして、以下の WITH 句を使って試してください。 classes 列が「ネストされた繰り返し列」です。配列であり、各要素は subject という STRING 型フィールドと teacher という STRING 型フィールドを持った STRUCT です。 WITH t2 AS ( SELECT " 田中 太郎 " AS name, [ STRUCT( " 国語 " AS subject, " 斉藤 三郎 " AS teacher), STRUCT( " 英語 " AS subject, " 伊東 四朗 " AS teacher) ] AS classes UNION ALL SELECT " 鈴木 二郎 " AS name, [ STRUCT( " 英語 " AS subject, " 伊東 四朗 " AS teacher) ] AS classes ) SELECT * FROM t2; (行番号) name classes.subject classes.teacher 1 田中 太郎 国語 斉藤 三郎 英語 伊東 四朗 2 鈴木 二郎 英語 伊東 四朗 SELECT classes 列を指定して SELECT することは可能です。 SELECT name, classes FROM t2; しかし、以下のように classes 列のフィールドを指定してクエリしようとすると、エラーになります。 SELECT name, classes.subject FROM t2; Cannot access field subject on a value with type ARRAY<STRUCT<subject STRING, teacher STRING>> at [18:11] classes は ARRAY です。classes 列の subject だけを取り出したい場合、以下のように UNNEST() してテーブル化し、そこから subject 列だけを取り出すことができます。ARRAY を先頭につけないと、単体の値 (スカラ値) が返ってくることが期待され Scalar subquery produced more than one element になってしまうため、ARRAY() として戻りが配列であることを明示します。 SELECT name, ARRAY( SELECT subject FROM UNNEST(classes)) AS subject FROM t2; (行番号) name subject 1 田中 太郎 国語 英語 2 鈴木 二郎 英語 SELECT 〜 WHERE (エラー) WHERE を使ったフィルタも独特です。以下のクエリはエラーになります。 SELECT name, classes FROM t2 WHERE classes.subject = " 国語 " ; Cannot access field subject on a value with type ARRAY<STRUCT<subject STRING, teacher STRING>> at [22:11] 先程と同じ理由で、配列である classes の一要素の subject フィールドにはアクセスできません。 ARRAY<STRUCT> をフィルタするには、次に示すようなクエリを用います。 SELECT 〜 CROSS JOIN 以下のクエリは通ります。 SELECT name, c.subject, c.teacher FROM t2 CROSS JOIN UNNEST(classes) AS c WHERE c.subject = " 国語 " ; (行番号) name subject teacher 1 田中 太郎 国語 斉藤 三郎 ARRAY である classes 列を毎行 unnest して CROSS JOIN し、第1正規化された状態のテーブルに WHERE でフィルタをかけています。 SELECT (SELECT ~ UNNEST) 以下ようなクエリもできます。 SELECT name, ( SELECT AS STRUCT subject, teacher FROM UNNEST(classes) WHERE subject = " 国語 " ) AS class FROM t2; (行番号) name class.subject class.teacher 1 田中 太郎 国語 斉藤 三郎 2 鈴木 二郎 null null こちらもやっていることは似ており、SELECT 句の中のサブクエリで毎行 classes を UNNEST して subject と teacher を取り出し、その結果を WHERE 句で絞っています。 SELECT で指定する列は単一の値 (スカラ値) を期待するので SELECT AS STRUCT を使うことで、戻りが STRUCT であることを明示的に指示しています。 AS STRUCT をつけないと以下のようなエラーになります。 Scalar subquery cannot have more than one column unless using SELECT AS STRUCT to build STRUCT values at [18:3] もしくは AS STRUCT をつけなくても、SELECT する列が subject か teacher の一つだけであればエラーになりません。 CREATE TABLE / INSERT ARRAY<STRUCT> の CREATE TABLE 文は以下のようになります。 CREATE TABLE `my-project.my_dataset.t2` ( name STRING, classes ARRAY< STRUCT< subject STRING, teacher STRING > > ); INSERT 文は以下です。 INSERT `my-project.my_dataset.t2` VALUES ( " 田中 太郎 " , [ STRUCT( " 国語 " AS subject, " 斉藤 三郎 " AS teacher ), STRUCT( " 英語 " AS subject, " 伊東 四朗 " AS teacher ) ] ); なお通常の STRUCT 型と同じで AS subject AS teacher のようなフィールド名の指定は省略可能で、むしろスキーマ定義と同じ順番で記載する必要があります。 実践 : Google Analytics 4 データへのクエリ 概要 Google Analytics 4 (GA4) や Firebase ではアクセス情報を BigQuery にエクスポートすることができます。簡単な設定で BigQuery に定期的にデータを吐き出してくれるので便利ですが、そのスキーマには当記事で紹介した ARRAY<STRUCT> が使われており、クエリの仕方が独特です。 当項目では、GA4 のエクスポートデータのテーブルを模したテーブルに対するクエリの方法を簡単にご紹介します。 参考 : [GA4] BigQuery Export 参考 : [GA4] BigQuery Export スキーマ 参考 : Firebase の BigQuery Export テーブル例 以下のような模擬テーブルを用います。 フィールド名 種類 モード event_timestamp INTEGER NULLABLE event_name STRING NULLABLE event_params RECORD (=STRUCT) REPEATED (=ARRAY) ├ key STRING NULLABLE └ value RECORD (=STRUCT) NULLABLE  ├ string_value STRING NULLABLE  ├ int_value INTEGER NULLABLE  ├ float_value FLOAT NULLABLE  └ double_value FLOAT NULLABLE データは以下のように入っています。 GA4 データを模したテーブル クエリ例1: 特定ページの PV 数を集計 特定ページの PV 数を計測するため event_name が "page_view" で、かつ page_location が "https://blog.g-gen.co.jp/entry/deploy-preview-using-cloud-run-tagged-revision" という文字列となっているレコードを選択したいとします。 以下のようにしたいところですが、エラーになります。 SELECT COUNT (*) AS pv FROM `my-project.my_dataset.ga4_mock` WHERE event_name = " page_view " AND event_params.value.string_value = " https://blog.g-gen.co.jp/entry/deploy-preview-using-cloud-run-tagged-revision " ; Cannot access field value on a value with type ARRAY<STRUCT<key STRING, value STRUCT<string_value STRING, int_value INT64, float_value FLOAT64, ...>>> at [8:16] フィルタ対象の event_params は ARRAY であり、その要素である event_params.value は STRUCT 型でありそのフィールドの一つが string_value です。どのようにクエリすれば良いのか、頭がこんがらがってしまいます。 以下のようなクエリが通ります。 SELECT COUNT (*) AS pv FROM `my-project.my_dataset.ga4_mock` WHERE event_name = " page_view " AND " https://blog.g-gen.co.jp/entry/deploy-preview-using-cloud-run-tagged-revision " IN ( SELECT value.string_value FROM UNNEST (event_params) WHERE key = " page_location " ) (行番号) pv 1 1 このクエリでは、event_name 列が "page_view" の行に対し、配列である event_param 列を UNNEST して平準化テーブルとし、その中で key が "page_location" である行の value.string_value フィールドを IN で検査しています。 また別案として、以下のようなビューを作ってしまうのも手です。 SELECT event_timestamp, event_name, ( SELECT value.string_value FROM UNNEST(event_params) WHERE key = " page_location " ) AS page_location FROM `my-project.my_dataset.ga4_mock` WHERE event_name = " page_view " ; (行番号) event_timestamp event_name page_location 1 1695781266341693 page_view https://blog.g-gen.co.jp/entry/deploy-preview-using-cloud-run-tagged-revision このように page_view イベントの page_location 値のビューだけを作ってしまえば、あとは一般的な SQL でクエリできます。 CREATE VIEW AS でビューを作るか、一時的・探索的なクエリなら WITH 句を使っても良いでしょう。 WITH unnested_view AS ( SELECT event_timestamp, event_name, ( SELECT value.string_value FROM UNNEST(event_params) WHERE key = " page_location " ) AS page_location FROM `my-project.my_dataset.ga4_mock` WHERE event_name = " page_view " ) SELECT COUNT (*) AS pv FROM unnested_view WHERE page_location = " https://blog.g-gen.co.jp/entry/deploy-preview-using-cloud-run-tagged-revision " ; (行番号) pv 1 1 上記のように UNNEST して平坦化した状態をデータマートやビューとして持っておけば、BI ツールや Connected Sheets からも利用しやすくなります。 このように ARRAY 型や ARRAY<STRUCT> 型は、SELECT 句または WHERE 句のサブクエリで UNNEST() 関数を使うことで、自在に扱うことができます。 クエリ例2 : string_value を取り出す関数を作る 前述の例だとサブクエリが長く、可読性に劣ります。UNNEST() する処理を関数に切り出して可読性を高めてみます。 CREATE TEMP FUNCTION getStringValue(col ANY TYPE , col_key STRING) AS ( ( SELECT c.value.string_value FROM UNNEST(col) c WHERE c.key = col_key) ); SELECT event_timestamp, event_name, getStringValue(event_params, " page_title " ) AS page_title, getStringValue(event_params, " page_location " ) AS page_location FROM `my-project.my_dataset.ga4_mock` 結果は以下のようになります。 (行番号) event_timestamp event_name page_title page_location 1 1695781266341693 page_view プルリクエストをトリガとするCloud Runのプレビュー環境自動デプロイを実装してみた - G-gen Tech Blog https://blog.g-gen.co.jp/entry/deploy-preview-using-cloud-run-tagged-revision 2 1695781266341693 first_visit プルリクエストをトリガとするCloud Runのプレビュー環境自動デプロイを実装してみた - G-gen Tech Blog https://blog.g-gen.co.jp/entry/deploy-preview-using-cloud-run-tagged-revision スキーマ表記 概要 BigQuery でのスキーマ表記は「SQL 上の表記」と「Web コンソールや JSON 形式での表記」が異なる場合があります。 例えば前述の ARRAY<STRUCT> は「タイプが RECORD でモードが REPEATED」のように表現されます。 参考 : スキーマの指定 以下に参考情報として記載します。 ARRAY BigQuery コンソール上や JSON 形式でのスキーマ表現では、ここまで扱ったような ARRAY は以下のように「種類が (配列内のデータの型名) でモードが REPEATED 」として表現されます。 配列は「モード」が REPEATED になっている { 〜略〜 " schema ": { " fields ": [ { " name ": " name ", " type ": " STRING " } , { " mode ": " REPEATED ", " name ": " subjects ", " type ": " STRING " } ] } , 〜略〜 } STRUCT BigQuery コンソール上や JSON 形式でのスキーマ表現では、STRUCT は以下のように「種類が RECORD でモードが NULLABLE/REQUIRED」として表現されます。 STRUCT は RECORD という種類として表記 { 〜略〜 " schema ": { " fields ": [ { " name ": " name ", " type ": " STRING " } , { " fields ": [ { " name ": " year ", " type ": " INTEGER " } , { " name ": " class ", " type ": " STRING " } ] , " name ": " school ", " type ": " RECORD " } ] } , 〜略〜 } ARRAY<STRUCT> BigQuery コンソール上や JSON 形式でのスキーマ表現では、 ARRAY<STRUCT> は以下のように「種類が RECORD でモードが REPEATED 」として表現されます。RECORD は STRUCT と、REPEATED は ARRAY と同義です。 「種類」が RECORD (=STRUCT)、「モード」が REPEATED (=ARRAY) JSON では以下のようになります。 { 〜略〜 " schema ": { " fields ": [ { " name ": " name ", " type ": " STRING " } , { " fields ": [ { " name ": " subject ", " type ": " STRING " } , { " name ": " teacher ", " type ": " STRING " } ] , " mode ": " REPEATED ", " name ": " classes ", " type ": " RECORD " } ] } , 〜略〜 } 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の藤岡です。当記事では Google Cloud(旧称 GCP)で「ドメイン別の ID の制限」の組織ポリシー適用下で Cloud Run サービスを一般公開する方法を紹介します。 前提知識 「ドメイン別の ID の制限」の組織ポリシー Cloud Run 2つのアクセス制御レイヤー サービスを一般公開する方法 注意点 タグがサポートされているサービス Config Controller は未対応 Cloud Run サービスの一般公開 アーキテクチャ 前提 権限 設定手順 組織管理者:「ドメイン別の ID の制限」の条件付き組織ポリシーを適用 組織管理者:タグキーとタグ値を作成 プロジェクト管理者:Cloud Run の作成 組織管理者:Cloud Run にタグバインディング プロジェクト管理者:Cloud Run に allUsers 許可 エラー例 前提知識 「ドメイン別の ID の制限」の組織ポリシー Google Cloud には、組織やフォルダ、プロジェクトに対して統制を効かせるための 組織ポリシー 機能があります。 組織ポリシーの制約の1つに ドメイン別の ID の制限 ( constraints/iam.allowedPolicyMemberDomains )があり、これは誤ってまたは悪意を持って自組織以外の Google アカウントが IAM 権限を持たないようにする制約です。(「ドメインで制限された共有」と表記される場合も有り) 以下のように、許可する Google Workspace お客様 ID または Google Cloud の組織リソース ID を指定します。 ドメイン別の ID の制限 リソースに特定のタグが付与されている場合は組織ポリシーの制約を適用しない、という条件を含めた設定もできます。当記事では条件が設定された組織ポリシーを 条件付き組織ポリシー と表記します。 参考: タグを使用した組織のポリシーの設定 タグについては以下の記事をご参照ください。 blog.g-gen.co.jp Cloud Run 2つのアクセス制御レイヤー Cloud Run には2つのアクセス制御レイヤーがあります。 Cloud Run サービスに到達するには、Ingress と IAM の両方で許可されている必要があります。 Cloud Run のアクセス制御レイヤー レイヤー名 仕様 Ingress ・ 通信元 に基づいてリクエストをフィルタリング ( ネットワーク的な制御 ) ・通信元が設定された、内部もしくはすべての場合に許可される ・組織ポリシー「 許可される上り 」( constraints/run.allowedIngress )で制御可能 IAM ・ 送信者 に基づいてリクエストをフィルタリング ( 認証・認可的な制御 ) ・送信者に Cloud Run 起動元ロール( roles/run.invoker )が付与されていると許可される ・組織ポリシー「ドメイン別の ID の制限」で制御可能 Cloud Run でサービスを一般公開する場合、Cloud Run 起動元ロール( roles/run.invoker )を allUsers に割り当てる必要があります。 しかし、前述の「ドメイン別の ID の制限」の組織ポリシーの適用下では allUsers に IAM ロールを付与できません。 参考: ドメインで制限された共有 サービスを一般公開する方法 「ドメイン別の ID の制限」の組織ポリシーの適用下で Cloud Run サービスを一般公開(つまり allUsers に Cloud Run 起動元ロールを付与)する方法として、以下の2つがあります。 「ドメイン別の ID の制限」の組織ポリシーを一時的に削除する タグと条件付き組織ポリシーを使う 方法1の場合、以下のようなフローとなります。 一時的に「ドメイン別の ID の制限」の組織ポリシーを削除 → Cloud Run を 未認証の呼び出しを許可 にしデプロイ( allUsers に Cloud Run 起動元ロールが割当たる) → 「ドメイン別の ID の制限」の組織ポリシーを適用 但し、組織ポリシーを削除することは一時的とは言えセキュリティリスクが高まるため2の方法が推奨されます。 当記事では、タグと条件付き組織ポリシーを使うことで「ドメイン別の ID の制限」の組織ポリシー適用下でも Cloud Run サービスを一般公開する方法を紹介します。 注意点 タグがサポートされているサービス タグがサポートされているリソースは ドキュメント に記載の通りです。 2023 年 10 月執筆時点では、 Cloud Functions はサポートされていません 。 但し、Cloud Functions 第2世代や Cloud Functions for Firebase 第2世代は Cloud Run 上で起動するため、当記事で紹介する方法でサービスを一般公開できます。 Config Controller は未対応 条件付き組織ポリシーを使うには、Organization Policy API V2 が必要です。 しかし 2023 年 10 月執筆時点では、Config Controller では Cloud Resource Manager API V1 のみの対応となっているため、条件付き組織ポリシーは使えません。 他の IaC ツールとしてよく使われる Terraform では google_org_policy_policy で条件付き組織ポリシーが使えます。 Cloud Run サービスの一般公開 アーキテクチャ タグと条件付き組織ポリシーを適用した際のアーキテクチャは以下の通りです。 アーキテクチャ 前提 Google Cloud を企業で利用する場合、「組織の管理者」と「各プロジェクトでリソースを管理するユーザー」は異なる場合が多く、また必要な権限も異なります。 後述の設定手順では実際に企業で使う場合を想定し、組織の管理者が行う作業とプロジェクトの管理者が行う作業を項目の箇所に記載しています。 権限 本構成で組織の管理者に必要な組織レベルのロールは以下の通りです。 組織ポリシーを設定:組織ポリシー管理者( roles/orgpolicy.policyAdmin ) タグの作成:タグ管理者( roles/resourcemanager.tagAdmin ) タグをリソースにバインディング:タグユーザー( roles/resourcemanager.tagUser ) 設定手順 組織管理者:「ドメイン別の ID の制限」の条件付き組織ポリシーを適用 ここでは Cloud Shell で実行します。コンソールからでも設定可能です。 drs-policy.yaml ファイルを作成します(ファイル名は任意)。 ORGANIZATION_ID と DIRECTORY_CUSTOMER_ID は置き換えてください。 # drs-policy.yaml name : organizations/ORGANIZATION_ID/policies/iam.allowedPolicyMemberDomains spec : rules : - values : allowedValues : - DIRECTORY_CUSTOMER_ID - allowAll : true condition : expression : resource.matchTag("ORGANIZATION_ID/allUsersIngress", "True" ) title : allowAllUsersIngress drs-policy.yaml ファイルを保存し、適用します。 $ gcloud org-policies set-policy drs-policy.yaml これによって、タグキー allUsersIngress の値が True のタグがバインディングされているリソースに対して「ドメイン別の ID の制限」で許可されているドメインに関わらず、IAM ロールを付与できるようになります。 適用後、以下のように allowedValues で定義した Google Workspace お客様 ID とタグの条件式が設定されています。 適用後の組織ポリシー 組織管理者:タグキーとタグ値を作成 タグキー ( allUsersIngress ) を作成します。 $ gcloud resource-manager tags keys create allUsersIngress \ --parent=organizations/ORGANIZATION_ID 以下のようにタグキーが作成されます。 作成されたタグキー 作成したタグキーにタグ値( True )を追加します。TAGKEY_ID は作成したタグキー ID (例: tagKeys/123456 ) に置き換えてください。 $ gcloud resource-manager tags values create True \ --parent=TAGKEY_ID \ --description="Allow for allUsers for internal Cloud Run services" 以下のようにタグ値が追加されます。 追加されたタグ値 参考: タグの作成と管理 プロジェクト管理者:Cloud Run の作成 ここではイメージにサンプルコンテナを使い、初回は 認証が必要 でデプロイします。 サービスの作成画面 ここで、 未認証の呼び出しを許可 でデプロイすると以下のエラーが表示されます。 サービスが作成されましたが、一般アクセスできない可能性があります。リソース「projects/xxxx/locations/asia-northeast1/services/hello」に対して IAM ポリシーを設定できませんでした。ロール「roles/run.invoker」を次のプリンシパルに割り当てることができませんでした: allUsers。詳細: One or more users named in the policy do not belong to a permitted customer, perhaps due to an organization policy. デプロイ時のエラー画面 サービス URL のエラー画面 組織管理者:Cloud Run にタグバインディング 作成した Cloud Run にタグをバインディングします。 TAGVALUE_ID は追加したタグ値(例: tagValues/1234567890 )に置き換えてください。 $ gcloud resource-manager tags bindings create \ --tag-value=TAGVALUE_ID \ --parent=//run.googleapis.com/projects/PROJECT_ID/locations/REGION/services/SERVICE_NAME \ --location=REGION タグバインディングをすると、コンソールから以下のように表示されます。 タグバインディング後の Cloud Run プロジェクト管理者:Cloud Run に allUsers 許可 最後に、 未認証の呼び出しを許可 とするため allUsers に Cloud Run 起動元ロールを付与します。 $ gcloud run services add-iam-policy-binding SERVICE_NAME \ --region=REGION \ --member="allUsers" \ --role="roles/run.invoker" コンソールから確認すると、以下のように未認証の呼び出しが許可されています。 未認証の呼び出しが許可された Cloud Run サービス URL へ問題なくアクセスできます。 サービス画面 エラー例 「ドメイン別の ID の制限」の組織ポリシー適用下で、許可されていないドメインのユーザーへ IAM ロールを付与しようとすると以下のエラーとなります。 IAM ポリシーの更新に失敗しました ドメイン制限の組織ポリシーがあります。ポリシーでプリンシパルとして追加できるのは、許可されたドメインのプリンシパルのみです。プリンシパルのメールアドレスを修正して、もう一度お試しください。 エラー画面 藤岡 里美 (記事一覧) クラウドソリューション部 接客業からエンジニアへ。2022年9月 G-gen にジョイン。Google Cloud 認定資格は全冠。ラーメンと甘いものが好きです :) Follow @fujioka57621469
アバター
G-gen の佐々木です。当記事では Cloud Run で Cloud Storage FUSE を使用して、オブジェクトストレージである Cloud Storage のバケットをコンテナ内のディレクトリにマウントしてみます。 前提知識 Cloud Run とは Cloud Storage(GCS)とは Cloud Storage FUSE について Cloud Storage FUSE とは 制限事項 料金 ネイティブ機能によるマウント 考慮事項 Cloud Run 実行環境 マルチプロセス化による PID 1 問題への対処 Cloud Run で Cloud Storage FUSE を使用してみる 構成図 Cloud Storage バケットの作成 Artifact Registry リポジトリの作成 使用するコード main.go gcsfuse_run.sh Dockerfile コンテナイメージのビルド・プッシュ Cloud Run サービスのデプロイ 動作確認 前提知識 Cloud Run とは Cloud Run は Google Cloud のマネージドなコンテナ実行環境を使用してアプリケーションを実行することができるサーバレス コンテナコンピューティング サービスです。 HTTP リクエストを処理のトリガーとする Cloud Run services と、手動もしくはスケジュール、ワークフローをトリガーとする Cloud Run jobs の 2種類があります。 それぞれ以下の記事で詳細を解説しています。 blog.g-gen.co.jp blog.g-gen.co.jp Cloud Storage(GCS)とは Cloud Storage は容量無制限のオブジェクトストレージサービスであり、99.999999999% (イレブンナイン) の堅牢性を持つオブジェクトストレージを安価に利用することができます。 Cloud Storage の詳細は以下の記事で解説しています。 blog.g-gen.co.jp Cloud Storage FUSE について Cloud Storage FUSE とは Cloud Storage FUSE は Cloud Storage バケットをローカルファイルシステムとしてマウントしてアクセスできるようにする FUSE (Filesystem in Userspace) アダプタであり、Google がサポートするオープンソースのプロダクトです。これを使用することで、アプリケーションから通常のファイルシステム同様にバケット内のオブジェクトを読み書きすることができるようになります。 Cloud Storage FUSE は、Cloud Storage バケットに格納されたオブジェクトの名前をファイルとディレクトリに変換します。オブジェクトの名前に含まれているスラッシュ(/)をディレクトリの区切りとすることで、仮想的なディレクトリ構成を使用してアプリケーションからファイルにアクセスできるようにします(以下の例を参照)。 これにより、アプリケーションは Cloud Storage の無制限のストレージをファイルシステムと同様に利用することができます。 # Cloud Storage バケットの状態 bucket ├ aaa/aaa-0.txt ├ aaa/aaa-1.txt ├ bbb/bbb-0.txt └ bbb/bbb-1.txt # アプリケーションからの見え方 bucket/ ├ aaa/ │ ├ aaa-0.txt │ └ aaa-1.txt └ bbb/  ├ bbb-0.txt  └ bbb-1.txt 参考 : Cloud Storage FUSE 制限事項 Cloud Storage FUSE によってマウントされるファイルシステムの制限事項をいくつか記載します。 その他の制限事項については ドキュメント をご一読ください。 Cloud Storage FUSE は POSIX に準拠していません。POSIX 準拠のファイルシステムとしては、Google Cloud からは Filestore が提供されています。 Cloud Storage FUSE が Cloud Storage にファイルをアップロードする際、 オブジェクトのメタデータ を設定することはできません。メタデータを設定する必要がある場合は、コンソールや CLI、API を使用して Cloud Stroage にオブジェクトを直接アップロードします。 Cloud Storage FUSE を使用して同じファイルに対して同時に複数の書き込みを行った場合、最後の書き込みだけが有効となり、それ以前の書き込みはすべて失われます(同時実行制御ができない)。 Cloud Storage FUSE ではハードリンクを使用することができません。 マウントされたファイルシステムへのアクセスには Cloud Storage バケットのアクセス権( roles/storage.objectUser など)が必要となります。 料金 Cloud Storage FUSE は無料で利用できますが、これを利用することによって Cloud Storage バケットに保存されるオブジェクトやネットワーク I/O は、通常の Cloud Storage の利用料として料金が発生します。 参考 : Cloud Storage FUSE - Cloud Storage FUSE の料金 参考 : Cloud Storage pricing ネイティブ機能によるマウント アップデートにより、FUSE の設定を意識することなく Cloud Storage バケットをマウントできるようになったため、基本的にはこちらを使用することを推奨します。 ネイティブ機能によるマウント方法については以下の記事で解説しています。 blog.g-gen.co.jp 考慮事項 Cloud Run 実行環境 Cloud Storage FUSE は Cloud Run services、Cloud Run jobs の両方で使用できます。 Cloud Run services では第1世代と第2世代の 実行環境 があり(Cloud Run jobs は第2世代のみ)、ネットワークファイルシステムがサポートされるのは第2世代のみとなっています。 そのため、Cloud Storage FUSE を使用する場合は第2世代の Cloud Run を使用します。 マルチプロセス化による PID 1 問題への対処 通常、コンテナでは単一のプロセス(アプリケーション)が実行されますが、Cloud Storage FUSE を使用する場合、アプリケーションのほかにファイルシステムへのマウントプロセスが実行されます。このようなマルチプロセスのコンテナでは、コンテナのエントリポイントとして実行されるアプリケーションに PID 1が割り当てられることで、その他のプロセス(ここではファイルシステムへのマウント)の終了処理が適切に行われない問題( PID 1問題 )が発生してしまいます。 この問題を適切に処理するために、コンテナのエントリポイントとして複数のプロセスを管理するプロセスマネージャーを実行し、そこからアプリケーションやファイルシステムのマウントプロセスを実行します。 このブログでは公式ドキュメントの チュートリアル に従い、プロセスマネージャーとして Tini を使用するコンテナを作成していきます。 PID 1 問題については以下の記事でわかりやすく解説されています。 参考 : コンテナ内で大量のゾンビプロセスが発生していた話 (※外部ブログ) Cloud Run で Cloud Storage FUSE を使用してみる 基本的には 公式ドキュメントのチュートリアル に従って進めていきます。チュートリアルには Node.js、Python、Java のアプリケーションの例がありますが、当ブログでは Go を使用していきます。 構成図 当記事では、Cloud Run にデプロイするコンテナに /mnt/gcs/ ディレクトリを作成し、Cloud Storage FUSE を使用して Cloud Storage バケットをマウントします。 Cloud Run で Cloud Storage FUSE を使用する Cloud Storage バケットの作成 ファイルシステムとして使用する Cloud Storage バケットを作成します。 バケット名はグローバルに一意の値を指定する必要があります。 # Cloud Storage バケットを作成する $ gcloud storage buckets create gs://mybucket --location asia-northeast1 Artifact Registry リポジトリの作成 Cloud Run にデプロイするコンテナイメージを格納するための Artifact Registry リポジトリを作成します。 # Artifact Registry リポジトリを作成する $ gcloud artifacts repositories create myrepo \ --repository-format = docker \ --location = asia-northeast1 使用するコード main.go Cloud Storage バケットをマウントしたディレクトリからテキストファイルを読み取り、ブラウザに表示するだけの簡単な Web アプリケーションを作成します。 package main import ( "fmt" "log" "net/http" "os" ) func readGCS() ( string , error ) { // Cloud Storage FUSE をマウントしたディレクトリからテキストファイルを読み取る f, err := os.Open( "/mnt/gcs/" + "test.txt" ) if err != nil { return "" , err } defer f.Close() text := make ([] byte , 1024 ) count, err := f.Read(text) if err != nil { return "" , err } return string (text[:count]), nil } func readGCSHandler(w http.ResponseWriter, r *http.Request) { text, err := readGCS() if err != nil { log.Print(err) http.Error(w, err.Error(), 500 ) } else { // 読み取ったテキストファイルの中身を表示 fmt.Fprintf(w, "%s" , text) } } func main() { log.Print( "starting server..." ) http.HandleFunc( "/" , readGCSHandler) port := os.Getenv( "PORT" ) if port == "" { port = "8080" log.Printf( "defaulting to port %s" , port) } log.Printf( "listening on port %s" , port) if err := http.ListenAndServe( ":" +port, nil ); err != nil { log.Fatal(err) } } gcsfuse_run.sh Cloud Storage FUSE を使用してコンテナインスタンスに Cloud Storage バケットをマウントしたあと、アプリケーションを実行するスクリプトです。 マウント対象の /mnt/gcs/ ディレクトリもここで作成しています。 #!/usr/bin/env bash set -eo pipefail # コンテナインスタンスに Cloud Storage バケットをマウントするディレクトリを作成 mkdir -p $MNT_DIR # Cloud Storage FUSE を使用してバケットをマウント echo " Mounting GCS Fuse. " gcsfuse --debug_gcs --debug_fuse $BUCKET $MNT_DIR echo " Mounting completed. " # Web アプリケーションの実行 /app/main Dockerfile Dockerfile ではアプリケーションの資材の配置のほか、Cloud Storage FUSE と Tini をインストールしています。 先述の PID 1 問題に対処するため、Tini を使用してマウントとアプリケーション、それぞれのプロセスを実行、管理するようにします。 FROM golang:1.21 WORKDIR /app # tini、gcsfuse をインストール RUN set -e ; \ apt-get update -y && apt-get install -y \ tini \ lsb-release ; \ gcsFuseRepo =gcsfuse- `lsb_release -c -s` ; \ echo " deb http://packages.cloud.google.com/apt $gcsFuseRepo main " | \ tee /etc/apt/sources.list.d/gcsfuse.list ; \ curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | \ apt-key add - ; \ apt-get update ; \ apt-get install -y gcsfuse \ && apt-get clean COPY main.go gcsfuse_run.sh ./ RUN go build -o main /app/main.go RUN chmod +x /app/gcsfuse_run.sh # Cloud Storage バケットをマウントするディレクトリをコンテナの環境変数に設定 ENV MNT_DIR /mnt/gcs # コンテナ実行時に Tini を実行 # https://github.com/krallin/tini ENTRYPOINT [ " /usr/bin/tini ", " -- " ] # ENTRYPOINT である Tini の引数としてスタートアップスクリプト(gcsfuse_run.sh)を指定 CMD [ " /app/gcsfuse_run.sh " ] コンテナイメージのビルド・プッシュ Cloud Build を使用してコンテナイメージをビルドし、Artifact Registry のリポジトリにプッシュします。 # Cloud Build を使用してコンテナイメージをビルド、プッシュする $ gcloud builds submit --region asia-northeast1 --tag asia-northeast1-docker.pkg.dev/myproject/myrepo/run-fuse Cloud Run サービスのデプロイ ビルドしたコンテナイメージを使用して Cloud Run サービスを作成します。 第 2世代の実行環境を使用するために --execution-environment で gen2 を指定しています。 環境変数として Cloud Storage のバケット名を指定します。この変数はコンテナインスタンスが立ち上がって gcsfuse_run.sh が実行された際、バケットをマウントするために使用されます。 # Cloud Run サービスをデプロイする $ gcloud run deploy run-fuse \ --image asia-northeast1-docker.pkg.dev/myproject/myrepo/run-fuse \ --execution-environment gen2 \ --region asia-northeast1 \ --allow-unauthenticated \ --set-env-vars BUCKET =mybucket 動作確認 Cloud Run 上のアプリケーションが、コンテナインスタンスのディレクトリにマウントされた Cloud Stroage バケットにあるファイルを読み込むことができるか確認します。 以下の内容のテキストファイル test.txt を Cloud Storage FUSE に設定したバケットに配置します。 Hello, FUSE! 以下のコマンドを使用してファイルをアップロードします。 # Cloud Storage バケットに test.txt をアップロードする $ gcloud storage cp test .txt gs://mybucket Cloud Run サービスの URL にアクセスすると、 test.txt の内容がブラウザに表示されます。 Cloud Storage にアップロードしたファイルの内容が表示される 佐々木 駿太 (記事一覧) G-gen最北端、北海道在住のクラウドソリューション部エンジニア 2022年6月にG-genにジョイン。Google Cloud Partner Top Engineer 2025 Fellowに選出。好きなGoogle CloudプロダクトはCloud Run。 趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。 Follow @sasashun0805
アバター
G-gen 又吉です。当記事では、Google Cloud Next '23 で発表された BigQuery DataFrames を解説します。BigQuery 上のデータを、pandas ライクな、また scikit-learn ライクなインターフェイスで操作できるライブラリです。 BigQuery DataFrames 概要 bigframes.pandas 概要 仕組み bigframes.ml 概要 自動前処理 概要 特徴の自動変換 欠損データの補完 制限事項 使ってみる やること 環境構築 初期設定 パッケージのインストール BigQuery セッションの設定 データのロード 前処理 特徴の変換 欠損値の対応 データ分割 モデルトレーニング 推論 モデル評価 モデルの保存 クリーンアップ 概要 BigQuery DataFrames とは、BigQuery API を介したデータの変換や機械学習を容易に行える Python のオープンソースパッケージです。 BigQuery DataFrames では、以下の 2 つの機能を提供します。 bigframes.pandas bigframes.ml 通常、機械学習モデルを構築する際、以下のようなフローが発生します。 BigQuery DataFrames を用いた機械学習モデル作成フロー BigQuery DataFrames を用いると、BigQuery 上のデータを pandas のような操作感で処理ができ、scikit-learn のような操作感でモデルトレーニングと評価、予測が行えます。 また、データの処理と保管を BigQuery 上で管理できるため、クライアントのマシンスペックやメモリ容量を気にせず開発ができます。 尚、BigQuery DataFrames は 2023 年 10 月現在プレビュー機能となります。 参考 : BigQuery DataFrames Python API 参考 : BigQuery DataFrames クイックスタート bigframes.pandas 概要 bigframes.pandas では、BigQuery 上のデータを pandas ライクに処理できます。一次元データを格納する Series クラスや、二次元データを格納する DataFrame クラスが用意されており、pandas でデータ処理を行うメソッドもほとんど用意されています。 仕組み bigframes.pandas の実態は、BigQuery API が裏側で実行されており、各メソッドを実行すると BigQuery にジョブを発行して BigQuery のコンピューティングリソースで処理し、またデータも BigQuery に保持します。つまり、クライアントのマシンスペックやメモリ容量を気にせず開発ができます。 例えば、サイズが約 60GB ある Wikipedia のページビューが格納された BigQuery サンプルテーブルを bigframes.pandas で処理してみたいと思います。 # input[0] df_sample = bqd.read_gbq( "bigquery-samples.wikipedia_pageviews.200809h" ) df_sample.head( 3 ) output[0] Open Job をクリックすると、実行された SQL を確認できます。 ジョブを確認 また、上記セルの実行前後で、クライアント側のメモリ使用量にはほとんど影響していないことから、60GB のデータはクライアント側に保存されていないことがわかります。 リソース使用状況 データをクライアントマシンにダウンロードしたいときは、 to_pandas メソッドを用いることでデータのダウンロードも可能です。 参考: Package pandas bigframes.ml 概要 bigframes.ml では、BigQuery ML API を scikit-learn ライクに操作することができます。 例えば、ほとんどのモデルに共通して以下のメソッドが用意されています。 fit : モデルトレーニング predict : 推論 score : モデル評価 サポートされているモデルも、回帰や分類、クラスタリングや次元削減といった基本的な機械学習モデルはもちろん、 Vertex AI PaLM API を利用した LLM モデルもサポートされています。 さらに、トレーニング後のモデルを to_gbq メソッドで BigQuery に保存することもできます。 参考: Train models 自動前処理 概要 bigframes.ml では、 BigQuery ML を用いてモデルトレーニングが行われるため、BigQuery ML の標準機能である 特徴量の自動前処理 を理解しておく必要があります。 自動前処理の主な機能は以下の通りです。 特徴の自動変換 欠損データの自動補完 また、 Preprocessing モジュールを用いることで、ユーザーが手動でデータの前処理を行うことも可能です。 特徴の自動変換 入力された特徴量は次のように自動変換されます。 No 入力データの型 変換方法 説明 1 INT64, NUMERIC, BIGNUMERIC, FLOAT64 標準化 各特徴量の最大と最小の幅が大きいと、特徴量をそのまま比較することが困難になるため、標準化を行うことで「平均値を 0 、標準偏差を 1」にして各特徴量のスケールを合わせる。 2 BOOL, STRING, BYTES, DATE, DATETIME, TIME one-hot encoding 数値や配列、TIMESTAMP 以外のデータ型では、ダミー変数用いて数値化します。 その他の入力データ型は以下の公式ドキュメントをご参照下さい。 参考: Feature transformations 欠損データの補完 欠損データ (NULL) がある際、列の型によって以下のように値が補完されます。 No 列の型 補完方法 1 Numeric 数値列の NULL 値は、元の入力列の平均値に置換します 2 One-hot/Multi-hot encoded 新規のカテゴリとして扱われます。つまり、NULL 値を持つデータは、新しいカテゴリとしてone-hot/Multi-hot encoding されます その他の列の型は以下の公式ドキュメントをご参照下さい。 参考: Missing data imputation 制限事項 基本的には、 BigQuery の割り当てと制限 に従いますが、他にも以下のような制限事項があります。 BigQuery セッション で指定しているロケーションと read_gbq / read_gbq_table / read_gbq_query で読み込むデータセットのロケーションは同じである必要があります。 bigframes.ml では、モデルトレーニングのサポートはロケーションによって異なります。詳細は BigQuery ML のロケーション をご覧ください。 使ってみる やること BigQuery DataFrames を用いて、機械学習モデルを構築します。 扱うデータは、BigQuery 公開データセットにある penguin テーブル を使用して、ペンギンの種類、居住島、くちばしの長さと深さ、足ひれの長さ、性別に基づいてペンギンの体重を予測する線形回帰モデルを作成します。 penguin テーブルのスキーマ情報は以下のとおりです。 No フィールド 型 モード 説明 1 species STRING REQUIRED ペンギンの種類 2 island STRING NULLABLE 居住島 3 culmen_length_mm FLOAT NULLABLE くちばしの長さ 4 culmen_depth_mm FLOAT NULLABLE くちばしの深さ 5 flipper_length_mm FLOAT NULLABLE 足ひれの長さ 6 body_mass_g FLOAT NULLABLE 体重 7 sex STRING NULLABLE 性別 環境構築 当記事では、Notebook 環境に Colab Enterprise を用います。 Colab Enterprise を使用すると、インフラストラクチャを管理せずに Notebook で作業できます。 Colab Enterprise の Notebook 作成方法は公式ドキュメントのクイックスタートをご参考下さい。 cloud.google.com 初期設定 パッケージのインストール Notebook で使うパッケージをインストールします。 # input[1] !pip install bigframes BigQuery セッションの設定 プロジェクト ID をご自身の値に書き換えて実行します。 # input[2] import bigframes.pandas as bpd PROJECT_ID = ${プロジェクト ID} REGION = "US" bpd.options.bigquery.project = PROJECT_ID bpd.options.bigquery.location = REGION データのロード bigframes.pandas では、pandas と同様に csv や json を読み込むメソッドもありますが、BigQuery 上のデータを読み込む read_gbq メソッドが用意されています。 今回は read_gbq メソッドを利用します。 # input[3] df = bpd.read_gbq( "bigquery-public-data.ml_datasets.penguins" ) df.head( 3 ) output[3] read_gbq の引数にテーブル ID を入力してデータを取得しましたが、BigQuery に対して SQL を実行して出力結果をデータフレームで取得することも可能です。 # input[4] query_df = bpd.read_gbq( """ SELECT species, AVG(body_mass_g) as avg_body_mass_g FROM `bigquery-public-data.ml_datasets.penguins` GROUP BY species """ ) query_df output[4] 参考: bigframes.pandas - API リファレンス 前処理 特徴の変換 各カラムのデータ型を確認します。 # input[5] df.dtypes output[5] string と Float64 の 2 種類のデータ型が存在します。 BigQuery ML の自動前処理 (特徴の変換) により、string 型の場合は one-hot encoding され、Float64 型の場合は 標準化 されるため、ここでは何も手を加えないことにします。 欠損値の対応 各カラムの欠損値の個数を確認します。 # input[6] df.isnull().sum() output[6] BigQuery ML の自動前処理 (欠損データの補完) では、string 型の場合は NULL が新規のカテゴリとなり、Float64 型の場合は元の入力列の平均値となります。 ここで、全体の行数も確認します。 # input[7] df.shape output[7] 全データ数は 344 であり、sex の欠損値は 10 であり全体の 3% となります。 sex 列で、「FEMALE」と「MALE」以外の新規カテゴリが追加されるとノイズになる可能性があり、また欠損値は全体の 3% 弱のため、sex 列で NULL となる行を削除したいと思います。 # input[8] df2 = df[df[ "sex" ].notna()] # input[9] df2.isnull().sum() output[9] sex の欠損値が含まれる行を削除した結果、他の列にあった欠損値も無くなっていることから、欠損値は削除した行の中にすべて含まれていたことになります。 # input[10] df2.shape output[10] データ分割 特徴列 (入力) と正解データ列 (出力) に分割します。 # input[11] x = df2[[ "species" , "island" , "culmen_length_mm" , "culmen_depth_mm" , "flipper_length_mm" , "sex" ]] y = df2[[ "body_mass_g" ]] トレーニングデータとテストデータにデータを分割します。 scikit-learn でもよく使われる train_test_split が bigframes.ml にも用意されているためこちらを使います。 # input[12] from bigframes.ml.model_selection import train_test_split x_train, x_test, y_train, y_test = train_test_split(x, y, test_size= 0.1 , random_state= 0 ) # input[13] print (f "x_train : {x_train.shape}" ) print (f "x_test : {x_test.shape}" ) print (f "y_train : {y_train.shape}" ) print (f "y_test : {y_test.shape}" ) output[13] 参考: Module model_selection モデルトレーニング bigframes.ml を用いて線形回帰モデルを構築します。 # input[14] from bigframes.ml.linear_model import LinearRegression # モデルの初期化 model = LinearRegression( enable_global_explain = True ) # モデルトレーニング model.fit(x_train, y_train) モデルの初期化では、各特徴がモデルに対してどれだけ影響しているかを示す Explainable AI を有効にするため、enable_global_explain を有効にしています。 その他の調整可能なパラメータは公式ドキュメントをご参照下さい。 参考: Class LinearRegression 推論 モデルに対して、 predict メソッドを用いることで推論 (予測) が可能です。 # input[15] pred = model.predict(x_test) pred.head( 2 ) output[15] モデル評価 モデルに対して、 score メソッドを用いることで評価指標を取得できます。 # input[16] model.score(x_test, y_test) output[16] mean_absolute_error (MAE : 平均絶対誤差) が 242.9 であり、また、0~1 の間の値をとり値が大きくなるほど予測値と実測値の誤差が少ないことを意味する決定係数も 0.80 であった。 モデルの保存 作成したモデルを BigQuery に保存できます。 データセット ID をご自身の値に書き換えて実行下さい。 # input[17] # データセットの作成 DATASET_ID = ${データセット ID} from google.cloud import bigquery client = bigquery.Client(project=PROJECT_ID) dataset = bigquery.Dataset(PROJECT_ID + "." + DATASET_ID) dataset.location = REGION dataset = client.create_dataset(dataset, exists_ok= True ) # モデルの保存 model.to_gbq(DATASET_ID + ".penguin_weight" , replace= True ) 参考: Class LinearRegression - to_gbq BigQuery にモデルが保存されているのを確認しました。 BigQuery に保存されたモデル また、Explainable AI によって各特徴量がどれくらいモデルに寄与しているのかを調べることができます。 Explainable AI の結果 BigQuery DataFrames を用いることで、pandas のようにデータの前処理を行い、scikit-learn のようにモデルの構築と評価、予測を行うことができました。 クリーンアップ 先程作成したデータセットを削除します。 input [ 18 ] from google.cloud import bigquery client = bigquery.Client(project=PROJECT_ID) client.delete_dataset( DATASET_ID, delete_contents= True , not_found_ok= True ) 又吉 佑樹 (記事一覧) クラウドソリューション部 はいさい、沖縄出身のクラウドエンジニア! セールスからエンジニアへ転身。Google Cloud 全 11 資格保有。Google Cloud Champion Innovator (AI/ML)。Google Cloud Partner Top Engineer 2024。Google Cloud 公式ユーザー会 Jagu'e'r でエバンジェリストとして活動中。好きな分野は AI/ML。 Follow @matayuuuu
アバター