TECH PLAY

電通総研

電通総研 の技術ブログ

822

こんにちは。 金融IT本部 PSユニット 融資ソリューション2部の武田です。 この記事では、 OSS -DB技術者認定試験の概要や勉強方法、業務・資格試験を通じて得られた気づきなどをまとめております。 DBや SQL についてこれから知りたいなという方や OSS -DB Silverの受験を検討している方の参考になれば幸いです。 1. OSS -DB技術者認定試験( OSS -DB Silver)とは 1.1 OSS -DB 試験の概要 OSS -DB技術者認定試験は、 オープンソース のデータベースである「 PostgreSQL 」に関する知識とスキルを認定する資格試験です。主催はLPI-Japanで、 PostgreSQL の基本的な操作から運用管理、セキュリティ、パフォーマンスチューニングまで、幅広い知識が問われます。 この試験は、以下の2つのレベルに分かれています: Silver(シルバー): PostgreSQL の基本的な知識と操作スキルを問う初級〜中級レベルの試験 Gold(ゴールド):より高度な運用・管理・設計スキルを問う上級レベルの試験 今回私が受験したのは「Silver」レベルで、 PostgreSQL を業務で使い始めたばかりの方やこれから本格的に学びたい方にとって、最初のステップとして最適な試験だと思います。 1.2 Silver試験の内容 Silver試験では、 PostgreSQL の基本的な機能や操作方法に加え、データベースの設計や運用に関する知識も問われます。具体的には、以下のような分野S1~S3が出題範囲となっています。 S1 一般知識(16%) S1.1 OSS -DBの特徴 PostgreSQL の機能や OSS の役割について理解 S1.2 RDB の一般知識 リレーショナルデータモデルや SQL の基本概念 S2 運用管理(52%) S2.1 インストール方法 PostgreSQL のインストールと クラスタ の作成 S2.2 付属ツールの使い方 OSコマンドでの管理ツールの利用 S2.3 設定ファイル 設定ファイルの利用と基本パラメータの知識 S2.4 バックアップ方法 バックアップ手法やWAL アーカイブ の理解 S2.5 運用管理作業 PostgreSQL の起動停止や基本運用コマンド S3 開発/ SQL (32%) S3.1 SQL コマンド 基本的な SQL 文やデータベース要素の知識 S3.2 組込み関数 データベースの標準関数や 演算子 の理解 S3.3 トランザクション トランザクション の概念と分離レベル 試験は選択式で90分間、50問出題されます。合格ラインは64点(32/50)です。 2.私の前提知識・受験目的 2.1. 私の前提知識 社会人2年目(受験当時) データベースに関する知識は、 入社後のIT研修にてSelect、Insert、Update、Deleteといった基本的な SQL コマンドを知る。 業務で PostgreSQL を少し触れた程度(テーブル、ビュー、インデックス作成、Grant権限付与など) データベースの設計や運用経験はなし。 2.2. 受験目的・きっかけ 現在の業務では構成管理作業を担当しています。具体的には、Gitのブランチ、サブモジュール管理や GitHub Actionsの軽微な修正、社内環境およびお客様環境の構築(サーバールームでのセットアップなど)を行っています。その中でデータベース関連のエラーに頻繁に遭遇するようになり、「もっとDBの仕組みを理解しないと...」と感じる場面が増えました。 ある日、上司との会話の中で、DBに関する教科書的なまとまったサイトを教えていただき、それを確認していく中で、 OSS -DB Silver試験の存在を知り「体系的に学ぶにはちょうどいいかも」と思い、勉強し受験しました。 3.勉強方法と使った教材 3.1. 学習期間 学習期間は約1.5ヵ月ほどで平日は朝の通勤時間30分と寝る前30分ほど、休日は2hを目標に学習し合計で30~50時間ぐらいだと思います。(平日、休日ともにさぼる日もありつつ、少しずつやりました) 3.2. 使用した教材 使用した教材は主に3つで、基本的には Ping -t(問題集サイト)で問題演習を行い、理解があいまいな箇所は上司に教えていただいた公式テキストを参照して補強しました。モチベーションを上げるためにも他の方の合格体験記を参考にしました。 Ping -t(問題集サイト) https://mondai.ping-t.com/ 公式テキスト https://oss-db.jp/ossdbtext 合格体験記ブログ 3.3. 試験対策で行ったこと まずは Ping -tの合格体験記を読み漁って、他の受験者の学習方法や正答率を参考にしました。学習方法のイメージをつかみました。 最初は「S1:一般知識」と「S3:開発/ SQL 」の分野から取り組みました。研修で触れた SQL コマンドが中心だったため、取り組みやすかったです。未回答をなくすことを目標にし、コンボ(連続正解)を目指して進めました。 次に「S2:運用管理」の分野に取り組み、同様に未回答をなくしコンボ達成を目標にしました。問題を解いている際に、コマンドのオプションなど「調べたらいいのでは?」と思う、覚えづらい部分の出題もありましたが、試験対策と割り切って暗記で乗り切りました。 全問題がコンボになった後、模擬試験に挑戦しました。正答率は7〜8割で、間違えた問題は都度復習して理解を深めました。模擬試験を5回解き、4回で8割を超えたので「もう大丈夫だろう」と判断し受験しました。 4.試験を終えて 試験結果は74点で無事合格してました。(合格基準:64点) 試験でも「S1:一般知識」と「S3:開発/ SQL 」は点がとれており、「S2:運用管理」はやや苦戦したという結果でした。 OSS -DB Silver試験の勉強を通じて、 PostgreSQL やDBに関する理解が受験前と比べてかなり深まりました。 試験勉強と実務を通じて、以下のようなスキルが身に付いたと実感しています。 ロールや スキーマ の理解 PostgreSQL のユーザー管理やアクセス制御に関する仕組み(ロール)、データベース内の構造( スキーマ )について、体系的に理解できました。 複雑なJOINやINDEXの仕組み INNER JOINやLEFT JOINなどの複雑な結合処理、INDEXの種類や効果について業務で使っているもの・使ってないもの含め幅広く学ぶことが出来ました。 バックアップ・リストアの操作を自信をもってできるように pg_dump , pg_restore, psql などのコマンドを使ったデータのバックアップ、リストア操作を業務でも問題なく行えるようになりました。特に、新たにテスト環境を作成する際に既存環境からデータを移行する場面で非常に役立っています。 本番環境と開発環境の差異によるエラー対応ができた リリース時に発生したエラーに対して、率先して各環境の スキーマ 調査を行い、原因の特定から対応まで行えました。 まとめ OSS -DB Silver試験は、 PostgreSQL を中心としたデータベースの仕組みを体系的に学ぶ良い機会でした。業務で断片的に触れていた知識が、試験勉強を通じて意味のある単位で整理され、「なぜそうなるのか」「どのような構成でデータが保存されているか」といった視点を持てるようになったと感じています。 PostgreSQL やDBについて詳しくなりたい方、業務で触れる機会がある方には、 OSS -DB Silver試験を受験し体系的に学ぶことをぜひおすすめしたいです。知識の整理だけでなく、実務への応用力も確実に高まると思います。 この記事を読んで「DBをもっと知りたい」「試験に挑戦してみよう」というきっかけになれば嬉しいです。 ここまで読んでいただき、ありがとうございました! 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @takeda0430 、レビュー: @handa.kenta ( Shodo で執筆されました )
アバター
初めまして。 エンタープライズ 第三本部、2年目の松田知洋です。 本記事では、用いた Snowflake の自動デプロイの仕組みを紹介します。Azure DevOpsを用いる事で、 ソースコード の一元管理、バージョン管理に加え、パイプラインによる人的ミスが少なく、再現性の高い運用が出来ます。実際普段の業務でもこういった仕組みを利用していますが、勉強を兼ねて改めて整理したのが本記事になります。 以下は Snowflake とAzure DevOpsに関する簡単な説明です。詳細に関してはリンクの弊社ブログ及び公式ドキュメントをご覧ください。 Snowflake について Snowflake は、 クラウド 上で提供されるデータウェアハウスプラットフォームであり、大量のデータを効率的に保存・管理・分析することが出来ます。また、 Snowflake は3大主要 クラウド サービス( AWS /Azure/ GCP )に対応しており、ユーザーのニーズに合わせて、柔軟に クラウド 環境を選択できます。これにより、既存のインフラと容易に統合できる点も大きな魅力です。 詳細: https://itsol.dentsusoken.com/snowflake/blog/snowflake-vol001-2694/ Azure DevOpsについて そもそもDevOpsという言葉は、「Development(開発)」と「Operations(運用)」を組み合わせた造語です。主にソフトウェア開発チームと運用チームが密に連携し、効率的かつ迅速にサービスやアプリケーションを提供するための方法論や文化を指します。Azure上でこれらを支援する様々なツールを提供するのがAzure DevOpsです。 詳細: https://azure.microsoft.com/ja-jp/products/devops Azure Reposについて Microsoft が提供するGitベースの ソースコード 管理サービスで、開発チームが効率的にコードを保存、共有、管理するためのツールです。 詳細(Repos): https://azure.microsoft.com/ja-jp/products/devops/repos Azure Pipelinesについて 継続的インテグレーション (CI)と継続的デプロイメント(CD)を実現するための自動化ツールであり、Azure Repos上にあるコードを様々なサービスに対して自動的にデプロイできます。 詳細(Pipelines): https://azure.microsoft.com/ja-jp/products/devops/pipelines 前提 今回紹介する手順は、以下の環境が利用できることが前提となります。 (1)Azureの利用環境及びLinuxVMの準備 (2) Snowflake の無料トライアル環境 (3)作業用PCへのGitのインストール/ GitHub アカウントの作成 (1)、(3)に関しては、手順での紹介を省略させていただきます。 作業手順 手順1 Snowflake トライアルアカウントの作成を作成する Snowflake のトライアルアカウントを作成します。 トライアルアカウントは1つのメールアドレスで何個でも作成することが出来ます。 以下のサイトにアクセスし、必要事項を記入して作成します。 https://signup.snowflake.com/ ※会社名、ジョブタイトルは適当に入力しても問題ないです。EditionはEnterprise以上を、 クラウド プロバイダーはAzureを選択してください。 手順2 Azure DevOpsの組織を作成する Azure DevOpsを使用するために必要な、Azure DevOpsの組織を作成します。 手順2-1:Azure DevOps Organizationsを開く ご自身のアカウントでAzureポータルへサインインし、Azure DevOps Organizationsを押下。 手順2-2:Organization作成画面を開く 遷移した画面でMy Azure DevOps Organizationsを押下。 手順2-3:Organizationを作成する 遷移した画面でCreate new organizationを押下。 手順2-4:Organizationの詳細を決める 認証画面が出てきたら、組織名とホストする地域を選択し、Continueを押下。 手順2-5:プロジェクトを作成する プロジェクト作成画面に遷移するので、プロジェクト名と公開範囲を設定し、作成。 手順3 Azure Reposの リポジトリ をローカルにコピーする 手順3-1:Azure Reposの情報をコピーする 作成したプロジェクトのReposからFilesを選び、Clone to your computerのURLをコピーします。 手順3-2:作業用PCにAzure Reposの リポジトリ をコピーする 作業用のPCでターミナルを開き、 リポジトリ を作成したいフォルダーに移動し(私はD:\DEMOに作成しました)、以下のコマンドを実行します。YOUR URLの部分には先ほどコピーしたURLを入れてください。 git clone <YOUR URL> 手順3-3:ローカルの リポジトリ にデプロイするファイルを作成する 作業用のPCにAzure Reposの リポジトリ がコピーされるので、新規フォルダーを作成し、その中に以下のように SQL ファイルを作成します(中身は自由に変更して下さい)。 CREATE OR REPLACE DATABASE DEVOPS_DB; CREATE OR REPLACE SCHEMA DEVOPS_DB.DEVOPS_SCHEMA; CREATE OR REPLACE TABLE DEVOPS_DB.DEVOPS_SCHEMA.DEVOPS_TABLE( ID NUMBER, NAME VARCHAR ); 手順3-4:デプロイするファイルをリモートに反映する 手順3-2で作成したフォルダに移動したら、以下のコマンドを実行し、作業用PCのローカルで作成した SQL ファイルをAzure Reposのメインブランチに反映します。 git add . git commit -m "<コメント>" git push origin main ReposのFilesに先ほど作成したフォルダ及びファイルが作成されていることを確認します。 手順4 デプロイ用パイプラインで使用する Snowflake への接続情報を作成する。 Snowflake への接続情報をDevOpsに変数として設定します。 手順4-1:Variable groupを開く PipelinesからLibraryを選択し、Variable groupを押下します。 手順4-2:Variable groupに Snowflake への接続情報を登録する 以下のように情報を登録し、Saveを押下します。パスワードは鍵アイコンをクリックし、伏字として登録しましょう。 ※ Snowflake の接続情報の詳細は、以下の場所から確認できます。 ロールは本来であれば接続用のシステムロールを作成するのが好ましいですが、今回はACCOUNTADMINとします。 5.デプロイ用のパイプラインを作成する 手順5-1:パイプライン作成画面を開く PipelinesからPipelinesを選択し、Create Pipelinesを押下します。 手順5-2:パイプラインで使用する リポジトリ の種類を選択する Azure Repos Gitを選択します。 手順5-3:パイプラインで使用する リポジトリ を選択する 作成したプロジェクトを選択します。 手順5-4:パイプラインの作成方法を選択する Starter pipelineを選択します。 手順5-5:パイプラインを作成する 以下の スクリプト を張り付け、Save and runの隣のボタンを押下し、Saveを選択します。 スクリプト の中では、エージェントの VM にSnowSQL( Snowflake の CLI )をインストールしたのちに、デプロイ対象のフォルダの中の SQL ファイルをリストアップし、SnowSQLで実行しています。 parameters: - name: deployFolderName displayName: Deploy Target Folder type: string variables: - group: Snowflake trigger: none stages: - stage: MainStage displayName: Run Snowflake Scripts jobs: - job: RunSnowSQL displayName: Execute all .sql scripts pool: name: 'MySelfHostedPool' variables: deployPath: '${{ parameters.deployFolderName }}' snowflakeAccount: '$(SNOWFLAKE_ACCOUNT)' snowflakeUser: '$(SNOWFLAKE_USERNAME)' snowflakePassword: '$(SNOWFLAKE_PASSWORD)' snowflakeWarehouse: '$(SNOWFLAKE_WAREHOUSE)' snowflakeRole: '$(SNOWFLAKE_ROLE)' steps: - checkout: self - task: Bash@3 displayName: Install SnowSQL inputs: targetType: inline script: | #!/bin/bash sudo apt-get install unzip wget https://sfc-repo.snowflakecomputing.com/snowsql/bootstrap/1.3/linux_x86_64/snowsql-1.3.0-linux_x86_64.bash SNOWSQL_DEST=~/bin SNOWSQL_LOGIN_SHELL=~/.profile bash snowsql-1.3.0-linux_x86_64.bash - task: Bash@3 displayName: List and Run SQL Scripts inputs: targetType: inline script: | #!/bin/bash # Add snowsql path source ~/.profile # Create Config Contents configContent=$(cat <<EOF [connections.my_snowflake_connection] accountname = "$(snowflakeAccount)" username = "$(snowflakeUser)" password = "$(snowflakePassword)" rolename = "$(snowflakeRole)" warehousename = "$(snowflakeWarehouse)" EOF ) # Create SnowSQL Config File configPath="$HOME/.snowsql" mkdir -p "$configPath" # Write config content to file echo "$configContent" > "$configPath/config" # Execute SQL sqlScripts=$(find "$(deployPath)" -type f -name "*.sql" | sort) echo "Found $(echo "$sqlScripts" | wc -l) SQL scripts to execute" echo "SQL Scripts found:" for sqlScript in $sqlScripts; do echo "Executing SQL script: $sqlScript" snowsql -c my_snowflake_connection -f "$sqlScript" done サイドバーが出てくるのでSaveを押下。 手順6 作成したデプロイ用パイプラインに接続情報の使用権限を与える 作成したパイプラインで先ほど作成した接続情報を使用できるよう、権限を与える必要があります。 手順6-1:許可設定画面を開く Libraryに戻り、先ほど作成した接続情報を選択し、右上のPipeline permissionsを押下します。 手順6-2:作成したパイプラインに権限を与える +を押下し、先ほど作成したパイプラインを選択します。 作成したパイプラインが追加されていることを確認します。 手順7 デプロイ用パイプラインを実行するエージェント VM を作成する。 今回は、今までの作業で作成したパイプラインをAzureのLinuxVM上で実行します。 本手順ではそのための設定を行います。 手順7-1:エージェントプール作成画面を開く まずは左下のProject SettingsからAgent Poolsを選択し、Add Poolを押下します。 手順7-2:エージェントプールを作成する 画像のように設定し(Nameは任意)、Createを押下します。 名前をMySelfHostedPool以外にする場合は、手順5-5の スクリプト 内のPoolのNameを変更し、一致させてください。 手順7-3:エージェント作成画面を開く 作成したエージェントプールに遷移するので、New Agentを押下します。 手順7-4:エージェントを使用する VM に設定する Windows 、 macOS 、 Linux の三種類が表示されるので、今回は Linux を選択します。 その後、LinuxVMにエージェントを作成・設定する手順が表示されるので、前提(1)にて用意したLinuxVMに作成・設定します。 手順8 作成したパイプラインをエージェント上で実行する。 いよいよパイプラインを実行します。 以下の手順は、手順7-4の3つ目のコマンドでエージェントがアクティブになっている状態であることが前提となります。 手順8-1:パイプライン実行画面を開く Pipelinesから手順5で作成したパイプラインを選択し、Run pipelineを押下します。 手順8-2:パイプラインを実行する 実行画面が表示されるので、Deploy Target Folderに手順3で作成したフォルダ名を入力し、Runを押下します。 手順8-3:パイプライン実行画面を開く 実行が開始されるので、Excute all . sql scriptsを押下します。 手順8-4:パイプラインの実行結果を確認する(Azure DevOps) 実行が正常に完了したことを確認します。 手順8-5:パイプラインの実行結果を確認する( Snowflake ) Snowflake にサインインし、 SQL ファイルが実行されていることを確認します。 クエリ履歴からも確認できます。 以上で終了です! 長い道のりでしたが無事デプロイ出来ました! まとめ 初めてのブログということもあり、非常に読みづらい部分が多かったと思います。 最後まで読んでくださり、ありがとうございました。 本記事を通して、少しでもAzure DevOpsや Snowflake に興味を持ってくれた方がいれば幸いです。 今回紹介したのは、ほんの一部の機能であり、Azure DevOpsや Snowflake にはまだまだ多くの便利な機能が存在するので、是非皆さんの手で発掘してみてください。 最後になりますが、私自身、入社当時はほぼIT未経験であり、研修はもちろんのこと、配属されてからも悪戦苦闘しながら色々と実装してきました。 今回もブログを書くために、改めて1からこの自動デプロイの仕組みを作り直してみたのですが、かなりの時間を要しました...。特に、手順5-5のサンプル スクリプト を作成する際に、SnowSQL( Snowflake の CLI )に触るのが久しぶりだったため、記述すべき情報と記述の形式をかなり忘れており、作成→エラー→公式ドキュメント等で調査のループをかなり繰り返しました。 しかし、実際に手を動かしてものを作ってみると意外と何とかなることがあるので、私のようにIT経験が浅く、設計やアーキに自信がない方でも、とりあえずチャレンジしてみると面白いかもしれません。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @matsuda.tomohiro レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター
はじめまして。金融IT本部 融資ソリューション2部 大澤弘和です。 継続的なアップスキリングの一環で、 AWS の学習を続けてきた結果、2024 Japan AWS All Certifications Engineersの選出に続き、今年2025年の応募クライテリアも達成し、2年連続で選出のご連絡を先日受領しました。 これまで累計15の認定資格に合格しましたが、必要な試験時間は約37時間、出題問題数はおよそ1,000問であり、改めて振り返ると、長い道のりでした。なお、「受験は試験センターで受ける」の一択。 AWS 認定履歴 最初に学習し始めたのはまだコロナ渦だった2021年。当時は AWS のみならず、Azureや Salesforce など多岐に渡る能力開発をしていましたので、 AWS 関連はハンズオンコースを通じて、 AWS Certified Solutions Architect - Associateまで取得しました。 その後、2023年から改めて、 AWS Certified Solutions Architect - Professionalを学習後、他の認定区分の領域にも手を広げ、2023年末に全冠達成(2024 Japan AWS All Certifications Engineersクライテリア)。 2024年は、その年に新たに追加された3つの認定資格を取得し、全冠達成(2025 Japan AWS All Certifications Engineersクライテリア)しました。 ※以下は私の認定履歴。太字が2024年に追加された3つの認定資格です。 No 認定年 Certification Name Code 1 2021 AWS Certified Cloud Practitioner CLF-C01 2 2021 AWS Certified Solutions Architect - Associate SAA-C02 3 2023 AWS Certified Solutions Architect - Professional SAP-C02 4 2023 AWS Certified Database - Specialty DBS-C01 5 2023 AWS Certified Security - Specialty SCS-C02 6 2023 AWS Certified Data Analytics - Specialty DAS-C01 7 2023 AWS Certified Machine Learning - Specialty MLS -C01 8 2023 AWS Certified: SAP on AWS - Specialty PAS-C01 9 2023 AWS Certified SysOps Administrator - Associate SOA -C02 10 2023 AWS Certified Developer - Associate DVA -C02 11 2023 AWS Certified DevOps Engineer - Professional DOP-C02 12 2023 AWS Certified Advanced Networking - Specialty ANS-C01 13 2024 AWS Certified Data Engineer - Associate DEA-C01 14 2024 AWS Certified AI Practitioner AIF-C01 15 2024 AWS Certified Machine Learning Engineer - Associate MLA-C01 私のバックグラウンド 現在は、金融機関向けの業務アプリケーション開発を推進するプロジェクトマネジメントのポジションで従事してます。 ここ数年は自分でシステムを開発したり実機を触る機会はめっきり減ってきていますが、元々は自分で設計やコーディングをするのが好きでした。 また、いわゆる業務アプリケーション開発だけでなく、専門性の高い リスク管理 領域における 定量 化・分析や、 遺伝的アルゴリズム を使った与信モデルやATM入出金予測モデル等の研究開発、 自然言語 解析系のAI活用 コンサルティング などの業務経験があるため、 統計学 的なアプローチやデータマネジメント、データパイプラインの肌感は比較的あるほうだったこともあり、2024年に追加された3試験も比較的スムーズに把握できました。 2024年に追加された3試験について 2024年に AWS Certified AI Practitioner、 AWS Certified Data Engineer – Associate、 AWS Certified Machine Learning Engineer – Associate の 3 つの新しい認定資格が追加されました。 私の学習方法はいずれも、試験ガイドを元に分野ごとに対象知識、スキル・サービスを把握して整理し、 AWS の公式学習コンテンツの AWS Skill Builderで学習していく形でした。 AWS Certified Data Engineer - Associate データエンジニア向けの試験内容で問われるサービスはGlue、Athena、Redshift、 Kinesis などです。 AWS Certified Data Analytics - Specialtyと比べると、そこまで深い内容が問われるわけでもない。 試験ガイドを読みながら各サービス内容を学習することで対応。 AWS Certified AI Practitioner AIとML、生成AI、基盤モデルについての概念や ユースケース 、そして責任あるAIに対する ガイドライン の認識等から出題されるもの。バックグラウンドのナレッジがあるため、試験ガイドを元に改めて整理しなおして対応。 AWS Certified Machine Learning Engineer - Associate Amazon SageMaker系サービスを軸としたMLエンジニアリングの主題が多い。また左記のような AWS のサービス利用の範囲ではなく、MLエンジニアリング自体の理解も問われるため、特徴量エンジニアリングや、モデルト レーニン グとチューニングにおけるハイパーパラメータ最適化、 正則化 手法、 過学習 回避方法などの理解が必要となります。 まとめ AWS 認定試験については、固有サービスの ユースケース を元に理解度が問われますが、どの分野が理解しやすいか、どれから学習すべきかは、学習者のそれまでの経験値に大きく依存します。 AWS の各サービスは次々と改定されていますし、 AWS に限らず、キャッチアップしてもすぐに知識が陳腐化するケースもありますが、特定時点におけるトレンドやサービスをある程度把握しておけば、将来の改良・改定部分は、差分で学習することができ、 クラウド や テク ノロ ジー 動向を掴みやすくなります。 たとえ普段の業務に関係のない分野のキャッチアップであっても、それは自分の興味の幅、視野を広げるものに将来つながってくるものです。 テク ノロ ジー に興味・関心を持ち、継続的に能力開発をすることは、いつの日もエンジニアとしてあるべき心構えであり、それが未来の自分やチームが一歩踏み出す時に背中を押してくれるものだと考えております。 www.dentsusoken.com 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @osawa.hirokazu 、レビュー: @takami.yusuke ( Shodo で執筆されました )
アバター
こんにちは。 夏が来るたび、日本の暑さに戸惑っています。 金融IT本部でお仕事をさせていただいております、新卒入社3年目の青井です。 今回は、情報処理安全確保支援士のオンライン研修(2年目)で学んだ中から、システムライフサイクルプロセスにおけるセキュリティについて少しお話ししようと思います。 セキュリティの フレームワーク や ガイドライン について実業務で少し考える機会があったので、紹介します。 セキュリティに興味がある若手SE(興味なくてもトレンドとしておさえるべき??)、 電通 総研に興味がある学生(実際どんな仕事してるの?)向けに、できるだけライトに書いているので、「ふーん。」くらいで読み流していただけると幸いです。 1. 情報処理安全確保支援士とは 初めに先ほど出てきた情報処理安全確保支援士についてさらっと説明します。 情報処理安全確保支援士は、サイバーセキュリティ対策を推進する人材の国家資格です。 いわゆるセキュリティの専門家です。登録セキスぺとも呼ばれています。 3年毎に更新があり、毎年1回のオンライン研修と3年間で1度の実践講習の計4回の受講が必要です。 電通 総研では、情報処理安全確保支援士に関しての受験費用・研修受講費を全額負担してくれるので、費用面の負担なく資格の取得・ 保有 が実現できます。 (結構高いんです。ありがたい。。。) 参考: 情報処理安全確保支援士(登録セキスぺ) 2. システムライフサイクルプロセスにおけるセキュリティとは 昨今の情報システムは、複雑化・高度化に伴い、適切なセキュリティ対策が不可欠となっています。システムライフサイクルプロセスとは、情報システムの企画・要件定義から運用、保守、廃棄に至るまでの一連の流れを指します。このプロセスにおいて、セキュリティを適切に組み込むことで、情報システムの安全性と信頼性を確保することができます。 (言葉では簡単に言えるものの難しいんですよね、、、) セキュリティは、システムライフサイクルのあらゆる段階で考慮される必要があります。企画段階では、セキュリティ要件の明確化や、リスク分析など、セキュリティ対策の検討が重要です。設計・開発段階では、セキュリティ機能の組み込みや、 脆弱性 の排除が求められます。運用・保守段階では、セキュリティパッチの適用や、監視・分析による脅威の早期発見、廃棄段階では確実・完全な情報の抹消など、継続的なセキュリティ対策が不可欠です。 このように、システムライフサイクルプロセスにおいて、適切なセキュリティ対策を講じることで、DevSecOpsを意識したセキュアなシステム運用への移行を実現することができます。 DevSecOpsとは、開発(Development)、セキュリティ(Security)、運用(Operation)の3つの領域を統合的に管理・運用していくアプローチのことを指します。従来は、開発とセキュリティ、運用がサイロ化(分離?孤立?のイメージ)されていましたが、DevSecOpsではこれらの領域を並行して進めることで、開発サイクルの早期からセキュリティを組み込み、セキュアで高品質なシステム構築を目指します。(とは言ってもこれがなかなか難しい。。。) 気になる方は、DevOpsとの違い等も学べるので是非色々調べてみてください! 3. ポイントは企画・要件定義段階におけるセキュリティ対策 情報システムのライフサイクル全般を通じて、セキュリティを適切なレベルで維持するためには、企画・要件定義段階からセキュリティ要件を定義することが重要です。 システム開発 をする際、機能要件で要件定義に落ちていないものは、通常その後の設計・製造工程で拾われません。 非機能要件のセキュリティも同じように、要件として定義できていないと、適切なセキュリティ対策がその後の工程に反映されません。セキュリティ要件の曖昧さや過不足は、過剰なセキュリティ対策によるコスト増や後工程での手戻り、運用後の セキュリティインシデント の発生につながります。 企画・要件定義段階でのセキュリティについての検討は、高品質で安全なシステムの構築に必要不可欠です。 昨今のシステムセキュリティに対する関心の高まりに伴い、その重要度が機能要件と同レベルになってきていると感じています。 4. 社内向け支援 システム開発 で実際に検討してみる ありがたいことに、社内向けの小規模システムのセキュリティについて少し考える機会をいただきました。 まずは一人でセキュリティ要件について考えてみました。通信・暗号化方式やアクセス制限、Webセキュリティ関連などなど。 が、、、全然思いつかない。 ここで、 IPA の非機能要件グレードのセキュリティを確認してみたところ中項目だけで11項目もありました。 前提条件・制約条件からインシデント発生時の対応・復旧に至るまで、数多くの考慮事項があります。 正直、非機能要件と言いながら、考慮する事項が 機能要件並みのカロリーがあるなぁと、、、 特にセキュリティ リスク管理 やセキュリティインデント対応/復旧などの運用後の想像が足りないなと実感。 試験ではイメージできてもいざ、実務でとなると試験以上に難しく自分の実力不足に打ちひしがれました。 (試験では、選択肢もあり、状況も整理されている) 実際の現場では、より複雑な状況(予算や期間など様々な条件)に直面するため、より高度な対応力が必要であると感じました。 圧倒的な経験&スキル不足による セキュリティ要件のあいまい・過不足 が顕在化してしまいましたね。。。 実際に『政府機関等の情報セキュリティ対策のための統一基準(令和5年度版)』や IPA の『システム構築の上流工程強化(非機能要求グレード)』をもとに観点等を洗い出し、たたき台を作成してみます。 特に網羅性の観点で効果が見られ、経験・スキルがない私自身でもたたき台程度のものは作成することができました。 システムライフサイクルプロセスにおいては、セキュリティに関する多くの考慮事項が存在します。 機能要件だけでも大変なのに、非機能要件にまで頭を悩ませられます。ツラい、、、笑 5. 実際の検討からの学び 研修の受講から実際の検討を通して、思考プロセスにおける ガイドライン や フレームワーク 活用の有効性を学びました。 普段、 システム開発 の中でReactやSpring等の フレームワーク や、インフラ選定で AWS 等の クラウド 基盤を使用するなど、目に見えるテクニカルな部分にスポットライトを当てることは容易でした。そうすることで、本来時間をかけるべき新たなサービスの創出等、コアな業務に注力できるというメリットは実務を通して認識できていました。 しかし、セキュリティの企画・要件定義などの思考プロセスにおいて ガイドライン 等を適用するという経験が今まで無く、そのような選択肢が頭にありませんでした。 このように経験やスキルの差を埋めてくれるのは、 ガイドライン や フレームワーク であることを身を持って実感できました。 6. まとめ 結局何を伝えたかったのかというと、要件などの 思考プロセスにも ガイドライン や フレームワーク を活用 すると良いということです。 冒頭でも述べましたが、DevOpsからDecSecOpsへとセキュリティに対する注目は日々高まっています。 これまで非機能要件として認識されていましたが、その重要度とウエイトからもセキュリティが機能要件として認識される時代が来るのではないのかな(すでに来ている??)と思っています。 電通 総研は、若手でも色々な機会(チャンス)を与えていただける環境です。自分がこれまで経験したことがない仕事はそれなりのストレスがかかりますが、達成と同時にストレス以上の成長を感じることができます! 今後も機会があれば、机上では獲得でき得ない経験をどんどん積み上げていきたいです。 ここまで読んでいただきありがとうございました。 これらを読んで、セキュリティと関連する ガイドライン 、 フレームワーク (あと 電通 総研。。。)に少しでも興味を持っていただけると幸いです。 参考 内閣サイバーセキュリティセンター(NISC)政府機関等の情報セキュリティ対策のための統一基準(令和5年度版) 独立行政法人情報処理推進機構(IPA)システム構築の上流工程強化(非機能要求グレード) 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @aoi.kazuma 、レビュー: @handa.kenta ( Shodo で執筆されました )
アバター
電通 総研、スマート ソサエティ センターの飯田です。 Gemini CLI がリリースされて話題になっていますね。 Developers, builders and creators: Bring the power of Gemini 2.5 Pro directly into your terminal with Gemini CLI , our new open-source AI agent with unmatched usage limits. Available now in preview — at no charge. pic.twitter.com/D576uqjfJG — Google (@ Google ) 2025年6月25日 リリースされたばかりで、Gemini CLI の良い利用方法はまだ掴みきれていないですが、 そもそも業務利用して使うために、 利用規約 、特にデータの取り扱いについて正しく理解しておくことは非常に重要だとおもいます。 本記事では、どのサービス経由でGemini CLI を使うかによって、適用される規約やデータポリシーがどう変わるのかを見てみたいと思います。 ご注意:本記事は、Gemini CLI Preview のリリース直後(2025年6月末時点)の情報に基づいています。プレビュー版のため、今後の更新により内容が最新の情報と異なる場合があります。 Gemini CLI の利用形態とデータポリシー Gemini CLI は、認証方法によって適用される 利用規約 が異なります。 公式のドキュメント( Terms of Service & Privacy )では以下のように記載されています。 利用可能な形態 Login with Google (Gemini Code Assist for individuals) → Google が提供する個人向けサービス Gemini API Key (Using Gemini Developer API a: Unpaid Service, b: Paid Service) → Google が提供するどちらかと言えば個人利用やPoC用途 Login with Google (for Workspace or Licensed Code Assist users) Workspace →  Google Workspaceで企業ユース Licensed Code Assist → Google Cloudのサービスで企業ユース Vertex AI (Using Vertex AI Gen API )→ Cloudのサービスで企業ユース ※適応される規約が異なってきます データがモデル学習に利用されるケース 以下の方法で利用する場合、プロンプト、生成された回答、および関連コードが Google の製品改善(モデルのト レーニン グを含む)のために収集・利用される可能性があります。業務利用の際はご注意ください。 Gemini Code Assist for individuals 無料契約のGemini API Auth method 1: Yes. When you use your personal Google account, the Gemini Code Assist Privacy Notice for Individuals applies. Under this notice, your prompts, answers, and related code are collected and may be used to improve Google 's products, which includes model training. Auth method 2a: Yes, When you use the Gemini API key Gemini API (Unpaid Service) terms apply. Under this notice , your prompts, answers, and related code are collected and may be used to improve Google 's products, which includes model training. データがモデル学習に利用されないケース 以下の方法で利用する場合、再学習されないと記載されており、問題ないと思われます。 有償契約 のGemini API Google Workspace 有償契約 の Code Assist Vertex AI Gen API Auth method 2b, 3 & 4: No. For these accounts, your data is governed by the Google Cloud or Gemini API (Paid Service) terms, which treat your inputs as confidential. Your code, prompts, and other inputs are not used to train models. 【Tips】知っておきたいサービスの違い  Google と Google Cloudの違い Google : 一般ユーザー向けの Webサービス (検索、 Gmail など)を提供します。 Google Cloud: 企業向けの クラウド サービス( GCP , Google Workspaceなど)を提供します。 提供元がどちらの会社かは、サービスのドキュメントのURL ドメイン ( google .comかcloud. google .comかなど)でおおよそ見当がつきます。 詳しい違いのイメージはこちらも参考にしてください。 zenn.dev 【Tips】知っておきたいサービスの違い Gemini API と Vertex AI Gen API Gemini API : Google が提供する、主に個人開発者やライトユーザー向けの API です。 Vertex AI: Googe Cloudが提供する、高度なセキュリティとガバナンスを備えた エンタープライズ 向けのAIプラットフォームです。 企業向けで本番で利用する際は、VertexAI経由で利用するのが良いとされています。 オプトアウト 利用統計情報の収集も下記のドキュメントにあるように、収集されるものがあり、オプトアウトが可能になります。 収集されるのは主にサービス改善のための統計情報です。しかし、利用者側に直接的なメリットは特にないため、業務で利用する場合はオプトアウトしておくのが無難でしょう。 https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/configuration.md#usage-statistics 収集されるもの Tool Calls: We log the names of the tools that are called, whether they succeed or fail, and how long they take to execute. We do not collect the arguments passed to the tools or any data returned by them. API Requests: We log the Gemini model used for each request, the duration of the request, and whether it was successful. We do not collect the content of the prompts or responses. Session Information: We collect information about the configuration of the CLI , such as the enabled tools and the approval mode. 収集されないもの Personally Identifiable Information (PII): We do not collect any personal information, such as your name, email address, or API keys. Prompt and Response Content: We do not log the content of your prompts or the responses from the Gemini model. File Content: We do not log the content of any files that are read or written by the CLI . 実際にセットアップしてみる セットアップ自体は、ドキュメント通りに行えば簡単にできます。 Google Workspaceの場合 私は Google Workspaceのアカウントを持っていたので、こちらで試してみました。 Login With Google で Google Workspaceアカウントを設定すると、最初はこのようにエラーとなったので、環境設定に登録します echo 'export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"' >> ~/.bashrc source ~/.bashrc これで動作しました。 Vertex AI ( GCP ) の場合 ドキュメントには以下のように設定するとあります。 GCP プロジェクトの認証 gcloud auth application-default login 環境変数 の設定 export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID" export GOOGLE_CLOUD_LOCATION="YOUR_PROJECT_LOCATION" # 例: us-central1 export GOOGLE_GENAI_USE_VERTEXAI=true まとめ Gemini CLI を安全かつ効果的に利用するためには、ご自身の ユースケース に合わせて適切な利用形態を選択することが不可欠です。特に業務で利用する場合は、入力データがモデル学習に使われない企業向けサービス(Workspace, Vertex AIなど)がその候補になるかと思います 最後まで読んでいただき、ありがとうございました。 ↓ のスターを押していただけると嬉しいです。励みになります。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @iida.michitaka7b3a3dd24e9c454b 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター
こんにちは。 電通 総研ITの寺尾です。 プラグイン 開発の機能実装について、今回は ラインマーカー の実装についてお話します。 前回はこちら: IntelliJプラグイン開発の始め方~アクション機能編~ ラインマーカーとは エディタ画面上のガター(行番号の表示される列)に表示されるアイコンを、 IntelliJ では ラインマーカー や ガターアイコン と呼びます。 インタフェースの実装や、オーバーライドメソッドの実装先へのジャンプで、アイコンをクリックする方も多いのではないでしょうか。 アクションによるファイルジャンプとは別に、今回はラインマーカーによるファイルジャンプ機能の実装をご紹介します。 公式ドキュメント ラインマーカープロバイダー 実装前に知っておくこと 前回と同様に、本記事でもKotlinでの実装例を提示します。 Kotlinプロジェクトに関する内容は、アクション機能編の 実装前に知っておくこと をご参照ください。 実装 ゴール 今回はラインマーカーのクリックで、DAOメソッドから SQL ファイルへのジャンプ機能の実装を目指します。 事前準備 ラインマーカーはプロバイダークラスを実装して実現します。 まずは以下の準備から始めていきましょう。 RelatedItemLineMarkerProvider のサブクラス プラグイン 設定登録 今回のラインマーカー処理は、 RelatedItemLineMarkerProvider のサブクラスで実装します。 plugin.xml には、以下のように<codeInsight.lineMarkerProvider>タグを使って登録します。 プロバイダークラスは IntelliJ の拡張ポイントとして登録するため、 タグ内に記述します。 codeInsight.lineMarkerProvider : ラインマーカーのプロバイダークラスを登録するタグ language : ラインマーカー表示処理対象とするファイルタイプ implementationClass : 実装したプロバイダークラスの完全修飾クラス名 <extensions defaultExtensionNs = "com.intellij" > <codeInsight . lineMarkerProvider language = "JAVA" implementationClass = "org.domaframework.doma.intellij.gutter.dao.DaoMethodProvider" /> </extensions> それでは、実装を始めていきましょう! 各オーバーライドメソッドでは、ガターに表示するアイコン設定とラインマーカーの登録処理を実装します。 ラインマーカーのアイコン ラインマーカーに表示するアイコンは、デフォルトで用意されている Icon や独自に用意した画像のアイコンタイプから設定できます。 getIcon デフォルトで用意されているアイコンや任意のアイコンを以下のように設定します。 // デフォルトで用意されているアイコン設定例 override fun getIcon(): Icon = AllIcons.General.Mouse 参考:独自のアイコンを登録する 独自に用意した画像をアイコンとして使用する場合、ファイルタイプとアイコンを表すオブジェクト、クラスを用意します。 「 Doma Tools」では、カスタム言語として SQL ファイルを扱うための実装の一環で、ファイルタイプ定義を生成しています。詳細は以下公式ドキュメントをご参照ください。 カスタム言語の実装について: カスタム言語サポート 独自のア イコン画 像について: アイコンの使用 class SqlFileType private constructor () : LanguageFileType(SqlLanguage.INSTANCE) { override fun getName(): String = "DomaSql" override fun getDescription(): String = "Doma sql template" override fun getDefaultExtension(): String = "sql" override fun getIcon(): Icon = SqlIcon.FILE companion object { @JvmField val INSTANCE: SqlFileType = SqlFileType() } } 次にアイコンタイプを表すオブジェクトを定義します。 object SqlIcon { @JvmField val FILE: Icon = getIcon( "/icons/SqlFile.svg" , SqlFileType :: class .java) } 独自で用意したアイコンも同じように、 Icon 型プロパティで設定できます。 override fun getIcon(): Icon = SqlIcon.FILE ナビゲーション機能を持つラインマーカーの登録 collectNavigationMarkers では、ラインマーカーがクリックされた時に呼び出される処理ではなく、 どのような機能を持つラインマーカーを登録するか を実装します。 メソッドに渡されるファイル内のPSI要素の条件をチェックして、対象にラインマーカーを紐づけた情報を生成します。 今回は簡単に「 メソッド要素(PsiMethod)である 」という条件を満たす要素に、「 SQL ファイルにジャンプする 」ラインマーカーを生成します。 アクション機能と異なり、このプロバイダークラスは「 Java ファイルを対象に動作する」設定で登録しているため、ファイルタイプチェックの実装はしません。 collectNavigationMarkers // PsiElement型引数eの型をチェック val method = e as? PsiMethod if (method != null ){ // ラインマーカー生成処理 } 引数 e がラインマーカーの対象であることを確認後、DAOメソッドから SQL ファイルにジャンプするラインマーカーを生成します。 if (method != null ){ // 一意な要素にラインマーカーを生成するため // 要素の識別子トークンを持つPsiNameIdentifierOwnerに変換 val owner = e as? PsiNameIdentifierOwner ?: return val identifier = owner.nameIdentifier ?: return val sqlFile : PsiElement? = // アクション機能と同じように、ジャンプ先のSQLファイル情報を取得 // ラインマーカービルダーオブジェクトの生成 val builder: NavigationGutterIconBuilder<PsiElement> = NavigationGutterIconBuilder .create(icon) // getIcon()から値を取得 .setTooltipText( "SQLへ移動" ) .setTarget(sqlFile) // ラインマーカー情報を保持する引数`result`にラインマーカーオブジェクトを設定 result.add(builder.createLineMarkerInfo(identifier)) } 参考:ナビゲーション以外の機能を持たせる 上記の例では、単純に指定した対象へのファイルジャンプを行うナビゲーション処理を行っています。 アイコンクリック時にファイルジャンプ以外の処理を実行したい場合、生成するラインマーカーオブジェクトを RelatedItemLineMarkerInfo 型として作成します。 val marker = RelatedItemLineMarkerInfo( identifier, identifier.textRange, icon, { "SQLへ移動" }, getHandler(e.project, sqlFile), // クリック時処理のハンドラーを設定 GutterIconRenderer.Alignment.RIGHT, ) { // 必要に応じて関連要素のCollectiopn<GotoRelatedItem?>を返す処理を実装 } result.add(marker) クリック時に実行する処理のハンドラーは、以下のように実装できます。 private fun getHandler(project: Project ,sqlFile: PsiFile): GutterIconNavigationHandler<PsiElement> = GutterIconNavigationHandler { _: MouseEvent?, _: PsiElement? -> // 任意の処理とファイルジャンプ処理 FileEditorManager.getInstance(project).openFile(sqlFile.virtualFile, true ) } 動かしてみる ラインマーカーの表示とクリック時の挙動を確認してみましょう。 デバッグ 起動方法は前回と同じく、 デバッグ起動する で環境を起動し、DAOファイルを開いてラインマーカーの表示を確認します。 アイコンが表示されたら、クリックして SQL ファイルへのジャンプを試してみましょう! 参考:「 Doma Tools」実装コード 「 Doma Tools」の同様のラインマーカーは以下コードで実装しています。 DaoMethodProvider さいごに 今回はアクションと同じくファイルジャンプをラインマーカーで実装する方法をご紹介しました。 独自のアイコンを表示させると、「自分で作った プラグイン 感」を一層強く感じます。 ワンクリックで処理を呼び出せるラインマーカーで、いろいろな便利機能を実装してみてください! レビューも投稿していただけますと大変励みになります🙇‍♀️ Doma Tools マーケットプレイスページ 本 プラグイン は OSS として Domaコミュニティ へ寄贈されています。 不具合修正や機能要望、ディスカッションにもぜひご参加ください。 採用ページ 執筆: @terao.haruka 、レビュー: @nakamura.toshihiro ( Shodo で執筆されました )
アバター
こんにちは。 製造エンジニアリング本部エンジニアリング クラウド 技術部の竹田です。 普段の業務では自動車会社様向けに CAEの クラウド 環境構築・運用保守 を担当しています。 パブリッククラウド である AWS 、Azure、OCI といった クラウド ベンダーを活用し、お客様のCAE解析業務を支援しています。 この記事では、 電通 総研に入社して3年目社員 である私がこれからエンジニアリング本部に配属される新人や、 電通 総研に興味を持っている就活生の方向けに、 部や社内の学習環境、担当業務、そして 電通 総研の強みについて紹介したいと思います。 👉 弊社CAE教材 目次 はじめに 業務をする上での学習環境と海外出張 担当案件とやりがいについて 電通総研の強み さいごに はじめに 社会人歴: 3年目 担当ソリューション: 製造業向け クラウド CAE環境の構築・運用保守業務を担当。 インフラ・ ミドルウェア 部分を主に担当しています。 私が所属する部ではCAEアプリケーションでの解析業務自体はしておらず、他部門が担当しています。 業務をする上での学習環境と海外出張 電通 総研に入社し、研修期間が終了するとそれぞれの部に配属され、業務がスタートするのですが、ほとんどの人が自分たちが扱うソリューションの知識がゼロもしくは浅い状態だと思います。そこで部に入って学習を進めていくわけですが、そちらの学習制度について共有します。 私は パブリッククラウド を扱うメンバーとして アサイ ンされましたので、まずは AWS ,Azure,OCI周りの知識を習得する必要がありました。私自身、知識習得という面で一番効率よく、又、証明にもなるものが 「資格取得」 だと考えています。 電通 総研では AWS の資格取得について、受験費用負担という制度があり(2025/06現在)、私もこの制度を使って現在資格を取得中です。現在、私はアソシエイトレベル3つ、プロフェッショナルレベル1つ、 スペシャリテ ィレベル2つの資格を 保有 しており、最終的には AWS 領域で全て(12個)の資格を取得する目標を立てています。部の中には全て取得している方が2名在籍されている他、 部のメンバー全員が資格取得に向けて積極的に取り組んでおり、切磋琢磨できる環境が整っています。 また、情報収集といったところで各ベンダーのイベントの参加も積極的に参加しており、参加できる環境にもあります。自分自身、配属後、たくさんのイベントに参加させてもらっているのですが、特に2024年12月には AWS reInventという AWS がラスベガスで開催する世界最大のイベントに参加しました。 こちらのイベントに参加し、現在の クラウド 全般のトレンドや技術知識取得はもちろんのこと、現地で日本の クラウド を扱うエンジニアにもお会いすることができ、たくさんの刺激を受けました。( AWS reInventではすべてスケールが大きくて驚きました。最終日のrePlayというお祭りでは、世界的に有名なDJであるZEDDが登場し場を盛り上げていました。) 毎日刺激を受けながら、日々成長している実感があり、 クラウド 領域に当初から興味のあった私にとっては、とても有意義な毎日を送っています。 私と一緒に AWS reInventをまわった宮崎君が 電通 総研テックブログを書いてますのでよろしければぜひご参考に。 👉 AWS reInventの雰囲気 担当案件とやりがいについて 私の担当ソリューションは 「 クラウド HPC」 という領域です。配属当初は、CAEの検証環境を構築し、受け渡す「構築業務」を担当していました。 CAEに関わる ライセンスサーバ と 計算マシン の関係性を、実際に手を動かしながら学ぶことで理解が深まりました。最近では構築業務だけでなく、設計業務の一部 も任されるようになり、実際に本番環境で稼働している システム構成の作成 を担当しました。 スケジュール通りに環境を顧客に引き渡せたことは、何より顧客の役に立ててうれしいですし、自信につながりました。 私のこの仕事に対するやりがいは、 現在もしくは将来的に世の中で走る車の設計部分で自分の手掛けた環境が何らかの形でかかわっている という部分です。これまで 電通 総研に入社して、多くの関連知識を勉強させてもらいましたが、これからもさらに知識を習得し、多くのお客様の支援を担当したいと思っています。 電通 総研の強み 最後に入社して3年目社員からみた 電通 総研の強みについて紹介します。 電通 総研の強みはたくさんあると思いますが私が強く感じる部分は 「個々人に合った裁量のある仕事ができる」 ことだと思います。案件の規模も大小様々あるので自分のレベルに応じた仕事内容を上司から アサイ ンしてもらえています。一歩一歩、できることを増やしていき、最終的に多くのことをできるようにすることは、成長という側面において、一番理想的な方法だと考えています。 さいごに 今回は新入社員・就活生向けに社内学習環境と担当案件、 電通 総研の強みについてお伝えしました。私自身3年目という身なので 電通 総研の魅力を伝えきれていないかもしれないのですが、参考にしてもらえれば幸いです。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 新卒採用サイト 執筆: @takeda.taiki 、レビュー: @nakamura.toshihiro ( Shodo で執筆されました )
アバター
みなさんこんにちは。 エンタープライズ 第一本部の鈴木です。 この記事では、以前記事にまとめたFeature Flag(フィーチャーフラグ)を取り入れたアプリケーションを、勉強を兼ねて AWS 上に構築してみたため、記事にまとめていきます。 Feature Flagについては、以前私がまとめた以下のリンク先の記事を参考にしていただければ幸いです。 Feature Flagという開発手法についてまとめる 1.はじめに 2.AWS AppConfigについて 3.構築内容 3-1.アプリケーション 3-2.AWS Lambda AppConfig 4.動作検証 5.まとめ 1.はじめに 今回は、以下2つの目的をもとに簡単なデモアプリを作成しています。 Feature Flagを導入したアプリケーションを実装してみる。 Feature Flagを管理することができる AWS のサービス「 AWS AppConfig」の使用感を確認する。 また、今回構築するシステムの全体構成は以下のとおりです。 今回重要となってくるのがAppConfigという AWS のサービスです。詳しくは次章でまとめますが、Feature Flagの管理に利用しています。 また、アプリケーションはLambdaにホストします。今回の目的はFeature Flagを用いたアプリケーションを実装することであり、構成をシンプルにするため、CloudFront + Lambdaのサーバーレス構成としています。LambdaはECSなどサーバーが必要なサービスと比較して、実行回数と実行時間に応じて料金が発生するため、今回のようなとりあえず試してみるミニマムな開発では良い選択だと思います。また、アプリケーションはコンテナで作成しているため、ECSなどサーバーありのホストに移行する際も比較的容易に移行できるのもメリットです。 アプリケーションは、フロントエンド/バックエンドともにNext.jsで構築しています。主要なパッケージのバージョンは以下のとおりです。 パッケージ バージョン Next.js 15.3.1 node.js v22-slim @ aws - sdk /client-appconfigdata 3.798.0 アプリケーションはLambdaにホストしていますが、通常LambdaではWebアプリケーションをそのまま動作させることができません。しかし、 Lambda Web Adapter という AWS が提供するツールを導入することで、実装をほとんど変更することなくWebアプリケーションをLambda上で実行できるようにしています。本筋からは外れるため詳細は記載しませんが、「構築手順」に実装方法は記載しているため、参考にしてみてください。 肝心のFeature Flagは、アプリケーションから AWS SDK を用いてAppConfigから取得しています。実装や設定方法は「構築手順」に記載しています。 2. AWS AppConfigについて この章では、先ほどから登場しているAppConfigについて紹介します。 AWS AppConfigとは、Feature Flagを管理する AWS のサービスで、開発者が完全なコードをデプロイすることなく、アプリケーションの動作を迅速かつ安全に変更することができます。 2019年12月に、 AWS Systems Managerの機能の1つとしてリリースされたサービスで、もともと Amazon ・ AWS 内で使われていた仕組みを一般向けにリリースしたサービスのようです。 詳しく知りたい方は、以下のドキュメントを参照してください。 参考: AWS AppConfig とは何ですか? - aws.amazon.com Feature Flagの管理にAppConfigを利用するメリットとしては、以下が挙げられます。 Feature Flagの設定・バージョン・環境の管理を自前で実装することなく、マネージドに管理することができる。 CloudWatchと連携することで、予期せぬ動作を検知して、自動で ロールバック することが可能である。 例えば、Feature Flagのリリース後にCloudWatch のアラームがトリガーされた場合、AppConfig が自動的に変更を ロールバック するように設定できる。これにより、アプリケーション更新によるユーザーへの影響を最小限に抑えることが可能である。 Feature Flagごとにバリアントを設定することができ、特定のユーザーIDや地理的位置などの条件をもとに評価を返却することができる。また、コンテキスト値に基づいて トラフィック を分割することも可能で、 カナリア リリースやA/Bテストの実現が可能である。 バリアントについては「 マルチバリアント機能フラグの概念と一般的なユースケースを理解する - aws.amazon.com 」を参照。 Feature Flagのリリース戦略をリリース単位で指定することができる。 リリース戦略はあらかじめ AWS 側で用意している戦略( 定義済みのデプロイ戦略の使用 - aws.amazon.com )と自分でカスタマイズ可能な戦略( デプロイ戦略の使用 - aws.amazon.com )を選択することができる。 3.構築内容 3-1.アプリケーション 今回は以下の3つのFeature Flagを持つ、簡単なTODOアプリを作成しました。 isNewFeatureEnabled( true の時、「新機能が有効になっています」と文言が表示される) isTodoReorderEnabled( true の時、TODOリストを入れ替えられる機能を有効にする) isTodoMemoEnabled( true の時、メモ機能を有効にする) アプリケーションはサーバーサイド レンダリング で、Feature Flagは初期表示の際に appconfig.ts を用いてAppConfigから取得するようにしています。 // app/page.tsx import getAppConfigConfiguration from "./appconfig" ; import TodoApp from "./components/TodoApp" ; export default async function Home () { const featureFlags = await getAppConfigConfiguration(); const initialTodos = [ { id : 1 , text : "お肉を買う" } , { id : 2 , text : "ニンジンを買う" } , { id : 3 , text : "ジャガイモを買う" } , { id : 4 , text : "ルーを買う" } , ] ; return < TodoApp initialTodos = { initialTodos } featureFlags = { featureFlags } /> ; } // appconfig.ts import { AppConfigDataClient, GetLatestConfigurationCommand, StartConfigurationSessionCommand, StartConfigurationSessionCommandInput, } from "@aws-sdk/client-appconfigdata"; // エラー等でFeature Flagが取得できなかった場合のデフォルト値 const FALLBACK_CONFIG = { isTodoReorderEnabled: { enabled: false }, isTodoMemoEnabled: { enabled: false }, isNewFeatureEnabled: { enabled: false }, }; async function getAppConfigConfiguration() { try { // AppConfig クライアント用の設定値を環境変数から取得する。 const region = process.env.AWS_REGION || "ap-northeast-1"; const applicationIdentifier = process.env.APPCONFIG_APPLICATION_ID; const environmentIdentifier = process.env.APPCONFIG_ENVIRONMENT_ID; const configurationName = process.env.APPCONFIG_CONFIGURATION_NAME; // AppConfig クライアントを生成 const client = new AppConfigDataClient({ region }); // AppConfig とのセッションを作成する。 const sessionParams: StartConfigurationSessionCommandInput = { ApplicationIdentifier: applicationIdentifier, EnvironmentIdentifier: environmentIdentifier, ConfigurationProfileIdentifier: configurationName, }; const session = await client.send( new StartConfigurationSessionCommand(sessionParams) ); if (!session?.InitialConfigurationToken) { console.warn( "AppConfig セッションの初期トークンが取得できませんでした。" ); return FALLBACK_CONFIG; } // AppConfigからFeature Flagを取得する。 const configCommand = new GetLatestConfigurationCommand({ ConfigurationToken: session.InitialConfigurationToken, }); const response = await client.send(configCommand); if (!response.Configuration) { console.error( "AppConfig から構成を取得できませんでした" ); return FALLBACK_CONFIG; } // 取得した値をJSON形式に変換する。 const config = JSON.parse(response.Configuration.transformToString()); console.info("AppConfig の構成取得に成功:", config); return config; } catch (error) { console.error("AppConfig 構成取得中にエラーが発生しました:", error); return FALLBACK_CONFIG; } } export default getAppConfigConfiguration; また、アプリケーションをLambda上で動作させるにあたり Standaloneモード でビルドしています。これは、Lambdaのファイルサイズ上限(250MB)を超えないようにサイズを小さくしたり、初期化を早くしてLambdaのコールドスタートの影響をなるべく小さくしたりするために採用しています。 Standaloneモードでビルドするためには、 next.config.ts に output:standalone を追加します。 // next.config.ts import type { NextConfig } from "next"; const nextConfig: NextConfig = { output: "standalone", }; export default nextConfig; LambdaにはDockerビルドしたコンテナをデプロイし、そのコンテナを起動するようにします。 以下にDockerfileと、サーバーを起動させるために使用する スクリプト run.sh の実装例を載せておきます。 補足として、DockerfileにLambda Web Adapter用の設定をしています。 このように COPY コマンドの設定を1行付け足すことで、Next.jsのような フレームワーク を使用したWebアプリケーションをLambda上で動作させることができます。 本筋から外れるため説明は省略させていただきますが、詳しく知りたい方は以下のドキュメントを参照してください。 参考: Lambda Web Adapter でウェブアプリを (ほぼ) そのままサーバーレス化する - aws.amazon.com // Dockerfile FROM node:22-slim AS builder WORKDIR /app COPY . . EXPOSE 3000 RUN npm install && npm run build # ----------------------------- FROM node:22-slim AS runner # Lambda Web Adapter用の設定 COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.9.1 /lambda-adapter /opt/extensions/lambda-adapter ENV PORT=3000 NODE_ENV=production WORKDIR /app COPY --from=builder /app/public ./public COPY --from=builder /app/package.json ./package.json COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/run.sh ./run.sh RUN ln -s /tmp/cache ./.next/cache RUN chmod +x ./run.sh RUN apt-get update && apt-get install -y bash ENTRYPOINT ["./run.sh"] # run.sh #!/bin/bash [ ! -d ' /tmp/cache ' ] && mkdir -p /tmp/cache exec node server.js 3-2. AWS この章では、AppConfigとLambdaを中心に、 AWS 環境の構築例を紹介させていただきます。 ※ CloudFrontまわりの設定は本筋から外れるため、設定内容を省略させていただきます。 Lambda はじめにLambda関数を設定します。 コンソール画面からLambdaを開き、「関数を作成」から新しい関数を作成します。 以下のように「コンテナイメージ」を選択し、ECRにデプロイ済みのコンテナイメージを選択して作成します。 次に、Lambda実行ロールへAppConfigに対するアクセス権限を追加します。 具体的には、実行ロールにAppConfigに対する権限を付与するポリシーを追加します。 { " Version ": " 2012-10-17 ", " Statement ": [ { " Sid ": " AllowAppconfigForLambda ", " Effect ": " Allow ", " Action ": [ " appconfig:StartConfigurationSession ", " appconfig:GetLatestConfiguration " ] , " Resource ": " arn:aws:appconfig:<region>:<account-id>:application/* " } ] } AppConfig 次にAppConfigを設定します。 コンソール画面からAppConfigを開き、設定を作成します。 「設定オプション」を「機能フラグ」にして、「設定プロファイル名」を入力して次へ進みます。 次にFeature Flagを設定します。 以下の図のように、値を設定します。「フラグ名」はAppConfig上でFeature Flagを識別する名前で、「フラグキー」はアプリケーションから設定を取得する際のキーとなる値です。 「バリアント」については「基本フラグ」を選択していますが、「マルチバリアントフラグ」を設定すると、特定のユーザーIDや地理的位置などの条件をもとに評価を返却したり、コンテキスト値に基づいて トラフィック を分割したりすることも可能です。 最後にフラグ値をオン/オフで選択します。 必要なFeature Flagを設定したら「保存してデプロイを続ける」をクリックして、デプロイに進みます。 デプロイの画面に進んだら、まずはじめに「環境を作成」から環境を作成します。 環境を判別できる名前を付けたら「環境を作成」をクリックします。今回は「dev」としています。 デプロイの画面に戻ってきたら、「環境」に先ほど作成した環境名が設定されていることを確認します。 そして、デプロイ戦略を選択します。デフォルトでいくつかデプロイ方法が選択できますが、「デプロイ戦略を作成」から自分でデプロイ戦略を作成することができます。今回は「AppConfig.AllAtOnce」を選択します。 「デプロイを開始」をクリックしてFeature Flagの設定をデプロイします。デプロイは数秒で完了します。これでアプリケーションからFeature Flagの設定を取得できる状態となりました。 4.動作検証 構築が完了したため、動作検証します。 まずはじめに、設定したFeature Flagが全てオフ(false)の場合で確認します。 アプリケーションを起動すると「3-1.アプリケーション」で記載したフラグが全てfalseの場合と一致しています。 CloudWatchに出力されているログを確認すると、AppConfigから取得したフラグ値が全てfalseとなっていることが確認できます。 では設定を変更して、機能をリリースします。 AppConfigから、先ほど作成したアプリケーションの設定を開きます。 各フラグの値をオン(true)に変更し、「Save version」をクリックして設定を保存します。 その後に遷移する画面で、保存したバージョンの設定値が表示されていることを確認して、「デプロイを開始」をクリックします。 デプロイの画面で、環境名、バージョン、デプロイ戦略を選択して「デプロイを開始」をクリックします。 デプロイは数秒で完了します。状態が「ベーキング」となったことを確認して、アプリケーションの動作検証をします。 アプリケーションを起動すると「3-1.アプリケーション」で記載したフラグが全てtrueの場合と一致しています。 CloudWatchに出力されているログを確認すると、AppConfigから取得したフラグ値が全てtrueとなっていることが確認できます。 以上のように、アプリケーションコードのデプロイを挟まずに、AppConfigからFeature Flagを更新するだけで新機能をリリースすることができました。 5.まとめ 今回は簡単なデモアプリを作成して、Feature Flagの実装やAppConfigの使用感を検証しました。 まずFeature Flagについては、アプリケーションコードのデプロイをすることなく、AppConfigの更新のみで新機能の有効/無効を切り替えられるのはとても良いと思いました。 機能のリリースとデプロイの分離ができることで、任意のタイミングでデプロイを挟まずに機能リリースができるため、開発サイクルを早めることができると思いました。 AppConfigについては、Feature Flagのバージョン管理や環境管理が可能で、 AWS を利用している場合はとても良いと思いました。 プロジェクトで AWS を利用している場合、Feature Flagを導入する際には、選択肢の1つに含める価値は十分あるのではないでしょうか。 最後まで読んでいただきましてありがとうございました。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @suzuki.takuma 、レビュー: @miyazawa.hibiki ( Shodo で執筆されました )
アバター
こんにちは。 電通 総研ITの寺尾です。 前回ご紹介した プラグイン 開発環境構築に続き、今回から実際に機能実装についてお話していきます。 本記事でご紹介する機能は アクション機能 です。 前回はこちら: IntelliJプラグイン開発の始め方~環境構築編~ アクション機能とは IntelliJ におけるアクションとは、メニューやショートカットで呼び出せる機能全般を指します。 普段 IntelliJ を使う際に、ショートカットキーによるファイル検索、Gitウィンドウでの操作、Runメニューからの デバッグ 起動などをすることはないでしょうか。 実はこれらも、 IntelliJ 上ではアクションとして実装された機能となっています。 「 Doma Tools」で実装したアクションを例に、任意のメニューに独自のアクションを追加する方法についてご説明します。 公式ドキュメント カスタムアクションの作成 実装前に知っておくこと 実装言語 公式ドキュメントでは Java コードのサンプルが提示されていますが、「 Doma Tools」ではテンプレートをベースにKotlinで実装しています。 Kotlinは Java と非常によく似た実装が可能な言語ですが、以下の特徴を持つKotlinを採用しています。 Kotlinでプラグインを開発する利点 null安全性:変数宣言時に、Null許容かを明示的に指定できます 型安全ビルダー:静的に必須パラメータをチェックし、 コンパイル が成功する状態でのみ、ビルド処理が呼び出せるようにします コールバック: IntelliJ プラットフォームが多用するコールバックを、Kotlinは ラムダ式 によって容易に実装できます 他にも保守性やパフォーマンスに効果のある機能を持ち、 IntelliJ プラグイン 開発において非常に相性の良い言語となっています。個人的にも、null安全性は開発において特に便利な点だと感じています。 これから プラグイン 開発をされる方も、Kotlinで実装してみてください! Kotlinプロジェクトに関する詳細は、 Kotlin をご参照ください。 【補足】 簡単なKotlinコードをウェブ上で実行することもできますので、この機会にKotlinにも触れてもらえればと思います! Play Kotlin PsiElement IntelliJ プラグイン の実装ではそのほとんどで PsiElement のオブジェクトを扱います。 これはファイルや ディレクト リ、ファイル内のメソッド名やパラメータなどあらゆる要素を表す基本的な型になっており、 IntelliJ 上のあらゆる要素はこの型によるツリー構造を持っています。 サブタイプも多く実際には複雑なツリー構造を持つ場合もあるため、開発を通して扱い方を覚えていきましょう。 公式ドキュメント 参考:PSIツリー構造の確認方法 デバッグ 環境では、 ツール > View Psi Structure of Current File から、PSIツリー構造を確認できます。 また PsiViewer プラグイン を導入することで、 デバッグ 環境以外でもPSIツリー構造を確認できるようになります。 実装 ゴール 今回例に挙げるアクションは、DAOファイルから SQL ファイルにジャンプする機能です。 アクションが有効なカーソル位置の判定や、ファイルジャンプまでの実装方法についても見ていきます。 事前準備 アクション機能の実装に必須なものは以下の2つになります。 AnAction のサブクラス プラグイン 設定登録 プラグイン 設定でアクションとして登録できるクラスは AnAction のサブクラスとなっており、 アクション機能の登録は plugin.xml に タグを使って登録します。 前回ご紹介した アクション機能の登録例 と同じ内容ですが再度掲載します。 actions : アクションメニューをグループ化するタグ group : アクショングループの設定。グループ名やどのメニューにアクションを追加するなどを設定 action : アクション情報を記載するタグ id : アクション機能の識別ID(任意のID) class : 実装したAnActionのサブクラスの完全修飾クラス名 text : アクション表示名 description : アクションの説明 keyboard-shortcut : デフォルトのショートカットキーを登録するタグ <actions> <group id = "org.domaframework.doma.intellij.DomaToolGroupActions" text = "Doma Tools" popup = "true" icon = "AllIcons.Nodes.AbstractClass" > <add-to-group group-id = "EditorPopupMenu" anchor = "last" /> <action id = "org.domaframework.doma.intellij.action.JumpToSQLFromDao" class = "org.domaframework.doma.intellij.action.dao.JumpToSQLFromDaoAction" text = "Jump to SQL" description = "Jump from DAO file to SQL file" > <keyboard-shortcut keymap = "$default" first-keystroke = "alt D" /> </action> </group> </actions> 準備が整いましたら、実装を始めていきましょう! 参考:Plugin DevKitを使う Plugin DevKit を使うことで、簡単に上記の下準備ができます。 ファイル > 新規 > Plugin DevKit > Action 表示制御の実装 AnAction クラスで主に使用するオーバーライドメソッドについて説明します。 紹介するメソッドの役割は、それぞれアクション表示制御、アクション実行スレッドの設定、処理本体です。 まずは表示制御から見ていきます。 update メニュー表示時やショートカット実行時、まずはこのメソッドが呼び出され、アクションの条件を満たしているかを制御します。 引数で渡される AnActionEvent 型が持つ presentation.isEnabledAndVisible を、最終的に true とすることがアクション実行条件を満たすことになります。 例えば、以下の条件をチェックするロジックを実装します。 アクションを呼び出したのが Java ファイル上か カーソル位置がDAOメソッド名の上にあるか SQL ファイルへのジャンプが必要なDAOメソッドか 以下は実装例です。ファイル情報やカーソル位置の取得は、他機能の実装でもよく使うロジックになります。 ファイルタイプの判定 アクションの呼び出しが Java ファイル上であるかを判定するため、ファイル情報を取得してファイルタイプをチェックします。 // eはupdateに渡されるAnActionEvent型引数 // アクションを呼び出したファイル情報をPsiFileオブジェクトで取得 val currentFile = e.getData(CommonDataKeys.PSI_FILE) ?: return val file: PsiFile = currentFile ?: return // PsiFileからVirtualFile型の要素を取得し、FileTypeManagerによってファイルタイプを取得 val fileType = FileTypeManager.getInstance().getFileTypeByFile(file.virtualFile) val isDaoFileType = when (fileType.name) { "JAVA" , "Kotlin" , "CLASS" -> true else -> false } カーソル位置の取得 DAOメソッドを対象にアクションを実行するため、カーソル位置の要素をチェックします。 // editorにエディタ画面情報を格納 val editor = e.getData(CommonDataKeys.EDITOR) ?: return // editor.caretModel.offsetで、エディタ画面上のカーソル位置の要素をPsiElement型オブジェクトとして取得 val element = file.findElementAt(editor.caretModel.offset) ?: return SQL ファイルへのジャンプが必要なDAOメソッドか は、実際にはメソッドに付与された アノテーション タイプなどを細かくチェックする必要がありますが、 今回は簡単に カーソル位置の要素がDAOメソッドか のチェック方法を例にします。 // 取得したelementが、メソッド要素であることをチェック val isDaoMethod = element is PsiMethod 最後に、チェックした結果を AnActionEvent のプロパティに設定して表示制御のロジックは完成です。 e.presentation.isEnabledAndVisible = isDaoMethod アクションスレッドの設定 update() をバックグラウンド(BGT)とイベントディスパッチ(EDT)のどちらのスレッドで呼び出すかを指定します。 書き込み処理など編集を加える処理はEDT、その他は基本的にBGTを設定します。 ※6/20 getActionUpdateThread() が update() に影響するメソッドであることをご指摘いただいたため、明記させていただきました。 詳細は 公式ドキュメント をご参照ください。 getActionUpdateThread 今回はファイルジャンプのみを行うためBGTで設定します。 override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT アクション処理の実装 アクションが呼び出された時の本体処理を実装します。 actionPerformed 必要な情報を再度取得してファイルジャンプ処理を実装します。 // カーソル位置のDAOメソッド要素を取得 val editor = e.getData(CommonDataKeys.EDITOR) ?: return val element = currentFile?.findElementAt(editor.caretModel.offset) ?: return // PsiMethodの子要素が取得される可能性もあるため、念のため親のPsiMethodを取得 val method = PsiTreeUtil.getParentOfType(element, PsiMethod :: class .java) ?: return val daoFile = method.containingFile.virtualFile // 以下はプロジェクトの構成情報を扱うために必要なオブジェクト val project = e.project ?: return val module = project.getModule(daoFile) // ジャンプ先のファイル情報を取得し、ファイルジャンプ ファイルジャンプのロジック ここからは少し複雑なロジックになるため、ファイル情報を取得するために必要なコアな実装例のみを記載します。 ファイルパスを取得 Doma のルール上、DAOメソッドに関連する SQL ファイルは、リソース ディレクト リ内の以下に配置されていることが前提となります。 【 SQL ファイルの配置先】 {リソースディレクトリ}/META-INF/{DAOパッケージパス}/{DAO名}/{DAOメソッド名}.sql まずは基となるDAOメソッドのファイルパスを取得します。 カーソル位置から取得した要素オブジェクトから、以下のようにファイル情報を取得できます。 // DAOメソッド名 val methodName = element.name // プロジェクトのルートパス。「{プロジェクトディレクトリ}/src/main」のようなパスを取得 val contentRoot = this .psiProject.getContentRoot(daoFile)?.path // contentRootが取得できていれば、収集した情報でSQLファイル用の相対パスを生成 val sqlFilePath = contentRoot.let { // DAOファイルの絶対パス val daoFilePath = daoFile.path // DAOファイルのパスを文字列変換し、SQLファイル用の相対パスを生成 // 例)「src/main/java/example/dao/ExampleDao.java」を変換 daoFilePath .replace( "java" , "resources/META-INF" ) .replace( ".java" , "/" ) .plus( " $methodName .sql" ) // src/main/resources/META-INF/example/dao/ExampleDao/exampleMethodName.sql } SQL ファイルを取得 リソース ディレクト リ内から 相対パス でファイルを取得する場合、 ResourceFileUtil を使用します。 以下の処理では、DAOファイルと同じモジュール内のリソース ディレクト リから、 相対パス に一致する SQL ファイルを VirtualFile オブジェクトとして返します。 第3引数は検索スコープを設定します。 getModuleScope には、テストリソース ディレクト リとしてマークされた ディレクト リを検索対象とするかのフラグを設定します。この例では対象外とするため false で設定します。 sqlFilePath は META-INF/ から始まる 相対パス です。 val targetSql = ResourceFileUtil.findResourceFileInScope( sqlFilePath.replace( "//" , "/" ), project, module.getModuleScope( false ), ) SQL ファイルへジャンプ 最後はファイルジャンプの実装です。 対象ファイルにジャンプする処理自体は非常にシンプルで、 FileEditorManager を使用して以下のように実装します。 FileEditorManager.getInstance(project).openFile(targetSql, true ) これでDAOメソッドから SQL ファイルをエディタ画面上で開くことができるようになりました! 動かしてみる デバッグ 起動して、想定通りにファイルジャンプアクションが動作するか試してみましょう。 前回ご紹介した デバッグ起動する で、 IntelliJ の デバッグ 画面を起動してください。 画面が起動したら、以下手順で動作確認してみましょう。 任意の Doma プロジェクトを作成し、DAOと SQL ファイルを実装 DAOメソッド名上の右クリックでポップアップメニューを表示 登録したジャンプアクションを選択 SQL ファイルにジャンプ もしアクションが表示されない場合や、アクションを実行してもファイルジャンプできない場合 開発画面側で ブレークポイント を設定し、DAOや SQL ファイル情報が正しく取得できているか等を確認してください。 参考: 「 Doma Tools」の実装コード 「 Doma Tools」の同様のジャンプアクションは以下コードで実装しています。 JumpToSQLFromDaoAction さいごに 今回は IntelliJ プラグイン のアクション機能実装に関するお話でした。 アクション機能は「 Doma Tools」に実装した中では個人的に比較的簡単な機能となっており、最初に実装するにはちょうど良い難易度でした。 この記事ではファイルジャンプ機能を例に挙げましたが、 SQL ファイルの生成など様々なアクションも実装できますので、「 Doma Tools」や他の プラグイン も参考にして好みの機能を追加してみてください! 今後も他機能の実装に関する記事を投稿していきますので、ぜひご覧ください。 レビューも投稿していただけますと大変励みになります🙇‍♀️ Doma Tools マーケットプレイスページ 本 プラグイン は OSS として Domaコミュニティ へ寄贈されています。 不具合修正や機能要望、ディスカッションにもぜひご参加ください。 採用ページ 執筆: @terao.haruka 、レビュー: @nakamura.toshihiro ( Shodo で執筆されました )
アバター
こんにちは。 電通 総研ITの寺尾です。 前回に続き、以前ご紹介した IntelliJ 向け プラグイン 「 Doma Tools」の開発経験を基にした、 プラグイン 開発方法についてお話していきたいと思います。 前回はこちら: IntelliJプラグイン「Doma Tools」のご紹介~OSSなプラグイン開発~ まず今回は、環境構築からリリースまでの大まかな流れをご説明します。 ※Gradle、 GitHub の基本的な知識があると本記事の内容が理解しやすくなります ※記事内の GitHub リポジトリ のリンクは、本記事作成時点での最新のコミットをリンクしています IntelliJ プラグイン を作ってみよう 日本国内から マーケットプレイス にあげられている IntelliJ 向け プラグイン は、比較的少ない傾向にあります。 「 プラグイン 開発に興味はあるけど始め方がわからない」、「 マーケットプレイス に出すって難しそう」 …と感じられている方に、本記事が取っ掛かりになれば幸いです。 前提 プラグイン 開発で用意するものは以下になります。 IntelliJ IDEA(Ultimate、Community Editionのどちらか) Gitコマンドが扱える環境 開発する プラグイン の GitHub リポジトリ 1.環境構築 「 Doma Tools」はJetBrainsが用意している IntelliJプラットフォームプラグインテンプレート をベースにしています。 まずはこの リポジトリ をクローンすることで、基本的なプロジェクト構成を構築できます。 プロジェクトはGradleプロジェクトとして構成されており、ビルド、リリースを実行するためのGradleタスクや GitHub Actionsも、テンプレートに用意されています。 GitHub Actions: .github/workflows Gradleビルド スクリプト : build.gradle.kts 参考 Gradleとは? Gradle Gradle User Manual GitHub Actionsとは? GitHub Actions ドキュメント 2. プラグイン 設定 プラグイン の名前やサポートするバージョンなどを、自身の プラグイン の設定に変更します。 プラグイン の設定は以下のファイルを編集して管理します。 IntelliJ公式ドキュメント plugin. xml plugin.xml は、 マーケットプレイス 上の プラグイン 識別IDや プラグイン 名、開発元情報、 プラグイン で提供する機能を設定するファイルです。 実装をしても、このファイルへの設定を忘れると機能を利用できないためお忘れずに! 例えば、「 Doma Tools」ではアクション機能を プラグイン で提供する場合は以下のように記述しています。 actions : アクションメニューをグループ化するタグ group : アクショングループの設定。グループ名やどのメニューにアクションを追加するなどを設定 action : アクション情報を記載するタグ id : アクション機能の識別ID(任意のID) class : 実装したAnActionのサブクラスの完全修飾クラス名 text : アクション表示名 description : アクションの説明 keyboard-shortcut : デフォルトのショートカットキーを登録するタグ <actions> <group id = "org.domaframework.doma.intellij.DomaToolGroupActions" text = "Doma Tools" popup = "true" icon = "AllIcons.Nodes.AbstractClass" > <add-to-group group-id = "EditorPopupMenu" anchor = "last" /> <action id = "org.domaframework.doma.intellij.action.JumpToSQLFromDao" class = "org.domaframework.doma.intellij.action.dao.JumpToSQLFromDaoAction" text = "Jump to SQL" description = "Jump from DAO file to SQL file" > <keyboard-shortcut keymap = "$default" first-keystroke = "alt D" /> </action> </group> </actions> 拡張ポイントの実装は extensions タグ内に記述します。以下はコード検査機能の設定例です。 inspectionToolProvider : コード検査機能を登録するタグ implementation : 実装したInspectionToolProviderサブクラスの完全修飾クラス名 <extensions defaultExtensionNs = "com.intellij" > <inspectionToolProvider implementation = "org.domaframework.doma.intellij.inspection.dao.provider.SqlFileExistProvider" /> </extensions> gradle.properties gradle.properties は、ビルド スクリプト で参照されるプロジェクトプロパティを設定するファイルです。 テンプレートでは、ビルド時の プラグイン バージョンやプラットフォームバージョンの設定をこのプロパティファイルから参照します。 【補足】 一部のプロパティは plugin.xml と同様の項目を表すものがありますが、ビルド スクリプト によって gradle.properties の内容で設定が参照、上書きされます。 build.gradle.kts build.gradle.kts は、Gradleのビルド スクリプト を実装するファイルです。 プロジェクトの依存関係や、 IntelliJ プラットフォーム プラグイン のビルド、テスト、リリースに関わる設定も記載されています。 テンプレートではリリースに必要な プラグイン 情報の収集処理などが実装されており、基本的には追加の実装なしで利用することが可能です。 【補足】 Doma Toolsでは、リリースノートや CHANGELOG.md 内容の更新、次リリースの仮バージョン生成など、運用に関わる処理を build.gradle.kts と GitHub Actionsの追加実装で自動化しています。 参考:パッケージのバージョン管理 build.gradle.kts に記載するライブラリや プラグイン バージョンは、Gradleのバージョンカタログで管理することがおすすめです。 カタログファイル libs.versions.toml にまとめて記載しておくことで、依存パッケージのバージョン管理ツールが自動で最新バージョンへのアップデートを提案してくれます。 【補足】 Doma Toolsでは Renovate を採用しており、依存パッケージに最新バージョンがリリースされると、カタログファイルに記載のバージョンを更新するPull Requestを作成してくれます。 3.実装 アクションやコード補完など IntelliJ に追加したい機能を実装します。 公式ドキュメントや OSS の プラグイン コードも参考にしてみましょう。 機能によって、 IntelliJ プラットフォームで指定されたサブクラスを作成します。 継承するクラスや実装するインタフェースの一覧は 公式ドキュメント をご参照ください。 機能実装やテストに関する詳細な説明は、順次投稿していく予定です。 先に基本的な実装方法が気になる方は、 IntelliJ のサンプルプロジェクトやドキュメントをご覧ください。 IntelliJプラットフォームプラグインサンプルプロジェクト ガターアイコン機能の実装 コード補完機能の実装 参考:開発で役立つ プラグイン Plugin DevKit : IntelliJ プラットフォーム プラグイン の開発で推奨されている プラグイン です。アクション機能の実装に必要な設定やクラスを簡単に生成できるようになります。 PsiViewer : カスタム言語を使った機能を実装する際、エディタ上のファイル内の要素情報を確認する際に便利な プラグイン です。 GitHub Copilot : プラグイン 実装に限らず、ロジックの実装に悩んだ時の相談相手や リファクタリング 、ビルドまでの一貫したタスクなどの開発作業を依頼できます。 参考:コードの品質を高める プロジェクトの品質を向上させるために、コードフォーマットを統一します。 「 Doma Tools」では以下 プラグイン を使用しています。 spotless google-java-format ktlin また、 タイプミス や変数のアクセスレベルなどを検査することもプロジェクトの品質向上につながります。 IntelliJ はQodanaと連携したコード解析が可能です。詳細は 公式ドキュメント をご参照ください。 参考: OSS とコミュニティの活用 IntelliJ Platform Explorer 拡張ポイントやインタフェースを実装している OSS リポジトリ を検索できるサイトです。 JetBrains Platform IntelliJ プラットフォーム プラグイン 開発者の集うコミュニティです。 実装の悩みについては、こちらでア イデア を探してみましょう。 4.動作確認 実装した プラグイン 機能を デバッグ 環境で確認します。 デバッグ 起動する Run Plugin を デバッグ モードで起動し、開発した プラグイン をインストールした想定の仮想的な IntelliJ 環境を立ち上げます。 別ウィンドウで起動する IntelliJ 上で実際に プラグイン 機能を試し、バグ調査や動作確認が行えます。 【補足】 Run Plugin 起動設定は、テンプレートプロジェクトですでに 設定 が用意されているため、デフォルトで選択可能です。 5.(省略可) プラグイン のビルドファイルを生成する プラグイン のビルドファイルは、Gradleタスクを実行することで生成できます。 ZIPファイルの生成はリリース作業上必須ではありませんが、何らかの理由で後述のリリースができない場合や、内部的に プラグイン ファイルを共有する際の方法としてご参考ください。 ローカルで生成する ローカル環境で ./gradlew buildPlugin を実行することで、プロジェクト内の build/distributions にZIPファイルが生成されます。 生成されたZIPファイルを IntelliJ の 設定 > プラグイン 画面からインストールすることで、 プラグイン が利用可能になります。 GitHub Actionsで生成する テンプレートプロジェクトで用意されている GitHubActionsのビルドワークフロー を実行することで、 GitHub 上からも同様のZIPファイルがダウンロードできます。 テンプレートでは、Pull Request作成時、またはmainブランチにプッシュされた時にこのワークフローが実行されます。 生成されたファイルは、 GitHub リポジトリ の Actionsタブ > Build > 実行されたワークフロー > Summary を選択し、画面下部のArtifactからダウンロードします。 6. マーケットプレイス に公開する JetBrains マーケットプレイス への プラグイン リリースでは、Gradleタスク publishPlugin を実行します。 このタスクにはアカウント設定やリリース公開 トーク ンが必要になります。 ここでは、ローカルや GitHub Actionsで必要な作業のみを記載しますので、 事前にアカウント登録や トーク ン生成の詳細な手順は 公式ドキュメント を参照し、JetBrainsアカウント情報と トーク ンを作成してください。 リリース作業で用意するもの JetBrainsアカウント( マーケットプレイス に公開する プラグイン を管理するアカウント) プラグイン 公開 トーク ン プラグイン 署名用の 秘密鍵 プラグイン 署名用の証明書 プラグイン の署名情報を生成する プラグイン 署名に使用する 秘密鍵 と証明書生成コマンドは 公式ドキュメント を参照してください。 ここで生成された 秘密鍵 、パスワードなどはハードコードせず、 環境変数 として設定します。 後で確認できるように保管しておきましょう。 【補足】 文字列として登録するため、「 Doma Tools」ではGradleタスクを実装し Base64 に変換しています。 Base64に変換するためのGradleタスク実装 シークレット 環境変数 を設定 GitHub の 環境変数 設定 署名情報は非公開にして扱う必要があるため、 GitHub で扱う際は リポジトリ シークレットとして登録します。 GitHub の リポジトリ 設定の Sercrets and variables > Actions > Sercretsタブ > Repository secrets で、以下を登録します。 環境変数 名 値 CERTIFICATE_CHAIN 証明書チェーン(chain.crtを Base64 化) PRIVATE_KEY 秘密鍵 (private.pemを Base64 化) PRIVATE_KEY_PASSWORD 秘密鍵 のパスワード PUBLISH_TOKEN JetBrainsアカウントページで生成したToken ローカルでの 環境変数 設定 ローカルからリリースする場合、以下のようにGradleタスク publishPlugin の起動設定を用意し、 Enviroment variables へ GitHubの環境変数設定 と同様の 環境変数 を設定してください。 この方法で設定した 環境変数 は、起動設定と同じ /.run 内の XML ファイルに保存されます。 XML ファイルを外部に公開しないように、 リポジトリ へのプッシュ時などの取り扱いにご注意ください。 リリース公開 mainブランチへのマージ忘れがなければ、以上で準備完了です。 リリース作業は非常に簡潔で、 GitHub 上のリリースノート公開をするだけで自動で マーケットプレイス にリリースされます。 リリース処理の実体はテンプレートで用意されている GitHub Actionsとなっており、そのまま利用可能です。 「 Doma Tools」では、このワークフロー実行時に次回リリースの仮バージョンを生成するなどの実装を追加しています。 GitHub のリリース画面を開く 下書き状態のリリースノートの編集を編集する リリースノートの内容を必要に応じて編集する リリースタグを マーケットプレイス にリリースしたいバージョンと同じ名前で設定する 画面下部で Set as the latest release にチェックを入れ、 Publish release を押下 リリースノートが公開されると同時に、 GitHub Actionsの releaseワークフロー が起動します。 ワークフロー正常終了後、自身の マーケットプレイス 管理画面や IntelliJ の プラグイン 検索画面で、最新バージョンの プラグイン がアップロードされていることを確認しましょう! 【補足】 マーケットプレイス へ プラグイン をアップロードすると、JetBrainsによる審査が開始されます。 審査完了後に、正式に マーケットプレイス 画面で最新バージョンが表示されます。 その他 マーケットプレイス に関する詳細は、 マーケットプレイス公式ドキュメント をご参照ください。 参考: マーケットプレイス チャネルの使い分け JetBrainsの マーケットプレイス には チャネル という概念があります。 普段 マーケットプレイス 画面の検索で表示される プラグイン は、デフォルトの「Stable」チャネルにアップロードされているものになります。 例えば、開発者内に限定で マーケットプレイス にあげたい場合や、テスター向けのバージョンを限定公開したい場合などには、任意のチャネルにアップロードすることが可能です。 IntelliJ公式ドキュメント マーケットプレイス 画面で直接アップロードする publishPlugin を実行せずとも、 プラグインのビルドファイルを生成する で生成したZIPファイルを、 マーケットプレイス 管理画面から直接アップロードすることでもリリースが可能です。 管理画面右上の「Upload Update」ボタンを押すと、アップロードする プラグイン ファイルとチャネルの設定ダイアログが表示されます。 「 Chanel 」で任意の文字列を入力するか、既存のチャネルを選択することでアップロード先を選択できます。 一般的に、ベータ版は「beta」、先行リリース版は「 eap 」とチャネル名が名付けられます。 Gradleタスクでもチャネルを自動制御する 実はテンプレートの publishPlugin 設定でも、 プラグイン バージョンを基にリリース先のチャネルを切り替えられるようになっています。 Gradleタスク publishPlugin 実行時、 セマンティック バージョニング に従ってプレリリース識別子を取得し、識別子名と同じチャネルにリリースされます。 (プレリリース識別子がないバージョンは、デフォルトの「Stable」チャネルにリリースされます) プラグインバージョンの識別とチャネル判定処理 【例】 プラグイン バージョン:1.1.0-beta.123.0でリリースした場合 、 チャネル「beta」にver1.1.0-beta.123.0の プラグイン が登録されます。 IntelliJ 上から任意のチャネルの プラグイン を取得する 任意のチャネルにアップロードされた プラグイン は、 IntelliJ に設定を追加することでそのバージョンを参照することも可能になります。 IntelliJ 上で、 設定 > プラグイン を開き、上部の歯車アイコンから ManagePluginRepositories... を選択すると、参照したいチャネルのURLを登録する画面が表示されます。 ここに任意のチャネルのURLを追加することで、任意のチャネルにリリースされた プラグイン バージョンが使用可能になります。 さいごに 今回は プラグイン 開発の始め方ということで、環境構築からリリースまでの簡単な流れをご紹介しました。 開発を始めてから、 IntelliJ プラットフォームのルールや GitHub Actionsの動きなど分からないことがたくさんありましたが、 他の OSS やコミュニティの投稿などを参考にしていくことで段々と機能を実現していけるようになりました。 今後も「 Doma Tools」をベースにした機能実装方法について投稿していきますので、引き続きよろしくお願いいたします。 ご興味を持たれた方は、是非 プラグイン 開発に挑戦してみてください! レビューも投稿していただけますと大変励みになります🙇‍♀️ Doma Tools マーケットプレイスページ 本 プラグイン は OSS として Domaコミュニティ へ寄贈されています。 不具合修正や機能要望、ディスカッションにもぜひご参加ください。 採用ページ 執筆: @terao.haruka 、レビュー: @nakamura.toshihiro ( Shodo で執筆されました )
アバター
はじめまして。 電通 総研ITの寺尾です。 本記事では、私が開発に携わったJetBrainsの IntelliJ 向けの プラグイン 「 Doma Tools for IntelliJ 」(以下、「 Doma Tools」と表記)についてご紹介します。 「Doma Tools」とは Domaとは? 主要機能紹介 ファイルジャンプ コード検査 DAOメソッドに紐づくSQLファイルチェック 未使用の引数チェック 不正なバインド変数チェック コード補完 SQLフォーマット(プレビュー機能) さいごに 「 Doma Tools」とは 「 Doma Tools」は、 IntelliJ IDEA上で Doma を用いた開発を支援するためのツールです。 IntelliJ IDEAのUltimateやCommunity Editionで動作し、 Doma のDAOや SQL に焦点を当てた便利な機能を提供します。 Doma とは? Doma は、 Java やKotlinで実装されたアプリケーションにおいて、データの取得や更新を実現する OSS の フレームワーク です。 詳細は、公式のドキュメントをご参照ください。 Doma 主要機能紹介 ver1.0.0時点での「 Doma Tools」のメイン機能の一部について紹介させていただきます。 その他の機能については、 プラグイン リポジトリ の README をご参照ください。 ファイルジャンプ 大きなプロジェクトになると、DAO名から対応する SQL ファイルを探す作業がかなりの手間になります。 似たようなメソッド名が多いとなおのこと。 IntelliJ の検索アクションを利用しても開くファイルを間違えてしまうかもしれません😭 「 Doma Tools」ではアクションとガターアイコンにより、一発でDAOインタフェースファイルと SQL ファイルを相互移動できるようにします。 DAOメソッド名上でメニューを開き、 Doma Tools > Jump to SQL を選択、またはショートカットキーで対応する SQL ファイルを開くことができます。 DAOメソッドの行に表示されるガターアイコンをクリックすることでも、 SQL ファイルにジャンプ可能です。 その逆も然り、 SQL ファイル上でも同様にアクションやガターアイコンからDAOメソッド定義箇所にジャンプすることができます。 コード検査 ビルド時に初めて Doma にエラーを出されてしまい、地道な修正作業が始まる……。 コーディング時に問題箇所が分からないとストレスになることはないでしょうか。 この プラグイン では Doma のルールに違反している箇所をエラーハイライトし、コーディングしながら問題箇所も発見できるコード検査機能を提供します。 DAOメソッドに紐づく SQL ファイルチェック DAOメソッドに対応する SQL ファイルが存在しない場合、メソッド名が赤文字でハイライトされます。 同時にクイックフィックスが提案され、ワンクリックで対応するリソース ディレクト リに SQL ファイルが生成されます📝 未使用の引数チェック SQL 内で使用されていないDAOメソッドパラメーターをエラーハイライトし、実装漏れを発見できるようになります。 不正なバインド変数チェック SQL ファイル内で、DAOメソッドのパラメーターにないバインド変数や、存在しないフィールド、メソッドの呼び出しなどをエラーハイライトします。 コピペしたままで混入した、誤った変数名やクラス名も即座に発見できます🔍 コード補完 SQL 内でバインド変数のコーディングを行う際、「こんな変数名だったっけ…」となりDAOメソッドやEntityクラスの定義を見に行くことはないでしょうか? コード補完機能により、DAOメソッドのパラメーターから変数名候補を提供します。 また、パラメーターの型に基づいたフィールド、メソッドも補完されます。 静的フィールド、メソッドへのアクセス でも同様に、クラス名からstaticなプロパティの補完までサポートします。 SQL フォーマット( プレビュー機能 ) フォーマットを統一することが大事なことは分かっていても、外部のフォーマットツールの選定は大変…。ということもあるでしょう😔 「 Doma Tools」でも、 SQL フォーマットルールを統一できる機能の提供を目指しています。 こちらはまだプレビュー版となります。現在は基本的なクエリのフォーマットをサポートしています。 SQL キーワードをレベル分けし、レベルやキーワードの組み合わせによって改行、インデントルールを指定しています。 そのほか、複数のカラム行が見やすくなるような改行や、サブクエリグループを視覚的に判別しやすくなるようなフォーマッターの開発を進めています。 さいごに 初めての プラグイン 開発、そして初めてのKotlin実装でしたが、無事リリースができたことを嬉しく思います。 プラグイン 開発において課題解決に試行錯誤を重ね、実装だけでなく OSS とすることを意識した今回のプロジェクトからは、 技術者として多くの学びを得られました😊 今後は「 Doma Tools」の開発経験を基にした、具体的な プラグイン 機能実装についてもご紹介していきますので、引き続きご覧いただけますと幸いです。 これからも多くの Doma プロジェクト開発者の貢献に繋がるようアップデートを重ねていきますので、 IntelliJ + Doma を使った開発をされている方はぜひご活用ください! レビューも投稿していただけますと大変励みになります🙇‍♀️ Doma Tools マーケットプレースページ 本 プラグイン は OSS として Domaコミュニティ へ寄贈されています。 不具合修正や機能要望、ディスカッションにもぜひご参加ください。 採用ページ 執筆: @terao.haruka 、レビュー: @nakamura.toshihiro ( Shodo で執筆されました )
アバター
こんにちは、スマート ソサエティ センターの飯田です。 はじめに NotebookLMでは、文章をアップロードすると、 マインドマップ 形式で内容を可視化することができます。 この機能により、情報の整理や関連性の把握が容易になります。 デジタル庁が公開している ChatGPT 等の生成 AI の業務利用に関する申合せ(第2版) を入力してみると下記のような結果が得られます。 NotebookLMでこのような見せ方ができるということは、Geminiでもナレッジグラフ生成ができるのでは?と思い、Geminiをつかって、どこまでナレッジグラフを抽出できるかを試してみてみました。 そして、抽出した結果をGraphRAGに入力し、どのような情報が得られるかを確認してみました。 ※プリミティブな実装しかしていないので、本当はもっと性能がでるかもしれないですが、ご容赦ください。 対象のデータ 対象のデータは、デジタル庁の「ChatGPT等の生成AIの業務利用に関する申合せ(第2版)」です。 このドキュメントは、 自治 体における生成AIの業務利用に関する ガイドライン を提供しており、AIの利用に関する重要な情報が含まれています。 このドキュメントをもとに、ナレッジグラフを抽出し、GraphRAGでの情報検索を行います。 全体の処理の流れ 流れとしては以下のような流れです Geminiを使用してドキュメントからナレッジグラフを抽出 抽出したナレッジグラフを可視化・結果の確認 抽出したナレッジグラフをGraphRAGに入力 GraphRAGを使用して情報検索を行い、関連情報を取得 ナレッジグラフの抽出 ナレッジグラフの抽出には、GraphRAGに繋げることも意識して、langchainのlangchain_experimental.graph_transformersを使ってみました。 langchainにGraphRAGの機能が追加されているのを知りませんでした。 便利になりましたね。 実装の一部としてはこんな感じです llm_transformer = LLMGraphTransformer(llm=llm) graph_documents = llm_transformer.convert_to_graph_documents(documents) 抽出結果 graph.draw_ graphviz でグラフの可視化をすると下記のような結果が得られました。 いい感じに抽出できていそうです。 また、ネットワークとしては、下記のような形になっています。 [( 'Agreement On Business Use Of Generative Ai (2Nd Edition)' , 'Digital Society Promotion Council Secretariat' , 'ISSUED_BY' ), ( 'Agreement On Business Use Of Generative Ai (2Nd Edition)' , 'Generative Ai' , 'CONCERNS' ), ( 'Agreement On Business Use Of Generative Ai (2Nd Edition)' , 'Government Ministries And Agencies' , 'FOR' ), ( 'Agreement On Business Use Of Generative Ai (2Nd Edition)' , 'Ai Strategy Council' , 'BASED_ON' ), ( 'Agreement On Business Use Of Generative Ai (2Nd Edition)' , 'Ai Strategy Team' , 'BASED_ON' ), ( 'Chatgpt' , 'Generative Ai' , 'IS_A' ), ( 'Chatgpt' , 'Contract-Based Cloud Service' , 'CLASSIFIED_AS' ), ( 'Government Ministries And Agencies' , 'Contract-Based Cloud Service' , 'MANAGES' ), ( 'Contract-Based Cloud Service' , 'Confidential Information' , 'CANNOT_HANDLE' ), ( 'Contract-Based Cloud Service' , 'Government Unified Standards' , 'DEFINED_BY' ), ( 'Shadow It' , 'Information Leakage' , 'INCREASES' ), ( 'Institutions, Etc.' , 'Government Unified Standards' , 'MENTIONED_IN' ), ( 'Institutions, Etc.' , 'Security Measures' , 'RELATED_TO' ), ( 'Institutions, Etc.' , 'Data Handling' , 'RELATED_TO' ), ( '約款型クラウドサービス' , '要機密情報' , 'CANNOT_HANDLE' ), ( '約款型クラウドサービス' , '要機密情報を含まない情報の取扱い' , 'USED_FOR' ), ( '生成Ai' , '約款型クラウドサービス' , 'CAN_BE_USED_VIA' ), ( '生成Ai' , '個別契約等に基づく利用' , 'CAN_BE_USED_VIA' ), ( '個別契約等に基づく利用' , 'クラウドサービス関連規程' , 'REQUIRES_COMPLIANCE_WITH' ), ( '個別契約等に基づく利用' , '機密性2情報' , 'CAN_HANDLE' ), ( '個別契約等に基づく利用' , '機密性2情報取扱いのための措置' , 'REQUIRES' ), ( '個別契約等に基づく利用' , 'Ai戦略チーム' , 'REQUIRES_UNDERSTANDING_FROM' ), ( '個別契約等に基づく利用' , '組織の規程' , 'REQUIRES_APPROVAL_BY' ), ( '個別契約等に基づく利用' , '要機密情報を含まない情報の取扱い' , 'USED_FOR' ), ( '職員等' , '約款型クラウドサービス' , 'SHOULD_BE_INFORMED_ABOUT' ), ( '職員等' , '要機密情報' , 'SHOULD_BE_INFORMED_ABOUT' ), ( '職員等' , 'クラウドサービス' , 'USES' ), ( '職員等' , '定型約款や規約等' , 'REVIEWS' ), ( '職員等' , '利用申請の許可権限者' , 'APPLIES_TO' ), ( '関係省庁' , '個別契約等に基づく利用' , 'CONSIDERS' ), ( '関係省庁' , 'Ai戦略チーム' , 'OBTAINS_UNDERSTANDING_FROM' ), ( '要機密情報を含まない情報の取扱い' , '組織の規程' , 'REQUIRES_APPROVAL_BY' ), ( '要機密情報を含まない情報の取扱い' , 'Ai戦略チーム' , 'DOES_NOT_REQUIRE_REPORT_TO' ), ( '統括情報セキュリティ責任者' , '運用規程' , 'ESTABLISHES' ), ( '運用規程' , 'クラウドサービス' , 'GOVERNS_USAGE_OF' ), ( 'クラウドサービス' , '要機密情報' , 'CANNOT_HANDLE' ), ( '利用申請の許可権限者' , 'クラウドサービス' , 'APPROVES_USAGE_OF' ), ( '利用申請の許可権限者' , 'クラウドサービス管理者' , 'APPOINTS' ), ( 'クラウドサービス管理者' , '適切な措置' , 'TAKES' ), ( '適切な措置' , '安全な利用' , 'ENSURES' ), ( '安全な利用' , '要機密情報を取り扱わないクラウドサービス' , 'OF' )] この得られたグラフの情報をつかって、LangChainのGraphQAChainをつかって質問をしてみます。 下記のような実装のイメージです # グラフとLLMを使ってQAチェーンを作成 chain = GraphQAChain.from_llm( llm=llm, graph=graph, verbose= False ) question = input ( "質問を入力してください " ) result=chain.run(question) print (f " \n [回答]: {result}" ) その結果は下記の通りです。 このケースでは、そこそこいい感じに取れていますね。 ChatGPTについて詳しくまとめてください [回答]: 提供された知識に基づくと、ChatGPTについては以下のことがわかります。 ChatGPTはGenerative Aiです。 ChatGPTはContract-Based Cloud Serviceに分類されます。 サンプルを実装したときの感想 GraphRAGは数年前に話題になってから気になっており、ようやく触れたというカタチなのですが、 実装はLangChainのおかげて、シンプルに実装できたと思います。 ただ、プロダクションに投入するか?と言われると、このまま持っていくのは難しそうという印象を受けました。 1つは、処理時間の問題。ネットワークのグラフ構造を抽出する部分は、処理に時間がかかりました。 また、質問に対する精度についても、検索結果にヒットしないことも多く、一般的なRAGを超えるようにするには使い方とデータの与え方が難しいなという感想です。 グラフデータベースに慣れていないというのもあり、一般的なRAGに比べると、”検索”で何をどう検索しているかの感覚が、通常のデータベースと異なってくるので、直感的な理解が難しいなとも思いました。 うまく、GraphRAGを使いこなせるようになれるといいなと思いました。 おまけ シンプルにLLMにプロンプトで指示するだけでもある程度のグラフ構造を取得できます。 情報の理解や、グラフ構造による分析をしていくには、Geminiで前処理をしてしまうのは、 コストパフォーマンスがよくグラフ情報の抽出ができるかなと思うので、ナレッジグラフの抽出はどこかで使えたらいいなと思っています。 以下は、Geminiアプリの canvas でネットワークを可視化したもの 最後まで読んでいただき、ありがとうございました。 ↓ のスターを押していただけると嬉しいです。励みになります。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @iida.michitaka7b3a3dd24e9c454b 、レビュー: @miyazawa.hibiki ( Shodo で執筆されました )
アバター
はじめまして。製造エンジニアリング本部 SPDM技術部の冨永です。 本記事では、2024年4月に新卒で 電通 総研に入社してから約1年、部署に配属されてから半年が経過した私の現在の業務内容や働き方を中心に紹介したいと思います。あくまで私が所属している部署の話にはなりますが、読者の皆様には本記事を通して、 電通 総研での業務内容や働き方について少しでもご理解いただければ幸いです。 1. 電通総研の志望理由と入社の決め手 2. 現在の業務について 2.1. 業務内容 2.2. 業務のやりがいや難しさ 2.3. 今後の野望 3. 働き方 3.1. 1日のスケジュール 3.2. こだわり 4. 最後に 1. 電通 総研の志望理由と入社の決め手 本題に入る前に私が 電通 総研(当時ISID)を志望した理由をお話したいと思います。私が就活生時代に掲げていた「就活の軸」は以下2点でした。 ① 顧客業務の効率化に寄与する仕事をして、組織全体の持つ力を最大限に引き出し、社会の変革の一端を担う当事者になりたい。 ② 自分らしく、そして楽しく働きたい。 特に②は譲れない軸でした。仮に20-60歳まで働き、90歳まで生きるとした場合、その中で仕事が占める割合は意外と1~2割程度らしいですが、平日のほとんどを仕事に費やすことになります。だからこそ、自分らしく、楽しく働ける環境が自分の人生を充実させるために重要だと考えていました。そして、個人的に②に関しては 電通 総研でしか実現できないと感じました。というのも、就活生時代に 電通 総研主催の社員座談会に参加したのですが、その座談会の場で1人の社員の方が「 電通 総研の社長になりたい。」と本気で語られていたことや、社員の皆さんが年次関係なく楽しく交流されている姿を見て、「 電通 総研であれば夢を持って仕事ができそう!」とか、ほかの会社とは違う雰囲気(おそらく人間魅力)を感じました。就活期間中、他社から内定をいただき悩みましたが、自分が楽しく働いている姿を最も強くイメージすることができたこともあり、 電通 総研への入社を決意しました。 2. 現在の業務について ここでは私の現在の業務について紹介します。 2.1. 業務内容 現在は、製造エンジニアリング本部SPDM技術部で製造業のお客様向けに、 電通 総研のSPDM(Simulation Process and Data Management)製品である「 i-SPiDM(アイ・エスピーディーエム) 」の導入支援に携わっています。昨今、市場競争の激化や顧客ニーズの多様化、労働者不足など、製造業を取り巻く環境がより一層厳しくなっており、製品 開発プロセス のさらなる効率化とリードタイムの短縮が強く求められています。i-SPiDMは製品開発における検証業務の効率化と品質向上に寄与することができ、現在多くの製造業のお客様にご利用いただいている製品となっています。部に配属されてから約6ヵ月が経過し、自動車 OEM をはじめとした様々な製造業のお客様向けに、案件関係メンバと顧客業務の ヒアリ ングを行い、業務プロセスに適したi-SPiDM運用方法の検討および提案を実施しています。また、i-SPiDMのプリセールス(製品紹介や製品デモ)も実施するなど、技術者として手を動かすだけでなく、お客様と直接会話をするような場面にも多く携わっています。 2.2. 業務のやりがいや難しさ 様々な製造業のお客様へi-SPiDMという製品の導入を通して、私の軸でもあった「変革の一端を担う当事者になりたい」その思いを実現できており、大きなやりがいを感じています。同じ製造業であってもお客様毎に業務フローは異なっており、異なるニーズに応じたカスタマイズや、抜け漏れない要件の抽出など、日々新しい課題に取り組むことは非常に難しくもありますが、刺激的な毎日を送ることができていると感じています。 2.3. 今後の野望 私の今後の野望は “SPDMツールのスタンダードをi-SPiDMにする” です。 i-SPiDMはデータ管理や解析ジョブ管理機能を持ち、検証作業を効率化する強力なツールです。私自身、大学の研究室でデータ管理や解析ジョブ管理に課題感を持っていました。深夜にシミュレーションを実行するためだけに研究室に行き、翌朝シミュレーション結果を取得する。そんなブラックすぎる時間を過ごしていた時もありました。私の事例は極端かもしれませんが、現在でも、多くの企業や大学の研究室で大なり小なり同様の課題があると認識しています。なので、i-SPiDMの利用によって検証業務に携わられている全ての方々に非効率な作業から解放されてほしいと思っています。 3. 働き方 ここでは私の現在の働き方を紹介します。 3.1. 1日のスケジュール 以下は、私の出社した日のスケジュールの一例です。 9:30 出社:メールチェックやその日のタスクの確認を行います。 10:00 - 12:00 顧客会議:お客様との打ち合わせを行います。i-SPiDM運用案などをお客様にご提示し擦り合わせを実施します。 12:00 - 13:00 昼食:同僚と一緒にランチを楽しみながら、リフレッシュします。 13:00 - 14:00チームMTG:お客様との会議で得られた情報をチームメンバと整理します。 14:00 - 15:00 事前会議:別日に実施されるお客様との会議に向けて、事前に アジェンダ 検討や打ち合わせのゴールを明確にします。 15:00 - 16:00顧客会議:お客様向けにi-SPiDMプリセールスを実施します。 16:00 - 16:15 休憩 :(コンビニでおやつを買って糖分補給…) 16:30 - 17:30 社内定例:私が所属するユニットでは新人主催で合同勉強会を隔月で実施しています。その打ち合わせをユニットの同期メンバと行います。 17:30 翌日の作業確認:翌日の予定・作業を確認します。 18:00 退勤: この日は会議が多めの1日でした。社内または顧客会議が多くある日は頭を切り替えるのが大変です。(^^; 3.2. こだわり 私自身、面直の会話が好きなので、出社の頻度が高め(Ave. 週4出社)です。少し前時代的考えなのかもしれませんが、対面でのコミュニケーションは話し相手の細かなニュアンスや表情を読み取ることができ、より深い理解を得ることができると感じています。また、オフィスでの雑談やランチタイムの交流も、仕事のモチベーションを高める大切な要素です。帰宅後は手帳に残タスクの書き出しやタスクの優先順位付けを行っています。脳は多くのエネルギーを消費するため、省エネな性格だとか何かの本で読んだ記憶があります。なので、無理に頭の中で整理しようとはせず、書き出してビジュアル化することを心掛けるようにしています。 4. 最後に ここまで読んでいただいた皆様、お付き合いいただきありがとうございました。 To:社外の方 この記事を通じて、私の現在の業務内容や働き方を少しでもお伝えでき、 電通 総研について理解を深める一助になることができましたら幸いです。 To:社内の方 電通 総研に入社し1年、素敵な147名の同期と先輩方に出会い、この上なく恵まれた環境で仕事ができることに日々感謝しています。これからも楽しみながら自己成長を続け、会社に貢献できるよう努力してまいりますので、今後ともどうぞよろしくお願いいたします!! 執筆: @tominaga.ds 、レビュー: @nakamura.toshihiro ( Shodo で執筆されました )
アバター
スマート ソサエティ センターの飯田です。 突然ですが、今回のエントリーでは、 コードを1行も書かずに、ア イデア を形にする衝撃 をお伝えします。 前回のブログ でお見せしたGeminiと音声通話を連携させるデモ実装、実は ソースコード を1行も書いていません tech.dentsusoken.com デザインのクオリティも問題ない、さらにはGeminiのような生成AIの組み込みまでが、コーディング作業なしにできちゃう世界になってきてます。 これまでは、「こんなサービスが欲しい」というア イデア を思いつくと、下記のようなステップで最初のMVP(Minimum Viable Product)を制作していました。 Figma でのUIデザイン まず Figma を使い、画面遷移や見た目のイメージを具体化(いわゆる「紙芝居」) 価値の概念実装 「紙芝居」だけでは伝えきれないサービスの核心的価値、特にAIによる分析の「凄さ」などは、別途、概念実証(PoC)のための簡易的な実装を行う 新規事業開発において最も重要なのは「いかに早く仮説を構築し、顧客からのフィードバックを得るか」、 つまり「いかに早く失敗し、学習するか」だと考えています。このサイクルを高速化することこそ、成功の鍵を握ります。 私自身、プログラミング実装のスキルは持っていますが、得意ではなく、決してスピーディーとは言えません苦笑 そのため、このプロセスには、それなりの時間と労力が必要でした。 それが、Firebase Studioの登場により、AIがコーディングをしてくれるようになり、実装の時間が大幅に短縮されました。 Firebase Studioとは何か? 何ができるのか? FirebaseStudioは2025/4月に Google が発表した クラウド ベースのエージェント開発環境です。 2025/6/1現在、Firebase Studio はプレビュー版ですので、ご注意ください https://firebase.google.com/docs/studio?hl=ja ざっくりの使い方は以下のとおりです アプリのベースとなる機能や実現したいことをプロンプトで入力する 機能やデザインのトンマナ、使用する フレームワーク などの確認があるので、問題なければ作成をする 修正や機能を加えていく。右下のプロンプトで指示を入れていきます UIの言語を英語から日本語に変更したい場合の例 AIが理解してくれて、 ソースコード の修正を行ってくれます。 どこにどういう変更をいれたのかも教えてくれます タブからエレメント指定モードにすれば、特定の要素に対する指示もできます ちなみに、GeminiはGemini API を入力をすれば、すぐに連携してくれます 右上のPublishボタンをおすと、新しくFirebaseプロジェクトが作られて、AppHostingにデプロイされます 参考:FirebaseStudio公式のプロンプトテクニック  https://firebase.google.com/docs/studio/prompting?hl=ja 「FirebaseStudio」の魅力 ノーコード/ローコードでのUI構築 Figma のようなデザインツールでUIを設計する感覚で、あるいはそれ以上の速さで、実際に動作するフロントエンドを構築できます。 デザインの再現性も高く、プロトタイプの段階から高品質なユーザー体験を提供可能です。 Gemini AIのシームレスな統合 Geminiをはじめとする生成AIモデルを、複雑なコーディングなしにアプリケーションに組み込むことができます。これにより、これまで概念実証に留まっていたAI活用ア イデア も、手軽に実サービスに近い形で検証できるようになります。 開発サイクルの劇的短縮 上記の特徴により、ア イデア の着想から実際にユーザーが触れるプロトタイプ完成までの時間が圧倒的に短縮されます。これは、「早く失敗し、早く学ぶ」というリーンな 開発プロセス を強力に後押しします。 FirebaseStudioがもたらす、MVP開発の パラダイム シフト このMVPの検証を回すための時間と苦労が、「FirebaseStudio」によってガラリと変わりました。 FirebaseStudioによって、 Figma でUIデザインを描くよりも速く、かつ、実際に動作するAI組込みのプロトタイプが完成してしまう のです。 MVPやプロトタイプの開発のあり方そのものが、根本から変わるほどの インパク トを感じました。 ア イデア の着想から検証までのリードタイムが劇的に短縮され、動くWebアプリを顧客に提示でき、より多くの挑戦と、より質の高い フィードバックループ ができます。 今後、重点的に検証していきたいポイント ただし、MVPで終わらず、プロダクションコードにそのままもっていけるか?その実用性を確かめるためには、さらに以下の点を深掘りして見ていく必要があると考えています。 生成されるコードの品質 ノーコード/ローコードで生成されたコードが、どの程度の品質と保守性を備えているのか。 データベースとの連携 実際のアプリケーション開発に不可欠なデータベース(Firebase Realtime DatabaseやCloud Firestoreなど)との連携は、どの程度スムーズに行えるのか。 プロダクション利用へのハードル 作成したプロトタイプを、実際の製品コードとして利用していく際に、技術的な障壁や制約がないか。 ご注意 ログイン認証とかをそのまま指示してしまうと、 JavaScript に埋め込む方式で実装してくる可能性もあるので注意してください これらの検証を通じて、「FirebaseStudio」が持つ真のポテンシャルを見極めていきたいと考えています。 思考が即座に形になる未来 最後に、私が「FirebaseStudio」とGeminiの組み合わせで最も感動した体験を少しだけ。 それは、最初のプロンプトもGeminiに考えてもらい、編集もさらに 音声入力 で『ここのボタンの色を赤に変えて』『このリストに検索機能を追加して』といったプロンプトをいれていくという開発スタイルです。 アプリ開発 を行うときに、「なんかこんな感じのモノ」が欲しいというように、イメージはあるが 言語化 できないということがあると思います。その 言語化 もGeminiがサポートしてくれますし、音声入力を使うことで、頭の中にあるア イデア がリアルタイムに具現化されていく開発体験になりました。 「アプリを実装している」感覚ではなく、 「どういうアプリがいいかを議論していたら、そのまま議論のアプリが作られてた」みたいな感覚 です。 「FirebaseStudio」は、新規事業開発の「 自由の翼 」を与えてくれる存在だなぁと思いました。 最後まで読んでいただき、ありがとうございました。 ↓ のスターを押していただけると嬉しいです。励みになります。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @iida.michitaka7b3a3dd24e9c454b 、レビュー: 寺山 輝 (@terayama.akira) ( Shodo で執筆されました )
アバター
はじめに スマート ソサエティ センターの飯田です。 Google の生成AI「Gemini」を音声通話と組み合わせ、電話対応の負担を抑えるプロトタイプを作ってみました。 本記事では、その取り組みと、そこから見えてきた生成AI活用の具体的な可能性についてご紹介します。 背景:深刻化する電話業務の負担と、DXによる解決への期待 顧客からの理不尽な要求や迷惑行為は、近年深刻な社会問題となっています。 従業員の精神的な負担増大や 離職率 の上昇を引き起こし、企業経営にとって看過できない問題となっています。 このような状況を受け、各企業には電話業務軽減への具体的な対策強化が急務となっています。 厚生労働省 も対策の重要性を指摘し、「カスタマーハラスメント対策企業マニュアル」を公開するなど、社会全体での取り組みが進められています。 (参考: 厚生労働省 カスタマーハラスメント対策企業マニュアル ) Geminiを音声コミュニケーションと連携させ、電話対応業務の負荷を下げるプロトタイプを2つ作ってみました! 開発したプロトタイプ1:Geminiと電話で会話できるシステム デモはこちら https://youtube.com/shorts/sWuTqs8g_gU 電話システムとGeminiを直接連携させたプロトタイプを開発しました。 電話応対業務は 感情労働 の側面が強く、AIによる一次対応やオペレーター業務の一部代替は、 従業員の負担軽減と業務効率化に繋がるといいなという想いでつくりました。 アーキテクチャ : このシステムの構成はシンプルで、以下のような形です 電話回線: ユーザーからの電話 Twilio: 電話回線とWebアプリケーションを接続するためのPaaS。着信処理や音声ストリームの制御。 今回は TwiML Bin を利用。 https://www.twilio.com/ja-jp WebSocket (WS): Twilioとバックエンドアプリケーション間でリアルタイムな双方向通信を確立。 バックエンドアプリケーション ( Python on ngrok): WebSocket経由でTwilioから音声データを受け取り、Gemini API へ連携。開発段階では、ローカル環境を外部公開するために ngrok を使用。 Gemini: 受け取ったテキストに基づき、自然な応答メッセージを生成し、 音声合成 (別途実装想定)を通じてユーザーへ返す。 技術的考察と今後の課題: 実装してみたところ、現時点では、Geminiのリアルタイム性を最大限に活かすための Gemini LIVE API などの連携を完全に最適化できないので、若干の応答遅延が発生するケースが見られました。 また、UXの観点からも、より自然でスムーズな対話を実現するためには改善の余地があります。 TwilioからWebSocket経由で音声データを受け取るまでの 区間 にも遅延要因は存在するため、 システム全体のレイテンシを低減するには、ネットワーク設計を含めた総合的な最適化が求められるでしょう。 これらの課題解決は、実用的なAI電話応対システムを構築するうえで重要なポイントとなると思います。 また、以下のようなところも工夫の余地がありそうです RAG (Retrieval Augmented Generation) の活用: 社内マニュアルや過去の対応事例といった独自の知識ベースをGeminiと連携させることで、より文脈に即した的確な深刻度判定や、オペレーターへの具体的な対応アド バイス 生成など、高度な機能実装が期待できます。 Context Caching の最適化: 対話の文脈情報を効率的にキャッシュし再利用することで、Geminiへのリク エス トを最適化し、特にリアルタイム性が重視される検知システムにおける応答速度の向上に寄与する可能性があります。 開発したプロトタイプ2:リアルタイムのオペレーター負担検知Webアプリケーション youtu.be オペレーターと顧客の会話をリアルタイムで分析し、職員負担の兆候を即座に検知するWebアプリケーションも作ってみました。 このシステムは、従業員の保護を強化するとともに、応対品質の向上にも寄与することを目的としています。会話内容からGeminiがオペレーターの負担の深刻度や原因を推論し、オペレーター支援や早期対応に繋がります。 主な機能と特徴: リアルタイム 音声認識 とテキスト化 ブラウザのマイクを通して入力された音声をリアルタイムでテキストに変換。 Geminiによる深刻度判定: 変換されたテキストをGeminiに送信し、会話内容に基づいて「深刻度」と「原因の分類」を推論。状況の客観的な把握を支援。 アラート通知: オペレーター判定の深刻度が高い場合には、管理画面や担当者にアラートを通知し、迅速な介入や エス カレーション。 アーキテクチャ : このWebアプリケーションは、主にフロントエンド技術で構築されており、処理フローは以下のとおりです。 音声取得: ブラウザの Web Speech API を利用してユーザーの音声をリアルタイムに取得。 音声認識 (Speech-to-Text): 同じく Web Speech API の機能で、取得した音声をテキストデータに変換。 負担度判定: テキストデータをGemini API に送信し、負担度の判定(深刻度、原因分類など)をリク エス トします。この際、プロンプトには定義や判断基準となる事例をFew-shotとして含めることで、判定精度の向上を図っています。 結果表示とアラート: Geminiからのレスポンスに基づき、負担度の判定結果を画面に表示。一定以上の深刻度と判定された場合には、アラートを発する仕組み。 まとめ:音声通話とGeminiが開くDXと、より良い顧客コミュニケーションの未来 本記事で紹介したプロトタイプは、音声コミュニケーションとGeminiをはじめとする生成AI技術の組み合わせが持つワクワク感を伝えられたと思います。 顧客コミュニケーション基盤のDXを推進し 、同時にオペレーターの負担対策という喫緊の課題にも対応できる大きな可能性が見えてきました。 同様の課題認識を持つ方々や、新たな技術活用を模索されている方々にとって、何らかの参考となれば幸いです。 従来は 定量 化や即時対応が難しかったコミュニケーションの内容や感情の機微を、Geminiがリアルタイムに分析・評価することで、 電話応対業務の大幅な効率化、従業員の負担軽減、そしてデータに基づいた 顧客満足度 の向上 といったDXの具体的な成果が期待できます。 さらに、様々な社内システムや顧客データと連携することで、 業務プロセス全体の変革や、新たな顧客価値の創出 など、DXのさらなる深化が期待できるのではないでしょうか。 音声コミュニケーションは、AIとの融合によって、よりインテリジェントで価値あるものへと進化を遂げるでしょう。 皆さんは、Geminiのような生成AIと音声通話を組み合わせることで、どのような業務変革や新しい価値創造が生まれると考えますか?ぜひ、ご意見やア イデア をお聞かせください! 最後まで読んでいただき、ありがとうございました。 ↓ のスターを押していただけると嬉しいです。励みになります。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @iida.michitaka7b3a3dd24e9c454b ( Shodo で執筆されました )
アバター
こんにちは。クロス イノベーション 本部 クラウド イノベーション センターの柴田です。 この記事では Visual Studio Code で GitHub Copilot の agent mode と Remote Development を併用した場合に MCP サーバーがどこで実行されるのかをご紹介します。 はじめに GitHub Copilot とは Remote Development とは 前提条件 MCP サーバーはどこで実行されるのか おわりに 参考資料 はじめに GitHub Copilot とは GitHub Copilot は GitHub が提供するコーディングアシスタントです。 AI を活用してコードの補完や生成など様々な機能を提供します。 version 1.99 からは MCP クライアントとしても利用できるようになりました。 Remote Development とは Remote Development は Visual Studio Code の 拡張機能 の 1 つです。 ソースコード を開いたりコマンドや 拡張機能 を実行したりといった Visual Studio Code の各種操作を、ローカル環境と同じようにコンテナ・リモートマシン・ Windows Subsystem for Linux などのリモート環境上で行うことができます。 1 前提条件 この記事は以下の環境を前提とします。 Visual Studio Code version 1.100.2 Remote - SSH version 0.120.0 GitHub Copilot version 1.322.0 この記事の内容の動作確認は Remote Development のうち Remote - SSH でのみ行っています。 MCP サーバーはどこで実行されるのか GitHub Copilot の agent mode と Remote Development を併用した場合に MCP サーバーはどこで実行されるのでしょうか。 microsoft/vscode#243687 には以下のようにコメントされています。 VS Code will run the tool wherever it is configured. If it is configured in your user settings, then it will run on the VS Code 'host'. If they are configured in your remote settings or in workspace settings, then they will be run in the remote. つまり先ほどの質問への答えは以下のようになります。 MCP サーバの構成をどこに記述したか MCP サーバがどこで実行されるか ユーザー設定(ローカルの settings.json ) ローカル環境 リモート設定(リモートの settings.json ) リモート環境 ワークスペース設定(ワークスペースの .vscode/mcp.json ) ワークスペース のある環境(≒ リモート環境) もし MCP サーバーが期待通り起動しない場合は、 MCP サーバーの設定がどこに記述されているか、そして MCP サーバーがどこで実行されているかを確認してみるとよいでしょう。 おわりに この記事では Visual Studio Code で GitHub Copilot の agent mode と Remote Development を併用した場合に MCP サーバーがどこで実行されるのかをご紹介しました。最後までお読みいただき、ありがとうございました。 参考資料 MCP servers run on local machine, not in remote · Issue #10920 · microsoft/vscode-remote-release Vscode in WSL using other environment to connect to MCP Servers · Issue #245050 · microsoft/vscode Allow running and detecting servers on WSL2 · Issue #243687 · microsoft/vscode 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @shibata.takao 、レビュー: @kobayashi.hinami ( Shodo で執筆されました ) https://code.visualstudio.com/docs/remote/remote-overview より引用。 ↩
アバター
こんにちは。クロス イノベーション 本部 クラウド イノベーション センターの柴田です。 最近 Model Context Protocol ( MCP ) が注目を集めていますね。 一部の MCP サーバーは実行に資格情報を必要とします。例えば以下は https://github.com/makenotion/notion-mcp-server の設定例です。 環境変数 OPENAPI_MCP_HEADERS に Notion の integration secret を設定する必要があります。 { " servers ": { " notionApi ": { " command ": " npx ", " args ": [ " -y ", " @notionhq/notion-mcp-server@v1.7.0 " ] , " env ": { " OPENAPI_MCP_HEADERS ": " { \" Authorization \" : \" Bearer ntn_**** \" , \" Notion-Version \" : \" 2022-06-28 \" } " } } } } しかし MCP クライアントの設定ファイルに資格情報を平文でハードコーディングするのはセキュリティの観点から望ましくありません。そこでこの記事では MCP クライアントとして Visual Studio Code を使用する場合に MCP サーバーの実行に必要な資格情報をパラメーター化する方法をご紹介します。 入力変数を利用して資格情報をパラメーター化する おわりに 参考資料 入力変数を利用して資格情報をパラメーター化する Visual Studio Code では 入力変数 を利用して Task や Debugging の設定ファイルの値をパラメーター化できます。同様に MCP サーバーの設定でも入力変数を利用して実行に必要な資格情報をパラメーター化できます。 先ほどの Notion MCP サーバーの設定を入力変数を使って書き直すと以下のようになります。ハードコーディングしていた integration secret がパラメーター化されています。 { " inputs ": [ { " description ": " Notion Integration Secret ", " id ": " notion-integration-secret ", " password ": true , " type ": " promptString " } ] , " servers ": { " notionApi ": { " command ": " npx ", " args ": [ " -y ", " @notionhq/notion-mcp-server@v1.7.0 " ] , " env ": { " OPENAPI_MCP_HEADERS ": " { \" Authorization \" : \" Bearer ${input:notion-integration-secret} \" , \" Notion-Version \" : \" 2022-06-28 \" } " } } } } 早速 MCP サーバーを起動してみましょう。 すると integration secret を入力するプロンプトが表示されます。 integration secret を入力して MCP サーバーを起動しました。試しに適当なプロンプトを入力してみます。 MCP サーバーが正常に動作していることが確認できました。 inputs ブロックを見ると値が格納されていることがわかります( password=true なので表示される値は * に置換されています)。 カーソルを合わせると入力変数の値を編集またはクリアできます。 入力した値は Visual Studio Code によって永続化されます。試しに PC を再起動してみましたが integration secret は残っていました。 Visual Studio Code の公式ドキュメント には以下のように書かれています。 // 💡 Inputs are prompted on first server start, then stored securely by VS Code. 具体的にどうセキュアに保存されるのかは確認できませんでした。「入力した資格情報は Visual Studio Code によってローカルに保存される」ということは認識しておきましょう。 おわりに この記事では Visual Studio Code で MCP サーバーの実行に必要な資格情報をパラメーター化する方法をご紹介しました。最後までお読みいただき、ありがとうございました。 参考資料 Use MCP servers in VS Code (Preview) Variables reference 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @shibata.takao 、レビュー: @handa.kenta ( Shodo で執筆されました )
アバター
こんにちは。 エンタープライズ 第三本部 マーケティング IT部の熊倉です。 このブログでは、 高速に動作する分散処理エンジン「 Apache Spark」 と オープンテーブルフォーマット「Delta Lake」 を基盤としたレイクハウス環境を構築できるDatabricks上で管理しているデー タセット に対して、 名寄せ 処理を行うアプローチについて紹介します。 実際のノートブックの処理についても紹介しようと思っていますが、想定よりも内容が多くなってしまったので、 名寄せ の概要を紹介する「概要編」、 ソースコード など具体的な 名寄せ 処理の具体的な内容を紹介する「 決定論 的マッチング編」「確率的マッチング編」の三部作にしようと思います。 Databricksで実現するデータ名寄せ【概要編】 Databricksで実現するデータ名寄せ【決定論的マッチング編】 Databricksで実現するデータ名寄せ【確率的マッチング編】(本記事) 本記事は確率的マッチング編となります。 名寄せ 処理の概要について説明したブログ記事も公開しておりますので、 名寄せ 処理にまだ馴染みのない方は、ぜひそちらもご覧いただけると幸いです。 本記事ではZinggというライブラリを利用し、確率的マッチングを行う具体的な処理内容や流れについて説明します。Zinggの概要については「Databricksで実現するデータ 名寄せ 【概要編】」で紹介しておりますので、こちらも合わせてご覧ください。 また、本記事の内容はZinggが公開しているExampleとDatabricksが公開しているソリューション アクセラ レータを参考にしております(Example + ソリューション アクセラ レーター + 自分の方でDatabricksの設計に合わせて加筆変更を加えたような形) 適宜こちらのページも参考にしていただきながら本記事の方も読んでいただけると良いかと思います。 Zingg https://github.com/zinggAI/zingg/blob/main/examples/databricks/FebrlExample.ipynb https://www.zingg.ai/documentation-article/identity-resolution-on-databricks-for-customer-360 Databricks https://notebooks.databricks.com/notebooks/RCG/product-er-with-images/index.html#product-er-with-images_1.html では、早速データの 名寄せ を開始していきましょう! Zinggを利用した名寄せ処理の概要 1. ライブラリをインストールする 1. クラスターにライブラリをインストールする 1. ZinggのJARファイルをGitHubからダウンロードします。 2. 適当なVolumeにJARファイルを配置する 3. クラスターの設定からライブラリをインストールする 2. ノートブックでZinggのPythonパッケージをインストールする 2. 名寄せ処理に必要なモジュールやライブラリをインストールする ライブラリのインストール Zinggで利用するワークスペースを整理 名寄せ処理で利用する関数の定義、モジュールのimport 3. Zinggの設定(Config)を定義 4. Zinggのインプット、アウトプット先を設定する 5. フィールドの属性を指定する 6. パラメータを設定する 7. トレーニングデータ作成ジョブを実行する 8. ラベリングに使用するデータセットを作成する 9. ラベリングを行う 10. モデルのトレーニング 11. マッチング結果を確認する まとめ Zinggを利用した 名寄せ 処理の概要 Zinggを利用した 名寄せ は次のステップで行います。 まず最初に 名寄せ 対象デー タセット の項目の属性(テキストや数値項目なのか、どのようなマッチングをしたいかなど)をそれぞれ定義します 定義した内容を元にデー タセット から一致している可能性の高いペアをサンプリングします サンプリングされたペア候補を元に、ユーザがペアの一致、不一致、不明を判断し、ラベリングを行います モデルのト レーニン グに十分な数が集まるまでサンプリングとラベリングを繰り返します 教師データを元にモデルを作成し、 クラスタ ー化を行います クラスタ ー化されたデー タセット ではペアの一致確率が確認できます 一致確率が確認できるので、「XX%以上は一致、XX ~ YY%はユーザで改めて手動マッチング、YY%以下は別人とする」といったようなオペレーションが可能です では、次から実際にDatabricksでZinggの 名寄せ 処理を行う方法について、具体的に紹介していきます。 1. ライブラリをインストールする Zinggをノートブックで利用するためには、次の2ステップが必要になります。 (ノートブックにアタッチする) クラスタ ーにライブラリをインストールする ノートブックでzinggの Python パッケージをインストールする 手順を順番に紹介します。 1. クラスタ ーにライブラリをインストールする 1. ZinggのJARファイルを GitHub からダウンロードします。 以下の GitHub の リポジトリ から、最新のZingg JARファイルをダウンロードします。(25/5月現在0.4.0が最新) https://github.com/zinggAI/zingg/releases 2. 適当なVolumeにJARファイルを配置する ダウンロードしたJARファイルを、任意のVolumeにアップロードします。 クラスタ ーのライブラリは ワークスペース 、Volume、S3などの クラウド ストレージ等に配置されてある必要があるので、Volume以外の場所が良い場合は適宜配置先を変更してください。 https://docs.databricks.com/aws/en/libraries/cluster-libraries 3. クラスタ ーの設定からライブラリをインストールする クラスタ ー設定ページを開き、「ライブラリ」タブから「新規をインストール」を選択し、ステップ2でVolumeに配置したJARファイルを指定してインストールします。 2. ノートブックでZinggの Python パッケージをインストールする 1. でインストールした クラスタ ーをアタッチしたノートブック上で、以下のセルを実行し、Zinggの Python パッケージをインストールします。 %pip install zingg dbutils.library.restartPython() 2. 名寄せ 処理に必要なモジュールやライブラリをインストールする Zinggの他に、ノートブックで使用するその他のライブラリやモジュール、変数をあらかじめインストールまたは準備しておきます。 ライブラリのインストール データを表形式で整形して表示するための Python パッケージ tabulate をインストールします !pip install tabulate dbutils.library.restartPython() Zinggで利用する ワークスペース を整理 Zinggで 名寄せ 対象とするデー タセット の格納場所や、処理結果の出力先となるパスを指定します。 ただし、ここに関して少し注意が必要で、Zinggは Apache Sparkで動作する 名寄せ ライブラリですが、Databricksとネイティブに統合されているわけではないため、実装する際に気をつけなければいけないポイントがあります。 具体的には次のような点に注意が必要です。 Zinggで 名寄せ したいデー タセット はDatabricks上では外部テーブルとして登録されている必要がある Zinggで作成されるデー タセット や、ト レーニン グデータ、モデルなどはUnity Catalogのテーブルとして登録することができないため、DBFSやボリュームなどに作成される ZinggとDatabricks、 クラウド ストレージの関係をまとめると次のような図になります。 そのため、事前に 「インプットしたいデー タセット を外部テーブルとして作成」し、「Zinggの出力先となるVolumeを作成」しておく必要があります。 本記事では作成方法については割愛させていただきますが、以下ページを参考に作成していただけると良いかと思います。 https://docs.databricks.com/aws/ja/tables/external https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-volumes ノートブックでは次のように変数にパスを格納しておきます。 # Zinggで作成されるデータセットや、トレーニングデータ、モデルが格納されるVolume # catalog, schema, volumeはそれぞれ適当な値を指定してください。 zinggDir = "/Volumes/catalog/schema/volume" # モデルのID。名寄せの処理ごとに編集してください。 modelId = "hogehoge-model" # 後述の名寄せ処理でラベル付けした情報が格納されるフォルダ MARKED_DIR = zinggDir + "/" + modelId + "/trainingData/marked/" UNMARKED_DIR = zinggDir + "/" + modelId + "/trainingData/unmarked/" 名寄せ 処理で利用する関数の定義、モジュールのimport 後続の処理で利用する関数を定義したり、モジュールを先にimportします。 import pandas as pd import numpy as np import time import uuid from tabulate import tabulate from ipywidgets import widgets, interact, GridspecLayout import base64 import pyspark.sql.functions as fn ##this code sets up the Zingg Python interface from zingg.client import * from zingg.pipes import * def cleanModel (isFull= False ): if (isFull): dbutils.fs.rm(zinggDir + "/" + modelId, recurse= True ) else : dbutils.fs.rm(MARKED_DIR, recurse= True ) # drop unmarked data dbutils.fs.rm(UNMARKED_DIR, recurse= True ) return # assign label to candidate pair def assign_label (candidate_pairs_pd, z_cluster, label): ''' The purpose of this function is to assign a label to a candidate pair identified by its z_cluster value. Valid labels include: 0 - not matched 1 - matched 2 - uncertain ''' # assign label candidate_pairs_pd.loc[ candidate_pairs_pd[ 'z_cluster' ]==z_cluster, 'z_isMatch' ] = label return def count_labeled_pairs (marked_pd): ''' The purpose of this function is to count the labeled pairs in the marked folder. ''' n_total = len (np.unique(marked_pd[ 'z_cluster' ])) n_positive = len (np.unique(marked_pd[marked_pd[ 'z_isMatch' ]== 1 ][ 'z_cluster' ])) n_negative = len (np.unique(marked_pd[marked_pd[ 'z_isMatch' ]== 0 ][ 'z_cluster' ])) return n_positive, n_negative, n_total # setup widget available_labels = { 'No Match' : 0 , 'Match' : 1 , 'Uncertain' : 2 } # dbutils.widgets.dropdown('label', 'Uncertain', available_labels.keys(), 'Is this pair a match?') 3. Zinggの設定(Config)を定義 Zinggではモデルを作成する際、必要な設定情報はすべて Config (実体は JSON オブジェクト)を介して渡すことになります。 https://docs.zingg.ai/latest/stepbystep/configuration #Zinggを動作させるの必要なConfigの作成をサポートするクラス args = Arguments() # モデル名やZinggの作業ワークスペースをセット args.setModelId(modelId) args.setZinggDir(zinggDir) 4. Zinggのインプット、アウトプット先を設定する インプット( 名寄せ 対象デー タセット の格納先)とアウトプット(処理結果の出力先)を設定します # 名寄せ対象のデータセット # 前述しましたが外部テーブルとして登録されてある必要があります。 input_path = spark.sql( "DESCRIBE DETAIL catalog.schema.table" ).select( 'location' ).collect()[ 0 ][ 'location' ] # Pipeというクラスより、インプットのデータセットを指定する inputPipe = Pipe(name= 'input' , format = 'delta' ) inputPipe.addProperty( 'path' , input_path ) # Argumentsに追加 args.setData(inputPipe) # アウトプットとなるデータセットやモデルが格納されるDBFS上のパス output_path = zinggDir + "/" + modelId + "/outputData" # Pipeというクラスより、アウトプットのデータセットを指定する outputPipe = Pipe( "resultOutput" , format = "delta" ) outputPipe.addProperty( "path" , output_path) # Argumentsに追加 args.setOutput(outputPipe) 5. フィールドの属性を指定する 次に、Zinggがマッチング処理の中でフィールドの取り扱いについて判断するために、使用するフィールド毎に属性を指定します。 マッチのタイプは以下の中から指定できます。詳細はZinggのドキュメントを参照してください。 https://docs.zingg.ai/latest/stepbystep/configuration/field-definitions マッチタイプ 説明 適用対象 FUZZY タイポ、略語、その他のバリエーションを含む大まかなマッチ。 string, integer, long, double, date EXACT バリエーションを許容しない。国コード、PINコード、およびバリエーションが想定されないその他のカテゴリ変数に適しています。 string, integer, long, date, boolean DONT_USE 出力には表示されますが、計算は行われません。出力に必要なIDなどのフィールドに役立ちます。 showConcise がtrueに設定されている場合、DONT_USEフィールドはラベル付け中にユーザーに表示されません。 any EMAIL @文字の前のメールのID部分のみをマッチします。 any PINCODE xxxxx-xxxxのようなPINコードをマッチします(xxxxx付き)。 string NULL_OR_BLANK デフォルトでは、Zinggはnullをマッチとして扱いますが、FUZZYのような別のマッチタイプを持つフィールドにこれ(NULL_OR_BLANK)を追加すると、Zinggはnull値の機能を構築して学習します。 string, integer, long, date, boolean TEXT 2つの文字列間の単語の重複を比較します。 タイプミス があまりない記述的なフィールドに適しています。 string NUMERIC 文字列から数字を抽出し、両方の文字列間で同じものがいくつあるかを比較します(例:アパート番号)。 string NUMERIC_WITH_UNITS 製品コードまたは単位付きの数字を抽出します(例:16gbの文字列)。両方の文字列間で同じものがいくつあるかを比較します。 string ONLY_ ALPHABETS _EXACT アルファベット文字のみを見て、それらが完全に同じであるかどうかを比較します。文字列内の数字が問題ではない場合(例:建物を調べているが、フラット番号を無視したい場合)。 string ONLY_ ALPHABETS _FUZZY 文字列内の数字を無視し、あいまいな比較を実行します。 タイプミス のある住所などのフィールドに役立ちます。NUMERICを使用して番地を個別に調べたい場合。 string MAPPING_(FILENAME) タイプミス 、略語、および指定された値に対するその他のバリエーションとのマッチング。ニックネーム、性別、および会社略語などの場合に使用できます。たとえば、 IBM 、Int. Biz. MachineをInternational Business Machineに、M、0、MrをMaleに(つまり、複数のエンティティを単一のエンティティに) マッピング する場合。 string ノートブックでは次のように設定します。 # フィールド毎にマッチタイプを指定します。 # 名寄せ処理をしたいデータセット毎に実際は設定してください rec_id = FieldDefinition( "rec_id" , "string" , MatchType.DONT_USE) name = FieldDefinition( "name" , "string" , MatchType.FUZZY) ## Match Typeは複数指定可能です。 email = FieldDefinition( "email" , "string" , [MatchType.FUZZY,MatchType.EMAIL]) dob = FieldDefinition( "dob" , "string" , [MatchType.FUZZY,MatchType.NUMERIC]) address = FieldDefinition( "address" , "string" , MatchType.FUZZY) phone = FieldDefinition( "phone" , "string" , [MatchType.FUZZY,MatchType.NUMERIC]) # フィールドの定義をArrayにする fieldDefs = [rec_id, name, email, dob, address, phone] # Argumentsに設定 args.setFieldDefinition(fieldDefs) 6. パラメータを設定する 次に、Spark上で分散処理を行う際のパラメータを設定します。具体的には numPartitions と labelDataSampleSize を設定します。 numPartitions numPartitions は、データを クラスタ 間でどのように分割するかを定義します。 Zinggドキュメント を参照して、データと クラスタ サイズに応じて変更してください。 labelDataSampleSize labelDataSampleSize では、後述する findTrainingData 処理でサンプルする割合を指定できます。サンプリングする割合が大きいほうが、ラベリングする際にケースとして相応しいペアが出力できる可能性が高くなりますが、処理の時間が長くなりすぎる場合もあるので、1/10に減らすなど調整を行ってください。 # Sparkのパーティション数。ドキュメントより推奨はコア数 × 20~30とのこと num_partitions = sc.defaultParallelism * 20 args.setNumPartitions( num_partitions ) # モデルの学習に使用するデータの割合。 # サンプルサイズを小さく保ち、十分なエッジケースを迅速に検出できるよう、0.0001~0.1の間で調整してください。 # サンプルサイズが大きいと、ジョブがfindTrainingDataサンプルを精査するのに時間がかかります。サイズが小さすぎると、Zinggが適切なエッジケースを見つけられない可能性があります。 args.setLabelDataSampleSize( 0.05 ) 7. ト レーニン グデータ作成ジョブを実行する ここまでの設定を用いて、ト レーニン グデータ(ラベリング候補ペア)を作成するジョブ( findTrainingData フェーズ)を実行します。 options = ClientOptions([ClientOptions.PHASE,"findTrainingData"]) # トレーニングデータを特定するジョブを実行 zingg = ZinggWithSpark(args, options) zingg.initAndExecute() 8. ラベリングに使用するデー タセット を作成する ト レーニン グデータの作成が終わったら、ラベリングに使用するデー タセット を作成します。 ちなみに、ステップ7と8の処理(ト レーニン グデータ作成とラベリング用デー タセット 準備)は、 findAndLabel という単一のフェーズ指定で連続実行も可能です。しかし、ト レーニン グデータの作成には時間がかかる場合があるため、ここでは途中から再開しやすいようにステップを分けて記述しています。 options = ClientOptions([ClientOptions.PHASE, "label" ]) # ラベリングに使用するデータセットを作成するジョブを実施 zingg = ZinggWithSpark(args, options) zingg.init() 次に、ラベリングの候補となるペアが何件あるか確認します。 # get candidate pairs candidate_pairs_pd = getPandasDfFromDs(zingg.getUnmarkedRecords()) # if no candidate pairs, run job and wait if candidate_pairs_pd.shape[ 0 ] == 0 : print ( 'No unlabeled candidate pairs found. Run findTraining job ...' ) else : # get list of pairs (as identified by z_cluster) to label z_clusters = list (np.unique(candidate_pairs_pd[ 'z_cluster' ])) # identify last reviewed cluster last_z_cluster = '' # none yet # print candidate pair stats print ( '{0} candidate pairs found for labeling' .format( len (z_clusters))) ラベリングの候補としていくつペアあるか出力されます。(画像ではラベリングの候補として20ペアあることがわかります) 9. ラベリングを行う いよいよ、抽出された候補ペアに対して実際にラベリングを行います。 ノートブック上に候補ペアがHTML形式で表示され、各ペアに対して「Uncertain(不明)」「Match(一致)」「No Match(不一致)」のいずれかをボタンを押すことでラベリング作業を行います。 (Databricksがノートブック機能を提供している強みですね!) # Label Training Set # define variable to avoid duplicate saves ready_for_save = False # user-friendly labels and corresponding zingg numerical value # (the order in the dictionary affects how displayed below) LABELS = { 'Uncertain' : 2 , 'Match' : 1 , 'No Match' : 0 } # GET CANDIDATE PAIRS # ======================================================== #candidate_pairs_pd = get_candidate_pairs() n_pairs = int (candidate_pairs_pd.shape[ 0 ]/ 2 ) # ======================================================== # DEFINE IPYWIDGET DISPLAY # ======================================================== display_pd = candidate_pairs_pd.drop( labels=[ 'z_zid' , 'z_prediction' , 'z_score' , 'z_isMatch' , 'z_zsource' ], axis= 1 ) # define header to be used with each displayed pair html_prefix = "<p><span style='font-family:Courier New,Courier,monospace'>" html_suffix = "</p></span>" header = widgets.HTML(value=f "{html_prefix}<b>" + "<br />" .join([ str (i)+ "  " for i in display_pd.columns.to_list()]) + f "</b>{html_suffix}" ) # initialize display vContainers = [] vContainers.append(widgets.HTML(value=f '<h2>Indicate if each of the {n_pairs} record pairs is a match or not</h2></p>' )) # for each set of pairs for n in range (n_pairs): # get candidate records candidate_left = display_pd.loc[ 2 *n].to_list() candidate_right = display_pd.loc[( 2 *n)+ 1 ].to_list() # define grid to hold values html = '' for i in range (display_pd.shape[ 1 ]): # get column name column_name = display_pd.columns[i] # if field is image if column_name == 'image_path' : # define row header html += '<tr>' html += '<td><b>image</b></td>' # read left image to encoded string l_endcode = '' if candidate_left[i] != '' : with open (candidate_left[i], "rb" ) as l_file: l_encode = base64.b64encode( l_file.read() ).decode() # read right image to encoded string r_encode = '' if candidate_right[i] != '' : with open (candidate_right[i], "rb" ) as r_file: r_encode = base64.b64encode( r_file.read() ).decode() # present images html += f '<td><img src="data:image/png;base64,{l_encode}"></td>' html += f '<td><img src="data:image/png;base64,{r_encode}"></td>' html += '</tr>' elif column_name != 'image_path' : # display text values if column_name == 'z_cluster' : z_cluster = candidate_left[i] html += '<tr>' html += f '<td style="width:10%"><b>{column_name}</b></td>' html += f '<td style="width:45%">{str(candidate_left[i])}</td>' html += f '<td style="width:45%">{str(candidate_right[i])}</td>' html += '</tr>' # insert data table table = widgets.HTML(value=f '<table data-title="{z_cluster}" style="width:100%;border-collapse:collapse" border="1">' +html+ '</table>' ) z_cluster = None # assign label options to pair label = widgets.ToggleButtons( options=LABELS.keys(), button_style= 'info' ) # define blank line between displayed pair and next blankLine=widgets.HTML(value= '<br>' ) # append pair, label and blank line to widget structure vContainers.append(widgets.VBox(children=[table, label, blankLine])) # present widget display(widgets.VBox(children=vContainers)) # ======================================================== # mark flag to allow save ready_for_save = True ノートブックのアウトプットでは次のようなHTMLが表示されます。 実際にレコードが一致しているか、一致していないかを人の目で1つひとつチェックを行い、ボタンを押してラベリングを行っていきます。 ステップ8で作成されたペア分のチェックが終了したら、次のセルを実行し、内容を保存します。 if not ready_for_save: print ( 'No labels have been assigned. Run the previous cell to create candidate pairs and assign labels to them before re-running this cell.' ) else : # ASSIGN LABEL VALUE TO CANDIDATE PAIRS IN DATAFRAME # ======================================================== # for each pair in displayed widget for pair in vContainers[ 1 :]: # get pair and assigned label html_content = pair.children[ 1 ].get_interact_value() # the displayed pair as html user_assigned_label = pair.children[ 1 ].get_interact_value() # the assigned label # extract candidate pair id from html pair content start = pair.children[ 0 ].value.find( 'data-title="' ) if start > 0 : start += len ( 'data-title="' ) end = pair.children[ 0 ].value.find( '"' , start+ 2 ) pair_id = pair.children[ 0 ].value[start:end] # assign label to candidate pair entry in dataframe candidate_pairs_pd.loc[candidate_pairs_pd[ 'z_cluster' ]==pair_id, 'z_isMatch' ] = LABELS.get(user_assigned_label) # ======================================================== # SAVE LABELED DATA TO ZINGG FOLDER # ======================================================== # make target directory if needed dbutils.fs.mkdirs(MARKED_DIR) # save label assignments # save labels zingg.writeLabelledOutputFromPandas(candidate_pairs_pd,args) # count labels accumulated marked_pd_df = getPandasDfFromDs(zingg.getMarkedRecords()) n_pos, n_neg, n_tot = count_labeled_pairs(marked_pd_df) print (f 'You have accumulated {n_pos} pairs labeled as positive matches.' ) print (f 'You have accumulated {n_neg} pairs labeled as not matches.' ) print ( "If you need more pairs to label, re-run the cell for 'findTrainingData'" ) # ======================================================== # save completed ready_for_save = False 上記のセルを実行すると、これまでにラベリングしたペアの総数(一致、不一致ごとの件数)が出力され、進捗を確認できます。 Zinggのドキュメント では、最低でもマッチと判断できるペアが30~40必要とあり、マッチと判断した数が足りない場合は、あらためて「7. ト レーニン グデータ作成ジョブ実行する」から繰り返し、十分な教師データを収集します。 また、候補となるペアの質が低い場合(明らかに別の人がリストアップされている場合など)、 labelDataSampleSize の割合が小さい可能性があるので、必要に応じてこちらも検討してみてください。 10. モデルのト レーニン グ 十分な数のラベリング済み教師データが収集できたら、それらを基にマッチングモデルを学習します( trainMatch フェーズ) options = ClientOptions([ClientOptions.PHASE, "trainMatch" ]) #トレーニングジョブを実施します(時間かかります) zingg = ZinggWithSpark(args, options) zingg.initAndExecute() 11. マッチング結果を確認する モデル学習が完了したら、そのモデルを用いて 名寄せ 対象の全データに対して予測を実行し、どのレコードペアが同一エンティティとして判断されたかを確認します。 予測結果が出力されるデー タセット は、前述のZingg設定( outputPipe )で指定したパスに格納されます。 この出力デー タセット には、入力データに加えて、Zinggが付与した クラスタ IDや類似度スコアなどの情報が含まれます。 from pyspark.sql.types import StructType, StructField, IntegerType, FloatType, StringType # テーブルの取得 outputDF = spark.read.load(zinggDir + "/" + modelId + "/outputData/" ) # 内容の確認 display(outputDF.orderBy( "z_cluster" ).head( 25 )) 具体的には、以下の列が追加されています。 z_minScore そのレコードが同じ クラスタ 内の別のレコードと持つ最小の類似性スコアを表します。 z_maxScore そのレコードが同じ クラスタ 内の別のレコードと持つ最大の類似性スコアを表します。 z_cluster Zinggによって割り当てられた クラスタ ーのID。同一エンティティと判定されたレコード群には、共通のz_cluster IDが付与されます。 z_cluster をそのまま一意のエンティティを表すユニークIDとして使用できますが、 z_minScore や z_maxScore を元に 閾値 をユーザ側で定義(XX%以上は一致とする。XX ~ YY%はユーザで改めて目検。YY%以下は別人とする等々...)し、任意のオペレーションをすることもできます。 (詳細については、以下のZingg公式ドキュメントもご参照ください) https://www.zingg.ai/documentation-article/step-by-step-identity-resolution-with-python-and-zingg 以上で 名寄せ の一連のステップが全て終了しました! まとめ 本ブログ記事では、Zinggライブラリを用いた確率的マッチングの具体的な手法を紹介しました。 今回取り上げたZinggのような教師あり 機械学習 を活用する 名寄せ ライブラリも、Databricksのノートブック機能より、データ準備からラベリング、モデル学習、推論までを一貫したワークロードとして効率的に実行できます。 また、今回の記事では1つのデー タセット 内で 名寄せ する方法について取り上げましたが、他にもZinggを使用して、増分するデー タセット に対して継続的に 名寄せ 処理を実施できたり ( runIncremental 、 エンタープライズ 版で利用可能)、複数のデー タセット 間で一致し得るレコードを抽出も実行可能です( link )ので、もし興味がある方は是非公式ドキュメントの方もご覧ください。 三記事にわたり 名寄せ の概要からDatabricks上でSplinkによる 決定論 的手法、Zinggによる確率的手法まで 名寄せ のアプローチについて紹介しましたが、いかがだったでしょうか? 今回の一連の記事が、皆様のデータ活用や 名寄せ 業務の一助となれば幸いです。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @kumakura.koki 、レビュー: @kinjo.ryuki ( Shodo で執筆されました )
アバター
こんにちは。 エンタープライズ 第三本部 マーケティング IT部の熊倉です。 このブログでは、 高速に動作する分散処理エンジン「 Apache Spark」 と オープンテーブルフォーマット「Delta Lake」 を基盤としたレイクハウス環境を構築できるDatabricks上で管理しているデー タセット に対して、 名寄せ 処理を行うアプローチについて紹介します。 実際のノートブックの処理についても紹介しようと思っていますが、想定よりも内容が多くなってしまったので、 名寄せ の概要を紹介する「概要編」、 ソースコード など具体的な 名寄せ 処理の具体的な内容を紹介する「 決定論 的マッチング編」「確率的マッチング編」の三部作にしようと思います。 Databricksで実現するデータ名寄せ【概要編】 Databricksで実現するデータ名寄せ【決定論的マッチング編】(本記事) Databricksで実現するデータ名寄せ【確率的マッチング編】 本記事は 決定論 的マッチング編となります。 名寄せ 処理の概要について説明したブログ記事も公開しておりますので、 名寄せ 処理にまだ馴染みのない方は、ぜひそちらもご覧いただけると幸いです。 本記事ではSplinkというライブラリを利用し、 決定論 的マッチングを行う具体的な処理内容や流れについて説明していきますが、Pysparkの文法など基本的な内容については割愛させていただきます。(Splinkの概要については前編の概要編で紹介してますのでこちらも合わせてご覧ください) では、早速データの 名寄せ を開始していきましょう! 1. ライブラリをインストールする 2. 名寄せを行いたいデータセットを取り込む 3. ルールを定義する ルールの定義①: SQLで定義する ルールの定義②: block_onを利用する 注意が必要なルール: 等価結合以外の条件 4. マッチ数を確認する cartesianについて match_keyについて ネクストアクション 5. マッチングの実施 6. クラスターを作成する まとめ 1. ライブラリをインストールする 決定論 的マッチング処理における最終的なゴールは、 SQL のWHERE句に相当する条件の組み合わせを作成 することです。 SQL を記述することでも、もちろん 決定論 的マッチングは実現可能ですが、この記事では再利用性や可読性を考慮し、 Python の OSS 名寄せ ライブラリであるSplinkを用いた手法を紹介します。 まずは最初にライブラリをインストールします %pip install splink 2. 名寄せ を行いたいデー タセット を取り込む まず、 名寄せ 対象のデー タセット を取り込みます。 df = spark.read.table( "catalog.schema.table" ) (本記事ではUnity Catalogに登録されているテーブルから読み込んでいますが、もちろんファイルから直接データを読み込むことも可能です) 3. ルールを定義する 次にマッチングに使用するルールを定義します。 決定論 的マッチングは「ルールベースマッチング」とも呼ばれるように、このルール定義のステップが処理の根幹であり、最も重要なステップです。 ルールの定義は大きく分けて2つあります。 ルールの定義①: SQL で定義する ルールの定義方法の1つ目は、 SQL で定義する方法になります。 具体的には次のような形でルールを定義します。 rules = [] rules.append( "l.name = r.name AND l.email = r.email" ) SQL 文中のlおよびrというテーブル エイリアス は、同一テーブルをクロス結合(自己結合)する際の左テーブル (l) と右テーブル (r) をそれぞれ指します。 SQL 文の中でANDやORを使用して複雑な条件も設定できますが、OR条件はパフォーマンスが低下する可能性があるため、Splinkでは直接の使用は非推奨とされています。 OR条件のように複数の条件のいずれかに合致する場合を扱いたい場合は、各条件を個別のルールとしてrulesリスト(配列)に追加することで、同等の処理を実現できます。 具体的には、 rules.append( "l.name = r.name OR l.email = r.email" ) というルールを設定したい場合、 rules.append( "l.name = r.name" ) rules.append( "l.email = r.email" ) のようにリストに追加します。(ルールはリストに格納された順に評価されます) 補足すると、OR条件を含む結合は非等価結合となり、テーブルの直積に近い処理が必要になるため、一般的にパフォーマンスが低下します。Splinkでは、複数のルールをリストに格納することで、内部的にUNIONとNOTを組み合わせた処理に変換し、OR条件と同等の結果をより効率的に得られるように工夫されています。(詳細はSplinkの公式ドキュメントをご参照ください) 詳細については、以下Splink公式ドキュメントに紹介されているので、こちらも合わせてご確認ください。 https://moj-analytical-services.github.io/splink/topic_guides/blocking/performance.html ルールの定義②: block_onを利用する ルールの定義方法の2つ目は、Splinkで用意されている block_on 関数の利用になります from splink import block_on rules.append(block_on( "dob" , "address" )) Splinkの関数 block_on は、 SQL の l.dob = r.dob AND l.address = r.address と変換されます。 注意が必要なルール: 等価結合以外の条件 単純な列の一致比較(等価結合)以外、例えばLevenstein距離(編集距離)が特定の 閾値 以上であるといった条件(非等価結合)を用いる場合、多くの SQL エンジンでは、全レコードの総当たりに近いペア計算が発生し、計算量が膨大になる傾向があります。このような非等価結合を含むルールを設定する際は、パフォーマンスへの影響に十分な注意が必要です。 要件として、マッチングルールとして設定する必要がある場合もあるかと思いますが、注意が必要な条件になります。 4. マッチ数を確認する マッチング処理を行いレコードを突合する前に、3. で設定したルールで何件のレコードがマッチされるか確認できます。 from splink import SparkAPI from splink.blocking_analysis import cumulative_comparisons_to_be_scored_from_blocking_rules_data db_api = SparkAPI(spark_session=spark) # ruleの配列には以下を格納 # "l.name = r.name AND l.email = r.email" # block_on("dob", "address") count = cumulative_comparisons_to_be_scored_from_blocking_rules_data( table_or_tables=df, blocking_rules=rules, db_api=db_api, link_type= "dedupe_only" , unique_id_column_name= "id" ) display(count) 出力結果は以下のようになります。 ルールはリスト( rules )に入っている順に評価されるので、上記の ソースコード の例では "l.name = r.name AND l.email = r.email" block_on("dob", "address") の順に評価されます。 出力結果より、 "l.name = r.name AND l.email = r.email" のルールでは4345件がマッチと判断され、 block_on("dob", "address") のルールでは348件マッチと判断され、合計で4693件のペアがマッチと判断されたことが分かります。 注 : 「 block_on("dob", "address") のルールでは348件マッチ」とありますが、これは block_on("dob", "address") のルール 単体 でヒットしたペアが348件という訳ではなく、 "l.name = r.name AND l.email = r.email" のルールでヒットしなかったペアのうち、348件が2. のルールにヒットした、ということになります。 ちなみに、リストに格納されるルールの順を逆にすると以下のような出力結果になります。(ダミーデータの都合上、マッチするペアがほぼ一緒だったりしますが...) cartesianについて cartesian カラムに78,131,250という数値が入っていますが、デー タセット 内で作成可能な全てのユニークなペアの総数になります。これは(レコードの総数)* (レコードの総数 -1 )/ 2 で求められます。 (今回使用したダミーデータのレコード総数は12,501件であるため、作成可能なペアの総数は 12,501 × 12,500 / 2 = 78,131,250 となります) match_keyについて 出力結果には match_key カラムがありますが、これは各ルールに割り当てられた識別キー(インデックス)です。 後述のマッチング結果を確認する中で改めて登場します。 ネクス トアクション マッチ数を確認し必要に応じて3. で設定したルールの見直しを行います。 マッチ候補となるペア数は、後続のマッチング処理における計算リソースや処理時間に直接影響するため、「マッチ数が過大になっているルールはないか(処理負荷が高すぎないか)」、逆に「マッチ数が極端に少なく、効果の薄いルールはないか」といった観点で確認します。 基本的には、ルールをより厳しくする方向(例:リストに格納するルール数を調整する、ANDで条件を追加するなど)で再定義を検討しますが、実際にはプロジェクトごとの要件(精度、再現率、処理時間など)を総合的に加味して調整していくことになります。 5. マッチングの実施 ルールの定義が完了したら、実際にマッチングを行い突合したレコードを確認します。 settings = SettingsCreator( link_type= "dedupe_only" , blocking_rules_to_generate_predictions=rules, # ユニークな列を指定します。 unique_id_column_name= "id" , ) linker = Linker(df, settings, db_api=db_api) # マッチングの実施 df_predict = linker.inference.deterministic_link() df_predict_spark = df_predict.as_spark_dataframe() df_predict_spark はマッチングで突合されたレコードのペアが格納されたデータフレームになります。 display(df_predict_spark.count()) display(df_predict_spark.head( 15 )) ペアの情報のほか、出力結果には match_key カラムが追加されています。 こちらは「4. マッチ数を確認する」で確認できる match_key に対応しており、どのルールによって検出されたペアなのかを確認することができます。 (図の例だと、52行目のペアはmatch_keyが0、つまり"l.name=r.name AND l.email = r.email"というルールによってヒットしたペアで、53行目のペアはmatch_keyが1、つまり block_on("dob", "address") というルールによってヒットしたことが分かります) 6. クラスタ ーを作成する 同一ペアの検出は5. のステップで完了しましたが、ステップ6ではさらに進んで、同一と判定されたエンティティ(レコード群)に対して新しいユニークIDを付与します(この処理を クラスタリング 、または クラスタ ー化と呼びます)。 from pyspark.sql.functions import col # クラスター化の実行 clusters = linker.clustering.cluster_pairwise_predictions_at_threshold(df_predict) df_cluster_spark = clusters.as_spark_dataframe() # 結果の確認 display(df_cluster_spark.orderBy(col( "cluster_id" )).head( 15 )) cluster_id カラムが追加され、同一エンティティと判定されたレコード群ごとにユニークなIDが付与されていることが確認できます。 名寄せ 処理後のデー タセット では、この付与された cluster_id を新たなユニークIDとして扱うことになります。 以上で 名寄せ の一連のステップが全て終了しました! まとめ 本ブログではSplinkを使用した 決定論 的マッチングの具体的な手法について簡単に紹介しました。 処理自体は比較的シンプルかなと思いますが(冒頭で書いたように SQL のWHERE句を作るのが最終的なゴールなので)、実際のプロジェクトでは、このルール定義部分で難航することが多いのかなと思います。 以上、Databricks上で実現するデータ 名寄せ 【 決定論 的マッチング】編でした。 次回はDatabricks上で実現するデータ 名寄せ 【確率的マッチング】編になります! 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @kumakura.koki 、レビュー: @akutsu.masahiro ( Shodo で執筆されました )
アバター
こんにちは。 エンタープライズ 第三本部 マーケティング IT部の熊倉です。 このブログでは、 高速に動作する分散処理エンジン「 Apache Spark」 と オープンテーブルフォーマット「Delta Lake」 を基盤としたレイクハウス環境を構築できるDatabricks上で管理しているデー タセット に対して、 名寄せ 処理を行うアプローチについて紹介します。 実際のノートブックの処理についても紹介しようと思っていますが、想定よりも内容が多くなってしまったので、 名寄せ の概要を紹介する「概要編」、 ソースコード など具体的な 名寄せ 処理の具体的な内容を紹介する「 決定論 的マッチング編」「確率的マッチング編」の三部作にしようと思います。 Databricksで実現するデータ名寄せ【概要編】(本記事) Databricksで実現するデータ名寄せ【決定論的マッチング編】 Databricksで実現するデータ名寄せ【確率的マッチング編】 本記事は概要編で、 名寄せ 処理について概要、Databricksで 名寄せ 処理を行うメリットについて紹介します。 名寄せ 処理の基本をご存知の方は、本記事を読み飛ばしていただき、「 決定論 的マッチング編」または「確率的マッチング編」からお読みいただいても構いません 1. はじめに 1.1 名寄せとは 1.2 Entity Resolution と Identity Resolution 1.3 日本の名寄せ処理事情 1.4 国内の名寄せソリューション 2. 名寄せ処理の概要 2.1 名寄せ処理のステップ 2.2 偽陽性と偽陰性 2.3 決定論的マッチングと確率的マッチング 1. 決定論的マッチング 2. 確率的アイデンティティ解決 決定論的マッチングと確率的マッチングの選択 3. Databricks上での名寄せ 3.1 Databricksの利用 3.2 テックブログで取り上げるライブラリ Splink Zingg 1. はじめに 1.1 名寄せ とは 複数のレコードから、同一のエンティティ(現実世界で一意の顧客や製品など)を特定する操作を 名寄せ (英語だとEntity Resolution等)と呼びます。 1つのデー タセット 内で発生している重複を解消する場合や、共通IDが存在しない複数のデー タセット 間でユニークなエンティティを特定したい場合に 名寄せ 処理は実施されます。 エンティティは、企業が個別の単位として測定したいものなら何でも該当します。 (例えば、B2C企業だと「顧客」や「製品」、「 サブスクリプション 」、 B2B 企業だと「チーム」「企業」などが挙げられます) 1.2 Entity Resolution と Identity Resolution エンティティが「顧客」の場合の 名寄せ は、 アイデンティティ 解決(Identity Resolution)とも呼ばれることもあります。 アイデンティティ 解決の主要な目的の一つは、顧客に関するあらゆる情報を統合し、多角的な顧客理解を可能にする「カスタマー360」(360度顧客ビュー)の構築です。これの実現は、 マーケティング 効果の向上、顧客体験の最適化、効率的な顧客対応に不可欠です。 歴史的に見ると、このための機能は、金融機関における初期の顧客情報システムであるMCIFのようなデータベース マーケティング システムから始まり、その後、 CRM 、CDPといった様々なシステムで開発・実装されてきました。 1.3 日本の 名寄せ 処理事情 日本の情報が格納されたデー タセット に対して 名寄せ を行いたい場合、日本語特有の課題が存在します。 例えば、 ひらがな、カタカナ、漢字と文字の種類が多いこと 例(類似度について) 例えば、「Robert」と「Robelt」という文字列ペアと、「渡邉」と「渡辺」という文字列ペアは、どちらも編集距離(ここでは、1文字置換のコストを1とします)は同じ1です。しかし、単純に「編集距離/文字列長」で誤り率を評価すると、「Robert / Robelt」(6文字中1文字の違い)は約16.7%ですが、「渡辺/渡邉」(2文字中1文字の違い)は50%となり、後者の方が不一致度が大きく評価される傾向があります。このように、短い文字列(特に漢字2文字など)では、1文字の違いが全体に与える影響が相対的に大きくなってしまいます。 漢字については複数の読み方が存在しており、ふりがなの変換も難しいこと 例: 東海林(とうかいりん、しょうじ)など 住所の体系がかなり複雑なこと 日本の住所の正規化、 名寄せ の難易度の高さについて度々取り上げられ話題になります。 例: 「日本の住所のヤバさ」知れ渡る 正規化・名寄せ問題、Twitterトレンドに 1.4 国内の 名寄せ ソリューション 上記のような理由で日本語での 名寄せ は他の言語に比べると難しい傾向にあります。そのため、国内では従来より ゴールデンレコード(信頼できるソース)となる辞書データを所有 しており、 データの正規化を行える 企業が 名寄せ ソリューションを提供してきた背景があります。 例: 中小企業の辞書データを所有する企業が提供する会社の 名寄せ ソリューションや、住所辞書を所有する企業が提供する人の 名寄せ ソリューションなど 2. 名寄せ 処理の概要 2.1 名寄せ 処理のステップ 名寄せ 処理のステップは大きく 「対象データの分析」「 名寄せ の計画・設計」「対象データの前処理」「対象データのマッチング」 に分かれます。 対象データの分析 名寄せ を行いたいデー タセット について、項目ごとにカーディナリティや存在するデータの傾向などを分析・調査します。 名寄せ の計画・設計 名寄せ 処理のスケジュールや目的を設定します。目的によって、 名寄せ 処理の誤りをどの程度許容できるか(あるいは全く許容できないか)が異なるため、あらかじめ明確に定義し、関係者間で合意を得ておくことが必要です。 また、ルールベースで 名寄せ 処理を行う場合、この段階で 名寄せ ルールを定めます。 例)氏名と生年月日、住所が一致した場合は同一人物とする 対象データの前処理 データの内容は基本的に直接改変せず、後述のマッチング処理を効率良く行うために、表記揺れを吸収するようなデータの整形を行います。ただし、豊富な辞書データ(正本データ)を 保有 する従来型 名寄せ サービスなどでは、この段階で正本データに基づき表記の修正まで実施することもあります。 対象データのマッチング 前処理が完了した対象データに対してマッチング処理を行います。 また、対象データに対してマッチング処理を行った結果、(一般的には)同一とされたエンティティに対して新しいユニークなIDを付与します。 マッチング手法には ルールベースの 決定論 的マッチング と エンティティの一致度を確率で表現する確率論的マッチング が存在します。これらの詳しい処理内容については後述します。 2.2 偽陽性 と 偽陰性 ある情報を”分類”する際、その予測結果と実際の値(正解)パターンは以下の4つに分類できます。 真陽性 (True Positive, TP): 実際に陽性であるものを正しく陽性と予測できたケース 例: 実際に同一人物のレコードを同一人物と判断 真陰性 (True Negative, TN): 実際に陰性であるものを正しく陰性と予測できたケース 例: 実際に別人物のレコードを別人物と判断 偽陽性 (False Positive, FP): 実際には陰性であるものを、 誤って 陽性と予測してしまったケース 例: 実際は別人物なのにレコードを同一人物と判断 偽陰性 (False Negative, FN): 実際には陽性であるものを、 誤って 陰性と予測してしまったケース 例: 実際は同一人物なのにレコードを別人物と判断 名寄せ の目的によって、 偽陽性 と 偽陰性 のどちらを許容するか(反対に許容できないか)を合意しておくことが重要です。 2.3 決定論 的マッチングと確率的マッチング マッチングの手法は大きく、 決定論 的マッチング と 確率論的マッチング の 2 種類に分かれます。 1. 決定論 的マッチング 決定論 的マッチングは、ルール(条件)を定義し、エンティティを同一と見なす 名寄せ 手法です。 主な特徴 ルールベースのマッチング 事前に定義された厳格なルール(例:「氏名と生年月日が完全に一致する」「メールアドレスが完全に一致する」など)に基づいてレコードを比較し、条件に合致した場合にのみ同一エンティティと 判断 します。 利点 高精度 誤判定( 偽陽性 )が少なく、信頼性が高いです。特にパーソナライズされたコミュニケーションなど、精度が重視される用途に適しています。 計算コスト 確率的モデルと比較して、ルールベースのマッチングは計算量が少なく済む場合があります。 解釈可能性 なぜデータが結びつけられたのか、ルールに基づいて明確に説明できます。 欠点・課題 再現率の低さ(見逃しの多さ) ルールが厳格であるため、名前の表記揺れ(例: 「渡辺」 と 「渡邉」)、入力ミス、データの欠損(例: 郵便番号がない)などがあると、実際には同一人物であってもルールに合致せず、見逃してしまう( 偽陰性 )可能性が高くなります。 ルール設定の複雑さ 偽陰性 を低くしようと、より多くのパターンに対応しようとすると、ルールが非常に複雑になります まとめ 決定論 的マッチングは、明確な情報に基づいて高い精度で顧客情報を統合する強力な手法ですが、データの完全性や表記の揺れに弱く、すべての関連データを見つけ出す(再現率) 点では限界があることを理解して利用する必要があります。 2. 確率的 アイデンティティ 解決 確率論的名前解決とは、ルールに一致するかどうかだけに頼るのではなく、複数の情報や不完全な情報を統計的に評価し、異なるレコードが同じエンティティを指している「確率」を計算する手法です。 あいまい一致(Fuzzy Matching)と呼ばれることもあります。 主な特徴 証拠に基づくアプローチ 氏名、生年月日、住所、メールアドレス、位置情報など複数の属性や情報の一致率を算出し、「証拠」として利用します。 単一の属性(例:氏名が同じ、メールアドレスが同じ)だけでは一致と判断せず、複数の証拠を組み合わせ総合的に評価します。 各属性の一致・不一致が、どの程度「同一エンティティである」という結論を支持するか(または否定するか)を重み付けし、総合的な一致確率を算出します。 例えば 、 「田中 一郎、生年月日1990/05/09、郵便番号000 1234」というレコードと、 「田中 市朗、生年月日1990/05/09、郵便番号AB12 3CD」というレコードがあった場合、 名前は完全一致しないものの、他の属性が一致しているため、一致確率(例:98.21%)は高い のように確率をそれぞれ算出します。 閾値 の設定を後から設定でき、柔軟性がある 一致する確率が算出されるので、ユーザーが「どの程度の確率であれば同一エンティティとみなすか」という 閾値 をマッチングを行った後から設定できます。 これにより、 ユースケース に応じて精度と網羅性のバランスを調整できます。 例えば、同一人物であるにも関わらず誤って別人としてしまうこと( 偽陰性 )を避けたい場合は 閾値 を低めに、別人なのに同一人物と判断してしまうこと( 偽陽性 )を下げたい場合は 閾値 を高めに設定することが可能です。 利点 (ルールベースの 決定論 的マッチングに比べ)より多くのレコードを検出できる 確率論的手法は完全一致しないデータ間でも関連性を見つけ出すことができるため、 決定論 的手法よりも多くのレコードを統合できる可能性があります。 しかし、その性質上、(別人を同一人物として判断してしまう) 偽陽性 は 決定論 的手法よりも高くなる可能性があります。 実際にマッチングされた結果を見ながら、同一かどうかの判断ができる 偽陰性 、 偽陽性 の調整を後から実施できる ルールベースの 決定論 的マッチングの場合、あらかじめルールを定義する必要があり、その定義したルールで目的の 名寄せ ができたかどうかは結果が出力されないと判断ができない。(判断自体も難しい) 欠点・課題 解釈可能性が低い 確率によって一致かどうかを判断するため、究極的に言えば分類結果が誤っている可能性が常に存在する。 決定論 的マッチングは「一致とする」と判断してしまうアプローチなので、上記の点は明確です。 偽陽性 が高くなる場合がある 一致確率を基に判断する性質上、(別人を同一人物として判断してしまう) 偽陽性 は 決定論 的手法よりも高くなる可能性があります。 前述のように 閾値 の調整を行うことである程度調整は可能です。 まとめ 確率論的名前解決は、複数の不確実な情報から統計的に同一性を推定する柔軟なアプローチであり、より多くのデータを統合できる可能性がありますが、メリットとデメリットを理解し、 閾値 をどこに設定するかが重要となる手法です。 決定論 的マッチングと確率的マッチングの選択 上記のように、 決定論 的マッチングと確率的マッチングではそれぞれメリットデメリットが存在しており、どちらに優位性があるという訳ではありません。 例えば、 名寄せ した結果を基にユーザーに対してメールや電話による1on1の施策を行いたい場合、別人同士を同一人物として判断してしまう 偽陽性 が許容されないため、ルールベースの 決定論 的マッチングが適しています。一方、広告のオーディエンスとして利用するなど、ある程度の誤りが許容できる場合(機会損失の方が大きいと考えられる場合)は、確率論的マッチングの方が適しています。 名寄せ した結果どうしたいか(どのような利用を想定しているか)によって、どちらかを選択したり、 あるいは組み合わせて (氏名、住所、電話番号が一致する人は 決定論 的な考え方で同一人物とするが、他の属性の組み合わせについては確率的な考え方で 名寄せ を行うなど) 名寄せ 処理を行なっていくことになります。 3. Databricks上での 名寄せ 3.1 Databricksの利用 Databricksは、 Apache Sparkを基盤とする統合データ分析プラットフォームで、データエンジニアリング、 SQL や Python を利用した分析、 機械学習 、AIモデル開発といったデータ関連のワークロードを一元的に提供するプラットフォームです。 Databricksはデータエンジニアリングを行う主要なインターフェースの一つとしてNotebook環境を提供しています。 Notebookでは Python や Scala 、 SQL などがサポートされており、これらの言語を使用し、データを操作したり分析したりすることができます。 また、膨大な Python ライブラリ(pandas、NumPy、scikit-learn、TensorFlow、PyTorch等)をシームレスに利用することも可能で、 名寄せ 処理においては、企業がサービスとして提供しているもの以外に、 OSS として利用可能なライブラリも存在するため、それらを活用することでDatabricks上で 名寄せ 処理を実現できます。 Databricks上で 名寄せ 処理を行うメリットとして次のようなものがあります。 大量データに対して高速に実施可能 DatabricksはSpark(およびSparkを基に独自実装したPhoton)が動作するため、大量データの分散処理に強みがあります。 クラウド プラットフォームが提供する インスタンス 上に展開されるため、 インスタンス サイズを調整することで処理速度のチューニングも可能です。 Python の豊富なライブラリが利用可能 Sparkは Python や Scala で処理が記述でき、Notebookからpipによるライブラリのインストールが自由にできます。 Python はデータ分析の分野で利用実績が非常に多く、データ処理に関するライブラリ( Unicode 正規化ライブラリなど)の豊富さは他言語と比較して突出しており、コミュニティに蓄積された豊富なノウハウを 名寄せ 処理に活用できます。 また、 API を呼び出すことも可能なため、例えば住所正規化処理を提供している外部サービスに対してリク エス トを送信し、値の正規化を行うなど、柔軟な設計が可能です。 ELT 処理のワークロード内で実現可能 Databricksでは、 Python , SQL でETLを実現できるDelta Live Tableという機能や、データパイプライン(ジョブ)を管理できるWorkflowという機能が提供されています。 これらを組み合わせることで、複数システムからのデータインポート、突合から変換、 名寄せ 処理による重複排除、アウトプット作成まで一貫して行うことができます。 3.2 テックブログで取り上げるライブラリ 「 決定論 的マッチング編」「確率的マッチング編」では実際にDatabricksで 名寄せ 処理を実装する例を紹介していきます。 名寄せ のライブラリについては 決定論 的マッチングでは「 Splink 」、確率的マッチングでは「 Zingg 」というライブラリを使用していきたいと思います。 どちらもSpark上で動作する 機械学習 を活用した 名寄せ ライブラリで、確率的マッチングを行うことができます。 (Splinkについてはルールベースの 決定論 的マッチングも実施可能なので、 決定論 マッチングの例で利用しています) 教師なし学習 によるアプローチをとるのがSplink、 教師あり学習 によるアプローチを取るのがZinggとなっています。 Splink Splinkは英 国司 法省が開発した 名寄せ ライブラリです。 教師データなし学習によるアプローチを取っており、氏名、住所、生年月日といった複数の属性情報に対し、一致・不一致を判断する信頼度による重み付けを行い、2つのレコードの一致確率を算出(≒ 名寄せ )することができます。 「 Fellegi - Sunter 」モデルという理論に基づいて2つのレコードの一致確率を求めるのですが、その中でパラメータチューニング作業が求められるため、実装としてはやや難易度が高くなる傾向にあります。(実装には「 Fellegi - Sunter 」モデルの理解、基本的な 機械学習 の理解、そのデー タセット の理解が必要) メインとなる 名寄せ 処理(モデル作成など)以外に 名寄せ マッチングに必要な分析機能なども提供されており、 名寄せ のステップでいう対象データの分析を行う API が用意されています。 Databricksでは以前、ARC(Auto Record Linkage)というレコードの 名寄せ を行えるライブラリが提供されていました。 内容としてはSplinkをラップし、Databricks利用に特化したものだったようですが、現在更新が停止しており、利用が非推奨となっています(代わりにSplinkを直接使って欲しいと記載あり) https://www.databricks.com/blog/improving-public-sector-decision-making-simple-automated-record-linking https://github.com/databricks-industry-solutions/auto-data-linkage Zingg Zinggは、 機械学習 (ML)を活用した オープンソース の 名寄せ (エンティティ解決)ライブラリです。 顧客、製品、 サプライヤー など様々なエンティティに対応し、異なるデータソース間や単一データソース内の重複レコードや同一実体を特定・結合できます。 名寄せ 処理のステップは少しユニークで、対象となるデー タセット からまずラベリングを行い(2レコードが同一か別かを判断)、ラベリングした教師データを元にト レーニン グを行い、モデルを作成し、実際のデー タセット に対して 名寄せ を行う、といった流れを取ります。 Databricksや Snowflake 、Cassandra、S3、Azure、主要 RDBMS など、多くのデータソースやファイル形式(Parquet, Avro, JSON , CSV など)に対応しており、特にDatabricksに関しては、すぐにDatabricks上で処理を実行できるNotebookのサンプルなども提供されています。 Databricksが提供する特定の ユースケース に特化したテンプレート(ソリューション アクセラ レーターと呼ばれます)で利用されていたり、 AWS の公式ブログやHightouchのドキュメントで取り上げられるなど、( 名寄せ ライブラリの中では )比較的 知名度 の高いライブラリとなっています。( GitHub stars 1k) https://www.databricks.com/jp/solutions/accelerators/product-matching-with-ml https://aws.amazon.com/jp/blogs/big-data/entity-resolution-and-fuzzy-matches-in-aws-glue-using-the-zingg-open-source-library/ https://hightouch.com/blog/what-is-entity-resolution 「Databricksで実現するデータ 名寄せ 【概要編】」については以上になります。 本記事が 名寄せ 処理を理解する上で、少しでもお役に立てれば幸いです。 「 決定論 的マッチング編」、「確率的マッチング編」では実際にDatabricks上で実装する例について紹介しますので、こちらもぜひご覧ください! 以上、最後までご覧いただきありがとうございました。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @kumakura.koki 、レビュー: @akutsu.masahiro ( Shodo で執筆されました )
アバター