GenAIアプリの精度向上:GraphRAGとAzure Database for PostgreSQL
はじめに
- マイクロソフトではGraphデータとRAGを組み合わせたGraphRAGをリリースしました。
- GraphRAGとAzure Database for PostgreSQLを組み合わせたblogと動画が公開されていたので実際にコードを解説しながらデプロイしていきたいと思います。
- 一通りやると、GraphRAG、PostgreSQL、Semantic Rankerを使用したソリューションの構築方法、メリットの内容が把握できます。
RAGの課題とGraphRAG
RAGの精度の課題
- 関係性の理解不足
❌ 問題点
- 既存のRAGでは、単純な類似性検索が主流であり、エンティティ間の関係性を考慮しない。
- たとえば、「A社がB社を買収した理由」を知りたい場合、A社やB社に関する情報は取得できても、「買収の理由」につながる情報が得られないことがある。
- **因果関係(AがBに影響を与えた理由)や階層関係(AはBの親会社である)**など、意味的なつながりが維持されない。
✅ GraphRAGが解決
- ナレッジグラフを活用し、エンティティとその関係性を保持。
- 検索時に関係性を考慮した情報を取得できるため、「A社」と「B社」の関連性だけでなく、「買収の経緯」まで踏まえた情報を取得可能。
- ベクトル検索の限界
❌ 問題点
- 既存のRAGは**ベクトル検索(類似度検索)**に依存しており、単語の類似性に基づいて情報を取得。
- しかし、意味が似ていても質問に対して適切でない情報が含まれることがある。
- 例:「AIによる市場分析の影響」を知りたいとき、「AIと市場分析に関する一般的な記事」が検索されるが、「影響」に関する具体的な分析は含まれないことが多い。
✅ GraphRAGが解決
- グラフベースの検索により、「単語の類似性」だけでなく、「文脈上のつながり」を重視。
- たとえば、「A社の買収の影響」を知りたい場合、A社の買収に関する関連エンティティ(経営陣、財務状況、市場反応など)を含めた検索が可能。
- チャンクの切り方による情報の分断
❌ 問題点
- RAGでは文書を一定サイズのチャンクに分割し、それぞれのチャンクを検索対象とする。
- しかし、チャンク内に重要な関係性が含まれない場合、適切な情報が検索されない。
- 例:「X社の新製品発表が市場に与えた影響」について調べたいが、検索対象のチャンクが「新製品の仕様」や「X社の歴史」などに分かれており、肝心の「市場への影響」の情報が含まれないことがある。
✅ GraphRAGが解決
- チャンク単位ではなく、エンティティと関係性をグラフ構造で保持。
- **「X社の新製品発表 → 投資家の反応 → 株価変動」**といった情報のつながりを活用して、適切な情報を抽出できる。
- ハルシネーションの抑制
❌ 問題点
- RAGは検索した情報をLLMに渡して生成を行うが、**LLMが存在しない情報を補完してしまう(ハルシネーション)**ことがある。
- 特に、取得した情報が不完全な場合、LLMが勝手に因果関係や事実を作り出すリスクがある。
✅ GraphRAGが解決
- 検索した情報をグラフ構造に基づいて明確に整理し、LLMが誤った推論を行うリスクを低減。
- グラフのノード(エンティティ)とエッジ(関係)をチェックすることで、事実ベースの情報のみを使用可能。
- 長文コンテキストの処理の課題
❌ 問題点
- LLMにはトークンの制限があるため、検索した大量の情報を適切に処理しきれない。
- 重要な情報がコンテキストの中央に位置する場合、LLMが正しく認識できず、"Lost in the middle"問題が発生する。
✅ GraphRAGが解決
- 情報をエンティティと関係性に分けて構造化するため、必要な情報を圧縮しながら適切に取得可能。
- 意味的に関連する情報のみを優先的に取得し、不要な情報を除外できる。
GraphRAGにつながるために解決すべきRAGの課題は以下の通り:
- 関係性の理解不足 → ベクトル検索ではエンティティ間の関係を保持できない
- ベクトル検索の限界 → 単語の類似性に依存しすぎて、本当に関連する情報が取得できない
- チャンクの分断問題 → 文章の一部のみを取得するため、意味のつながりが失われる
- ハルシネーションの発生 → LLMが検索結果を正しく活用できず、不正確な回答を生成
- 長文コンテキストの処理 → 必要な情報が埋もれ、適切に活用できない
GraphRAGが解決策として有効な理由
GraphRAGでは、エンティティと関係性をナレッジグラフとして整理することで、文書の構造を理解しながら検索・生成を行うことが可能になります。その結果:
- 因果関係を考慮した検索が可能になり、より適切な情報を取得
- 長文の情報を圧縮して要点のみ抽出し、LLMの処理を最適化
- 検索結果の精度向上によってハルシネーションを抑制
GraphRAGが解決策として有効なユースケース
GraphRAGは、従来のRAG(Retrieval-Augmented Generation)の精度の課題を解決するために設計された手法です。特に、エンティティ間の関係性を考慮した検索・生成が可能になることで、以下のようなユースケースに適用できます。
-
企業のM&A(合併・買収)分析
🎯 課題
- RAGでは、「A社がB社を買収した理由」を知りたいときに、A社とB社に関する情報は取得できるが、「買収の経緯や影響」を適切に取得できない。
- 関連するニュース記事や財務データが別々のチャンクに分かれてしまい、全体像を把握しづらい。
✅ GraphRAGの解決策
- 企業や市場データのナレッジグラフを構築し、買収の背景や影響を考慮した情報取得を可能にする。
- **「A社 → B社 → 買収額 → 市場反応」**のような関係性を反映した検索・生成ができる。
-
法令・コンプライアンスの調査
🎯 課題
- 企業の法務担当者が「新しいデータ保護法が自社にどのような影響を与えるか?」を調査する場合、RAGでは単なる類似文書の検索しかできず、関連法令や過去の判例とのつながりを理解しにくい。
- 法令は改正が頻繁に行われるため、古い情報と最新の情報が混在し、検索結果の精度が低下する。
✅ GraphRAGの解決策
- 法令、規制、判例などをナレッジグラフ化し、それらの関係を考慮した検索が可能に。
- **「データ保護法 → 影響を受ける業界 → 過去の判例」**といった関連情報を体系的に取得できる。
-
製造業における品質管理・異常検知
🎯 課題
- 工場の品質管理担当者が「最近発生した不良品の原因」を調査する際、RAGでは類似の不良事例を検索できるが、根本原因や関連する機械のトラブル履歴とのつながりが見えづらい。
- 過去のトラブルや修理履歴が複数の異なるデータソースに分かれており、適切な情報の統合が難しい。
✅ GraphRAGの解決策
- **「機械の部品 → 故障パターン → 過去の修理履歴 → 原因」**という関係性をグラフで保持し、検索時に適切な情報を取得できる。
- 異常が発生した際に、その原因となる部品や環境要因を即座に特定可能。
-
医療分野での診断支援
🎯 課題
- 医師が「特定の症状を持つ患者に対する適切な治療法」を調べる場合、RAGでは症状と類似する過去のケースを検索できるが、「治療法の成功率」「副作用」「患者の体質との関係」などの詳細な要因が考慮されない。
- 医学論文や症例データは膨大で、単なるキーワード検索では適切な情報を見つけるのが困難。
✅ GraphRAGの解決策
- **「症状 → 診断 → 治療法 → 成功率」**といった関係性をナレッジグラフ化し、包括的な診断支援が可能。
- 治療法と副作用の関連性を考慮した検索ができるため、より適切な医療判断を支援。
-
金融市場の分析
🎯 課題
- 投資家が「最近の金利変動が株式市場にどのような影響を与えたか?」を調べる場合、RAGでは金利や株価に関する過去のデータを取得できるが、それらの関連性や因果関係が明確に示されない。
- 重要な経済指標(GDP、失業率、政策変更など)とのつながりが考慮されず、単発のデータしか得られない。
✅ GraphRAGの解決策
- **「金利 → 株価変動 → 業界別影響 → 投資戦略」**といった因果関係をグラフ化し、複合的なデータ分析が可能。
- 投資判断の精度を高めるために、過去の類似ケースや市場の動向を体系的に分析できる。
-
カスタマーサポートの最適化
🎯 課題
- 顧客が「製品Xのバッテリーが急に消耗する原因」を問い合わせた際、RAGではFAQやマニュアルの類似情報を取得するが、根本的な原因に関する情報が抜け落ちることがある。
- 製品の仕様、過去のユーザー報告、修理履歴が別々のデータベースに保存されており、統合的な情報取得が難しい。
✅ GraphRAGの解決策
- **「製品モデル → 不具合の傾向 → ユーザー報告 → 修理履歴」**といった情報をナレッジグラフ化し、適切な回答を自動生成。
- 過去の類似ケースや修理対応履歴をもとに、最適なトラブルシューティングを提案できる。
まとめ
GraphRAGは、従来のRAGの課題(関係性の欠如、検索の精度低下、ハルシネーションなど)を克服し、以下のユースケースで特に有効です。
- M&A分析(企業の買収・合併の背景や影響を整理)
- 法令・コンプライアンス調査(関連法規や判例の関係性を明確化)
- 品質管理・異常検知(機械トラブルや異常の原因特定)
- 医療診断支援(症状・診断・治療の関係を統合)
- 金融市場の分析(経済指標と市場動向の因果関係を分析)
- カスタマーサポートの最適化(製品の不具合データを統合し、適切なサポートを提供)
GraphRAGの導入により、単なるキーワード検索では得られない「意味のつながり」を考慮した情報検索と生成が可能になります。これにより、より正確で実用的な知識を活用できるようになります!
GraphRAGの概要
処理のプロセス
index
-
GraphRAGのインデックス作成プロセスは、非構造化テキストから意味のある構造化データを抽出し、ナレッジグラフを構築する一連のデータパイプラインと変換処理で構成されています。
-
主なステップ
-
エンティティ、関係、主張の抽出
- 入力されたテキストから、エンティティ(人、場所、組織など)やそれらの関係性、そして主張(特定の事実や意見)を抽出します。
-
コミュニティ検出
- 抽出されたエンティティ間の関係性を分析し、密接に関連するエンティティのグループ(コミュニティ)を特定します。
-
コミュニティの要約とレポート生成
- 各コミュニティに対して、LLM(大規模言語モデル)を用いて要約や詳細なレポートを生成し、コミュニティの特徴や重要性を明らかにします。
-
グラフベクトル空間への埋め込み
- エンティティをベクトル表現に変換し、グラフベクトル空間に配置することで、エンティティ間の類似性や関係性を数値的に表現します。
-
テキストチャンクのベクトル化
- 元のテキストを適切なサイズのチャンクに分割し、それぞれをベクトル化して、後の検索やクエリ処理で効率的に利用できるようにします。
プロンプトチューニング
-
プロンプトチューニングは、ナレッジグラフの生成や情報検索の精度を向上させるための重要なプロセスです。適切なプロンプト設計により、LLM(大規模言語モデル)の性能を最大限に引き出し、特定のドメインやデータセットに適合した結果を得ることが可能です。
-
Index Run の実行時により良い結果が得られるため、チューニングを実行することを強くお勧めします。入力をロードし、それらをチャンク(テキストユニット)に分割し、一連のLLM呼び出しとテンプレート置換を実行して最終的なプロンプトを生成することによって生成されます。
-
以下はプロンプトチューニングの提供されている手法です。
-
デフォルトプロンプト
- GraphRAGは初期設定としてデフォルトのプロンプトを提供しており、最小限の設定でシステムを迅速に開始できます。
- これらのプロンプトは一般的な用途向けに設計されています。
-
自動チューニング(Auto Tuning) :おすすめ
- 入力データを解析し、LLMとの対話を通じて、特定のドメインに適応したプロンプトを自動生成します。
- この手法は、インデックス作成時の結果を最適化するために推奨されています。
- 自動チューニングでは、入力データをチャンクサイズに基づいて分割し、LLMを活用して最適なプロンプトを生成します。
-
手動チューニング(Manual Tuning)
- 高度なユーザー向けの手法で、プロンプトを手動で微調整します。
- 特定のニーズや要件に応じてプロンプトをカスタマイズすることで、LLMの出力をより制御できます。
クエリ
- クエリに応じて、以下の検索手法を適用します。
- ローカル検索(Local Search)
- ローカル検索は、特定のエンティティに関する詳細な情報を取得する際に使用されます。
- ユーザーのクエリをベクトル化し、事前に埋め込まれたエンティティ記述と比較することで、最も関連性の高いエンティティを特定します。
- その後、ナレッジグラフ内の関連ノードやエッジをたどり、関連情報を収集して回答を生成します。
- この手法は、特定のエンティティに焦点を当てた質問に適しています。
- グローバル検索(Global Search)
- グローバル検索は、データセット全体にまたがる広範な質問に対応するための手法です。
- 事前に生成されたコミュニティレポート(ナレッジグラフ内のエンティティ群の要約)を活用し、ユーザーのクエリに関連する情報を抽出します。
- 各コミュニティレポートに対して質問を行い、その回答を統合・要約することで、包括的な回答を提供します。
- この手法は、特定のエンティティに依存しない抽象的な質問に適しています。
- DRIFT検索(Dynamic Reasoning and Inference with Flexible Traversal Search)
- DRIFT検索は、ローカル検索とグローバル検索の特性を組み合わせた手法です。
- コミュニティ情報を検索プロセスに組み込むことで、クエリの出発点を広げ、最終的な回答に多様な事実を取り入れることができます。
- 具体的には、ユーザーのクエリと最も関連性の高いコミュニティレポートを比較し、初期の回答とフォローアップの質問を生成します。
- その後、ローカル検索を用いてクエリを精緻化し、詳細な回答を得るプロセスを繰り返します。
- これにより、計算コストと回答の質のバランスを取りながら、詳細で文脈に富んだ情報を提供します。
- 質問生成(Question Generation)
-
質問生成は、ナレッジグラフの構造化データと入力ドキュメントの非構造化データを組み合わせて、特定のエンティティに関連する候補質問を生成する手法です。
-
過去のユーザー質問のリストを基に、ローカル検索と同様のコンテキスト構築手法を用いて、関連するデータを抽出・優先順位付けします。
-
これらのデータをLLM(大規模言語モデル)に入力し、データ内の重要な情報やテーマを反映した候補質問を生成します。
-
この手法は、ユーザーが次に探求すべき重要なトピックや情報を提案する際に有用です。
PostgreSQLを使用したGraphRAG概要
ソリューション全体像
- Azure Database for PostgreSQL でのベクトル検索、セマンティック ランク付け、GraphRAG の 3 つの情報取得手法の実装を示し、それらを組み合わせて法的な調査の質問に対して高品質の回答を提供する方法を示します。
- Solution Acceleratorとしてサンプルがあるのでデプロイしていきたいと思います。
- クエリ時の引用グラフの構造を、特殊なグラフクエリを使用して活用します。グラフ クエリは、訴訟の目立ちやすさをシグナルとして使用して、情報取得パイプラインの精度を向上させるように設計されています。グラフクエリは、従来のリレーショナルクエリとOpenCypherグラフクエリの組み合わせとして表現され、Apache AGE拡張機能を使用してPostgresで実行されます。結果の情報取得パイプラインを次に示します。
- セマンティックランキング(Semantic Ranking)
- ベクトル検索の精度を向上させるために、セマンティックランカーを使用して検索結果を再ランキングします。
- このアプローチにより、上位の検索結果の関連性が大幅に向上し、NDCG@10 の精度が 10~20% 向上することが確認されています。
- セマンティックランカーはスタンドアロンのソリューションアクセラレーターとして利用可能で、詳細は以下のブログで紹介されています。
Introducing Semantic Ranker Solution Accelerator for Azure Database for PostgreSQL
- GraphRAG
- GraphRAGは、Microsoft Researchが提案した高度なRAG(Retrieval-Augmented Generation)技術で、ナレッジグラフを活用してLLM(大規模言語モデル)の回答の質を向上させます。
- この手法では、ソースデータからナレッジグラフを抽出し、それをLLMのコンテキストとして提供することで、より適切な応答を生成します。
- GraphRAGの主なステップ:
-
グラフの抽出(Graph Extraction)
- ソースデータからエンティティと関係を抽出し、ナレッジグラフを構築。
-
エンティティの要約(Entity Summarization)
- 抽出されたエンティティを要約し、重要な情報を強調。
-
クエリ時のグラフ検索(Graph Query Generation at Query Time)
- クエリが実行されると、ナレッジグラフを活用して適切な情報を検索し、LLMに提供。
-
グラフの抽出(Graph Extraction)
- 情報検索パイプライン(Information Retrieval Pipeline)
- クエリ実行時に引用グラフ(Citation Graph)の構造を活用し、専門的なグラフ検索を行います。
- このグラフ検索では、法的判例の重要性を指標として用い、情報検索パイプラインの精度を向上させます。
- グラフ検索は、リレーショナルクエリとOpenCypherグラフクエリを組み合わせた手法で実装され、PostgreSQL上でApache AGE拡張を使用して実行されます。
構築方法
- 公開されているDeploymentガイドに沿ってデプロイしていきます。
https://github.com/Azure-Samples/graphrag-legalcases-postgres?tab=readme-ov-file#deployment-and-development
事前準備
- セマンティック ランク付け部分を実行するには、"bge-reranker-v2-m3" などのランク付けモデルをデプロイする必要があります
- 事前準備としてAzure MLのオンラインエンドポイントを設定します。
- こちらから手順にしたがってデプロイしていきます。
事前構築(Semantic Ranking)
- 基本的にREADME通りに実行すればデプロイできますが以下の点が注意です。
- いろいろライブラリが揃っているCloud Shellから実施しました。
-
Azure MLのオンラインエンドポイント
- Semantic-Ranker-Solution-PostgreSQL/model_asset/deployment.ymlでインスタンスタイプが「Standard_NC24ads_A100_v4」に設定されているので、「STANDARD_D16A_V4」に変更
- \i semantic_reranker_demo.sqlを実施すると
invalid byte sequence for encoding "SJIS"
のエラーが出た場合はクラウドシェルだと上手くいきました。。 - デプロイが失敗しても修正してazd upを繰り返して実行できるが、Azure MLのオンラインエンドポイントがエラーになる可能性があるため必要に応じて、以下のように削除、作成するとazd upが通ります。
az ml online-endpoint create(delete) --resource-group xx --workspace-name xx --name xx
-
色々なソリューションがデプロイされますが、今回必要な情報はオンラインエンドポイントのキー、REST エンドポイント、デプロイ名(bgev2m3-v1)になります。
PostgreSQLを使用したGraphRAG Solution構築
-
こちらもREADMEに沿ってデプロイします。
-
以下がデプロイ時の注意点やポイントを以下にまとめます。
- text-embedding-3-smallとgpt-4oを使用するのでデプロイのリージョンはjapaneastかaustraliaeastが推奨されます。最新の利用可能モデルは以下から参照ください。
-
Python 3.12でないとエラーになる。他のバージョンでは動作しなかった。anacondaのpython3.12を作成し仮想環境から実行しました。
-
Windows環境から実施する場合は、以下が必要になります。
- Install azd (https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/install-azd?tabs=winget-windows%2Cbrew-mac%2Cscript-linux&pivots=os-windows)
- Install PowerShell (PowerShell-7.4.6-win-x64.msi-> https://github.com/PowerShell/PowerShell/releases/tag/v7.4.6)
- Install Rust (rustup-init.exe ->https://rustup.rs/)
- Install Python 3.12 (Windows installer (64-bit)-> https://www.python.org/downloads/release/python-3120/)
- Install Node.js (https://nodejs.org/en).
- 必要なライブラリインストール
- pip install -r requirements-dev.txt
- pip install -e src/backend
-
setup_postgres_database.ps1、setup_postgres_azurerole.ps1、setup_postgres_seeddata.ps1で、直接pythonのパスが記載されているので、必要に応じてパスを変更。例
C:\Users\xxx\AppData\Local\anaconda3\envs\xxxx\python.exe
-
デプロイ後以下のような出力になります。
Deploying services (azd deploy)
(✓) Done: Deploying service web
- Endpoint: https://xxxxxx.xxxx.australiaeast.azurecontainerapps.io/
SUCCESS: Your up workflow to provision and deploy to Azure completed in 14 minutes 53 seconds.
-
You cannot run this script on the current system. For more information about running scripts and setting execution policy, see about_Execution_Policies at
が出る場合は、PowershellでSet-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Processを実行 - Graphrag-postgre-sematic\graphrag-legalcases-postgres\scripts以下の
setup_postgres_database.ps1
、setup_postgres_azurerole.ps1
、setup_postgres_seeddata.ps1
でPostgreの詳細設定を実施。- Apache AGE 拡張、CSV データのインポート、データベースの権限付与、Postgre内のFunctionの作成等。
-
flexibleserver.bicep
にPostgreSQLのユーザー、パスワードが記載されているのでpostgreに直接ログインする際は参照。param administratorLoginKey string
環境確認
-
Azure Portalで確認するとAzure OpennAIやPostgreSQL等リソースが作成されていることが確認できます。
-
PostgreSQLにデプロイして確認してみます。.envなどで実装した結果が返ってきます。
SELECT azure_ai.get_setting('azure_ml.scoring_endpoint');
SELECT azure_ai.get_setting('azure_ml.endpoint_key');
- クエリでパラメーターのnot foundが出るときは適宜set_settingで適宜設定ください。
SELECT azure_ai.set_setting('azure_openai.endpoint', 'https://xxxx.openai.azure.com/');
SELECT azure_ai.set_setting('azure_openai.subscription_key', 'xxxx');
- スキーマを確認します。
SELECT nspname FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname <> 'information_schema';
# | nspname |
---|---|
1 | azure_cognitive |
2 | azure_openai |
3 | azure_ml |
4 | azure_ai |
5 | public |
6 | case_graph |
7 | ag_catalog |
- public内のcases_updatedを確認します。
SELECT tablename
FROM pg_tables
WHERE schemaname = 'public';
# | tablename |
---|---|
1 | items |
2 | cases_updated |
3 | gold_dataset |
- dataの中に元のデータがjson(id、court(裁判所)、裁判の名前、中身等)で入っています。
SELECT * FROM public.cases_updated LIMIT 1;
# | id | data | description_vector |
---|---|---|---|
1 | 1005631 | {"id": 1005631, "name": "Harry R..."} | [0.03519562, 0.04 ベクトルデータ] |
-
必要な関数を設定
-
指定した query と cases_updated テーブルの text データをペアにして JSON 配列として構築し、最大 n 件の結果を返します。
-- generate_json_pairs関数
CREATE OR REPLACE FUNCTION generate_json_pairs(query TEXT, n INT)
RETURNS jsonb AS $$
BEGIN
RETURN (
SELECT jsonb_build_object(
'pairs',
jsonb_agg(
jsonb_build_array(query, LEFT(text, 800))
)
) AS result_json
FROM (
SELECT id, data -> 'casebody' -> 'opinions' -> 0 ->> 'text' AS text
FROM cases_updated
LIMIT n -
) subquery
);
END;
$$ LANGUAGE plpgsql;
- 入力テキストと件数を基に JSON データを生成し、Azure ML の bgev2m3-v1 モデルを呼び出してセマンティック関連性を評価し、結果を JSON で返します。
-- semantic_relevance関数
CREATE OR REPLACE FUNCTION semantic_relevance(query TEXT, n INT)
RETURNS jsonb AS $$
DECLARE
json_pairs jsonb;
result_json jsonb;
BEGIN
json_pairs := generate_json_pairs(query, n);
result_json := azure_ml.invoke(
json_pairs,
deployment_name=>'bgev2m3-v1',
timeout_ms => 180000
);
RETURN (
SELECT result_json AS result
);
END;
$$ LANGUAGE plpgsql;
- 確認
SELECT * FROM semantic_relevance('Water leaking into the apartment from the floor above.', 1);
検索結果
-
[Water leaking into the apartment from the floor above. What are the prominent legal precedents in Washington on this problem?]に関してベクトル検索、セマンティック検索、グラフ検索をそれぞれ実施するサンプルを記載します。
-
ベクトル検索:埋め込みモデル (text-embedding-3-small) を使ってクエリの文章をベクトル化し、それをデータベースのcases_updatedテーブル内のdescription_vectorと比較して類似度の高い判例を検索するものです。
結果として、関連する上位10件の判例を取得します。
-- ★Vector query
WITH
embedding_query AS (
SELECT azure_openai.create_embeddings('text-embedding-3-small',
'Water leaking into the apartment from the floor above.')::vector AS embedding
)
SELECT cases_updated.id,
cases_updated.data#>>'{name_abbreviation}' AS case_name,
cases_updated.data#>>'{decision_date}' AS date,
cases_updated.data#>>'{casebody, opinions, 0, text}' AS case_text
FROM cases_updated, embedding_query
ORDER BY description_vector <=> embedding
LIMIT 10;
- ベクトル検索+セマンティック検索:ベクトル検索の処理に加え、semantic_relevance 関数を使用して意味的関連性スコアを計算、それに基づいて結果をソートします。
WITH vector AS (
SELECT ROW_NUMBER() OVER () AS vector_order,
data#>>'{id}' AS id,
data#>>'{name_abbreviation}' AS case_name,
data#>>'{decision_date}' AS date,
data#>>'{casebody, opinions, 0, text}' AS case_text
FROM cases_updated
ORDER BY description_vector <=> azure_openai.create_embeddings('text-embedding-3-small',
'Water leaking into the apartment from the floor above. What are the prominent legal precedents in Washington on this problem?')::vector
),
result AS (
SELECT *
FROM jsonb_array_elements(
semantic_relevance('Water leaking into the apartment from the floor above. What are the prominent legal precedents in Washington on this problem?', 60)
) WITH ORDINALITY AS elem(value)
)
SELECT vector.id,
vector.case_name,
vector.date,
LEFT(vector.case_text, 20000) AS case_text,
vector.vector_order,
result.value::DOUBLE PRECISION AS semantic_relevance_score
FROM vector
JOIN result ON vector.vector_order = result.ordinality
ORDER BY semantic_relevance_score DESC
LIMIT 10;
- ベクトル検索+セマンティック検索+グラフ検索:上記セマンティック検索の結果とグラフデータ(参照数)を活用したランキング付けを行い、RRF (Reciprocal Rank Fusion) を用いて統合スコアを計算、それに基づいて結果をソートします。
-- ★semantic_relevance+graph関数 シンプル 10件
SET search_path = public, ag_catalog, "$user";
WITH vector AS (
-- セマンティック検索で上位60件を取得
SELECT ROW_NUMBER() OVER () AS vector_order,
data#>>'{id}' AS id,
data#>>'{name_abbreviation}' AS case_name,
data#>>'{decision_date}' AS date,
data#>>'{casebody, opinions, 0, text}' AS case_text
FROM cases_updated
ORDER BY description_vector <=> azure_openai.create_embeddings('text-embedding-3-small',
'Water leaking into the apartment from the floor above. What are the prominent legal precedents in Washington on this problem?')::vector
),
result AS (
-- セマンティック関連スコア取得
SELECT *
FROM jsonb_array_elements(
semantic_relevance('Water leaking into the apartment from the floor above. What are the prominent legal precedents in Washington on this problem?', 60)
) WITH ORDINALITY AS elem(value)
),
joined AS (
-- セマンティックスコアを付与
SELECT vector.id,
vector.case_name,
vector.date,
LEFT(vector.case_text, 20000) AS case_text,
vector.vector_order,
result.value::DOUBLE PRECISION AS semantic_relevance_score
FROM vector
JOIN result ON vector.vector_order = result.ordinality
),
graph AS (
-- グラフデータ(参照数)を取得し、joined と結合してランキング付与
SELECT
j.*,
g.refs,
RANK() OVER (ORDER BY g.refs DESC) AS graph_rank,
RANK() OVER (ORDER BY j.semantic_relevance_score DESC) AS semantic_rank
FROM joined j
JOIN cypher('case_graph', $$
MATCH ()-[r]->(n)
RETURN n.case_id, COUNT(r) AS refs
$$) AS g(case_id TEXT, refs BIGINT)
ON j.id = g.case_id
ORDER BY semantic_relevance_score DESC -- ここに統一
LIMIT 60 -- ここで制限
),
rrf AS (
-- RRF (Reciprocal Rank Fusion) で統合スコアを計算し、上位10件を抽出
SELECT
*,
COALESCE(1.0 / (60 + graph_rank), 0.0) +
COALESCE(1.0 / (60 + semantic_rank), 0.0) AS score
FROM graph
ORDER BY score DESC
LIMIT 10
)
-- 最終的なランキング結果を出力
SELECT
id,
case_name,
date,
case_text,
score,
graph_rank,
vector_order,
semantic_relevance_score,
refs
FROM rrf
ORDER BY score DESC;
検討事項
- インプットデータのアップデート方法は特に記載がありませんが、ベクトルデータ、グラフデータともにアップデートする必要があります。
- 事前用意されたcsvファイルを使用しましたが、実施の環境では構造化されていないデータから取得する必要があります。
- グラフデータの可視化は、Age-Viewerが提供されています。(今後試してみる予定です。)
まとめ
- ベクトルデータストアにグラフデータストアに Azure Database for PostgreSQLを使用し、セマンティック検索のモデルはAzure MLのオンラインエンドポイントを使用しました。
- 裁判所の判例検索システムを例に、ベクトル検索 (embedding search)、セマンティック検索 (semantic search)、グラフ検索 (graph search) を組み合わせて精度向上を図りました。
Discussion