Azure OpenAIのGraphRAGを解説及び検証（検証編）

本記事は、前記事の続編です。
[Azure OpenAIのGraphRAGを解説及び検証（解説編)](https://qiita.com/MMatsumotoMM/items/44c537a8af6858ab1199)

# はじめに

前回記事では、GraphRAGやGraphDBの特徴、活用事例等に関し解説いたしました。
今回の記事は、検証編として、実際に、GraphRAGをAzure上にデプロイし、検証していきます。

**検証編目次**
1. graphrag-acceleratorとは
1. 事前準備
1. Azureリソースの準備
1. graphrag-acceleratorのデプロイ
1. クエリの用意
1. 実行結果
1. まとめ

# graphrag-acceleratorとは

graphrag-acceleratorを
graphragを簡単にAzure上に構築できるIaCとして、graphrag-acceleratorが公開されています。

https://github.com/Azure-Samples/graphrag-accelerator.git

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3872169/eadea9b7-c882-842d-6b3b-b14017cc5d83.png)

# 事前準備
①以下のツールが必要になります。
Azure CLI >= v2.55.0
awk - a standard linux utility
cut - a standard linux utility
sed - a standard linux utility
curl - command line data transfer
helm - k8s package manager
jq >= v1.6
kubectl - k8s command line tool
yq >= v4.40.7 - yaml file parser

②以下の権限が必要になります。
なお、Azureでは、サブスクリプションやユーザ、サービスプリンシパルなどに対し、ロールを割り当てることでアクセス権を管理します。
Azure Portalから割り当てるほか、Azure CLIでも割り当てることができます。

|スコープ|ロール|
|:-:|:-:|
|サブスクリプション|リソースグループ|
|Contributer、Role Based Access Control(RBAC)Administrator|Owner|

```python
#　ロールを割り当て
az role assignment create --assignee "user@example.com" --role "Contributor" --scope "/subscriptions/your-subscription-id"
az role assignment create --assignee "user@example.com" --role "Owner" --scope "/subscriptions/your-subscription-id/resourceGroups/your-resource-group"
# ロール割り当ての確認
az role assignment list --scope "/subscriptions/your-subscription-id"
az role assignment list --resource-group "your-resource-group"
```

③以下のリソースプロバイダーの登録が必要になります。
Azure PortalのResource ProvidersメニューもしくはAzure CLIで登録ことができます。
```python
# リソースプロバイダーの登録
az provider register --namespace Microsoft.OperationsManagement
az provider register --namespace Microsoft.AlertsManagement
# リソースプロバイダーの確認
az provider show --namespace Microsoft.OperationsManagement -o table
az provider show --namespace Microsoft.AlertsManagement -o table
```

# Azureリソースの準備

①Azure OpenAI Serviceにて、gpt-4o（TPM Threshold：80K）、text-embedding-ada-002（TPM Threshold：300K）のモデルをデプロイします。
下記を参照下さい。
https://learn.microsoft.com/ja-jp/azure/ai-services/openai/how-to/create-resource?pivots=web-portal

| Model Name| TPM Threshold |
|:-:|:-:|
|gpt-4 turbo|80K|
|text-embedding-ada-002|300K|

②Azureアカウントにログインし、正しいサプスクリプションをセットします。
```shell
# Azureアカウントにログイン
az login
# ログインされているサブスクリプションをリスト表示
az account show
# 正しいサブスクリプションを選択
az account set --subscription "<サブスクリプション名> or <サブスクリプションid>"	
```
③リソースグループ名、リージョンを指定し、リソースグループを作成します。
```shell
az group create --name "<リソースグループ名>" --location "<リージョン名>"
```

④`/deploy.parameters.json`を編集します。
```shell
{
  "GRAPHRAG_API_BASE": "Azure OpenAIのエンドポイント",
  "GRAPHRAG_API_VERSION": "APIバージョン",
  "GRAPHRAG_EMBEDDING_DEPLOYMENT_NAME": "text-embedding-ada-002",
  "GRAPHRAG_EMBEDDING_MODEL": "text-embedding-ada-002",
  "GRAPHRAG_LLM_DEPLOYMENT_NAME": "gpt-4o",
  "GRAPHRAG_LLM_MODEL": "gpt-4o",
  "LOCATION": "Azure OpenAIのリージョン",
  "RESOURCE_GROUP": "GraphRAG_RG_20241022"
}
```

# graphrag-acceleratorのデプロイ

①DevContainerを起動し、`.sh`ファイルをデプロイします。

```shell
cd infra
bash deploy.sh -h # view help menu for additional options
bash deploy.sh -p deploy.parameters.json
```

下記アウトプットが返され、画像のリソースが作成されます。

```
   _____                             __       _
  / ____|                           / _|     | |
 | (___  _   _  ___ ___ ___ ___ ___| |_ _   _| |
  \___ \| | | |/ __/ __/ _ / __/ __|  _| | | | |
  ____) | |_| | (_| (_|  __\__ \__ | | | |_| | |
 |_____/ \__,_|\___\___\___|___|___|_|  \__,_|_|      _   _
     | |          | |                                | | | |
   __| | ___ _ __ | | ___  _   _ _ __ ___   ___ _ __ | |_| |
  / _` |/ _ | '_ \| |/ _ \| | | | '_ ` _ \ / _ | '_ \| __| |
 | (_| |  __| |_) | | (_) | |_| | | | | | |  __| | | | |_|_|
  \__,_|\___| .__/|_|\___/ \__, |_| |_| |_|\___|_| |_|\__(_)
            | |             __/ |
            |_|            |___/
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3872169/b0bba069-4f1b-d773-09a6-208ec391c5d9.png)

ちなみに、私はMac M1ユーザなのですが、下記エラーが出ました。
`ERROR: rosetta error: failed to open elf at /lib64/ld-linux-x86-64.so.2
Assigning 'Cognitive Services OpenAI Contributor' role to managed identity...`

Dockerfile の1行目を下記に修正することで、解決いたしました。
`FROM --platform=linux/amd64 python:3.10`
（参照：https://github.com/Azure-Samples/graphrag-accelerator/issues/161）


# graphrag-acceleratorを実行
**/graphrag-accelerator/notebooks/1-Quickstart.ipynb**ノートブックに従い、graphrag-acceleratorを実行していきます。

```python
! pip install devtools python-magic requests tqdm

import getpass
import json
import time
from pathlib import Path

import magic
import requests
from devtools import pprint
from tqdm import tqdm
```

```python
ocp_apim_subscription_key = getpass.getpass(
    "Enter the subscription key to the GraphRag APIM:"
)
```
ここで、`Ocp-Apim-Subscription-Key`の入力を求められます。
`Ocp-Apim-Subscription-Key`とは、Azure API Management service (APIM)でAPIにアクセスするために利用されるサブスクリプションキーで、APIへのアクセスを制御し、認証を行うためにHTTPリクエストのヘッダーに含める必要があります。
既にAPI Management servicesが作成されているため、AzurePortalのAPI Management services画面の、APIsメニュー内のサブスクリプションから取得できます。Built-in all-access subscriptionのprimaryキーになります。


```
headers = {"Ocp-Apim-Subscription-Key": ocp_apim_subscription_key}
```

下記パラメータを設定します。
なお、endpointには、API Management servicesのエンドポイントを入力します。
API Management services画面のOverviewにあるGateway URLをコピーペーストします。

```python
file_directory = "ファイルディレクトリ名"
storage_name = "graphrag-container"
index_name = "graphrag-index"
endpoint = "https://apim-m5fttyatbz4ho.azure-api.net"

assert (
    file_directory != "" and storage_name != "" and index_name != "" and endpoint != ""
)
```
データセットとして、wikipediaの情報を活用できるように準備されています。
get-wiki-articles.pyファイルの内容を編集したのち、
`/graphrag-accelerator/notebooks/get-wiki-articles.py <ファイルのディレクトリ名>`を実行することで、指定ディレクトリ名にてファイルが作成されます。

編集箇所は下記に記載しています。

```python
import argparse
import os
import wikipedia

# 日本語に変更
wikipedia.set_lang("ja")

# us_statesリストを、任意のテーマに変更。

ja_anime = [
    "アニメ",
    "名探偵コナン",
    "ワンピース",
]

```

以下は編集不要です。

```python
def main():
    parser = argparse.ArgumentParser(description="Wikipedia Download Script")
    parser.add_argument(
        "directory",
        help="Directory to download sample wikipedia articles to.",
        default="testdata",
    )
    parser.add_argument(
        "--short-summary",
        help="Retrieve short summary article content.",
        action="store_true",
    )
    parser.add_argument(
        "--num-articles",
        help="Number of wikipedia articles to download. Default=5",
        default=5,
        choices=range(1, 6),
        type=int,
    )
    
    args = parser.parse_args()
    os.makedirs(args.directory, exist_ok=True)
    for state in anime_titles + fashion_brands[0 : args.num_articles]:
    #for state in us_states[0 : args.num_articles]:
        try:
            title = wikipedia.page(state).title.lower().replace(" ", "_")
            content = (
                wikipedia.page(state).summary
                if args.short_summary
                else wikipedia.page(state).content
            )
            content = content.strip()
            filename = os.path.join(args.directory, f"{title}_wiki_article.txt")
            with open(filename, "w", encoding="utf-8") as f:
                f.write(content)
            print(f"Saving wiki article '{title}' to {filename}")
        except Exception:
            print(f"Error fetching wiki article {title}")
            
if __name__ == "__main__":
    main()
```
</details>

testdataディレクトリにwikipediaのデータが格納されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3872169/6bfe143e-a8fa-aaaa-a448-6e75b3e087de.png)

次に、作成されたデータセットをblobにアップロードします。

※この時点から、AKS（Azure Kubernetes Service）を起動する必要があります。
Azure Portalから該当のAKSリソースを選択すると、Overview画面に起動ボタンがあります。

![スクリーンショット 2024-10-27 9.26.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3872169/dee18acb-e084-7f99-fa83-610bd103cb15.png)

```python
def upload_files(
    file_directory: str,
    storage_name: str,
    batch_size: int = 100,
    overwrite: bool = True,
    max_retries: int = 5,
) -> requests.Response | list[Path]:

    url = endpoint + "/data"

    def upload_batch(
        files: list, storage_name: str, overwrite: bool, max_retries: int
    ) -> requests.Response:
        for _ in range(max_retries):
            response = requests.post(
                url=url,
                files=files,
                params={"storage_name": storage_name, "overwrite": overwrite},
                headers=headers,
            )
            print(response)
            # API may be busy, retry
            if response.status_code == 500:
                print("API busy. Sleeping and will try again.")
                time.sleep(10)
                continue
            return response
        return response

    batch_files = []
    accepted_file_types = ["text/plain"]
    filepaths = list(Path(file_directory).iterdir())
    for file in tqdm(filepaths):
        # validate that file is a file, has acceptable file type, has a .txt extension, and has utf-8 encoding
        if (
            not file.is_file()
            or file.suffix != ".txt"
            or magic.from_file(str(file), mime=True) not in accepted_file_types
        ):
            print(f"Skipping invalid file: {file}")
            continue
       
        batch_files.append(
            ("files", open(file=file, mode="r", encoding="utf-8", errors="ignore"))
        )
        # upload batch of files
        if len(batch_files) == batch_size:
            response = upload_batch(batch_files, storage_name, overwrite, max_retries)
            # if response is not ok, return early
            if not response.ok:
                return response
            batch_files.clear()
    # upload remaining files
    if len(batch_files) > 0:
        response = upload_batch(batch_files, storage_name, overwrite, max_retries)
    return response


response = upload_files(
    file_directory=file_directory,
    storage_name=storage_name,
    batch_size=100,
    overwrite=True,
)
if not response.ok:
    print(response.text)
else:
    print(response)
```
</details>

以下のアウトプットが返されます。

```
    100%|██████████| 9/9 [00:00<00:00, 27.80it/s]

    <Response [200]>
    <Response [200]>
```

次に、blobにアップロードしたデータセットにインデックスを追加します。

```python
def build_index(
    storage_name: str,
    index_name: str,
) -> requests.Response:
 
    url = endpoint + "/index"
    
    request = {"storage_name": storage_name, "index_name": index_name}
    return requests.post(url, params=request, headers=headers)

response = build_index(storage_name=storage_name, index_name=index_name)
print(response)
if response.ok:
    print(response.text)
else:
    print(f"Failed to submit job.\nStatus: {response.text}")

以下のアウトプットが返されます。
```python
<Response [202]>
{"detail":"Index 'graphrag-index' already exists and has not finished building."}
```

インデックス処理のステータスを確認します。
```python
def index_status(index_name: str) -> requests.Response:
    url = endpoint + f"/index/status/{index_name}"
    return requests.get(url, headers=headers)

response = index_status(index_name)
pprint(response.json())
```

進行中の場合
```
{
    'status_code': 200,
    'index_name': 'graphrag-index',
    'storage_name': 'graphrag-container',
    'status': 'running',
    'percent_complete': 12.5,
    'progress': 'Workflow create_base_text_units started.',
}
```

完了後
```
{
    'status_code': 200,
    'index_name': 'graphrag-index',
    'storage_name': 'graphrag-container',
    'status': 'complete',
    'percent_complete': 100.0,
    'progress': '16 out of 16 workflows completed successfully.',
}
```


```python
# a helper function to parse out the result from a query response
def parse_query_response(
    response: requests.Response, return_context_data: bool = False
) -> requests.Response | dict[list[dict]]:
    """
    Print response['result'] value and return context data.
    """
    if response.ok:
        print(json.loads(response.text)["result"])
        if return_context_data:
            return json.loads(response.text)["context_data"]
        return response
    else:
        print(response.reason)
        print(response.content)
        return response
```
</details>



```python
def global_search(index_name: str | list[str], query: str, community_level: int) -> requests.Response:
    """Run a global query over the knowledge graph(s) associated with one or more indexes"""
    url = endpoint + "/query/global"
    #optional parameter: community level to query the graph at (default for global query = 1)
    request = {"index_name": index_name, "query": query, "community_level": community_level}
    return requests.post(url, json=request, headers=headers)
```

クエリの実行コードは以下のとおりです。

**Globalクエリ**

```python
# perform a global query
global_response = global_search(
    index_name=index_name, query="クエリを入力", community_level=1
)
global_response_data = parse_query_response(global_response, return_context_data=True)
global_response_data
```

**Localクエリ**

```python
def local_search(index_name: str | list[str], query: str, community_level: int) -> requests.Response:
    """Run a local query over the knowledge graph(s) associated with one or more indexes"""
    url = endpoint + "/query/local"
    # optional parameter: community level to query the graph at (default for local query = 2)
    request = {"index_name": index_name, "query": query, "community_level": community_level}
    return requests.post(url, json=request, headers=headers)

# perform a local query
local_response = local_search(
    index_name=index_name, query="クエリを入力", community_level=2
)
local_response_data = parse_query_response(local_response, return_context_data=True)
local_response_data
```

# クエリの用意

従来のRAGで回答精度の上がりづらいクエリを3つ用意しました。
また、①では、グローバル、ローカル双方のクエリを実行し、出力及び、情報ソースを比較しました。

**クエリ①** 複数のソース、チャンクから情報を繋ぎ、統合する必要があるクエリ

「OnePieceの主題と名探偵コナンの主題についてまとめた上で、それらの主題を比較してください。」

**クエリ②**  全体的な理解が必要な抽象的な質問クエリ

「OnePiece、名探偵コナン双方の物語の特徴もとに、日本のアニメの特徴についてまとめてください。」


**クエリ③**  エンティティ同士の関係性を捉える必要があるクエリ

「毛利蘭と工藤新一の関係性を分析してください。また、One Pieceの中で、最も毛利探偵と相性が良いと考えられる人物を教えてください。」

# 実行結果

## クエリ①

**グローバルクエリ**

```
## 名探偵コナンの主題

名探偵コナンの中心的なテーマは、探偵であるコナンが子供の姿に変えられてしまったことにあります。彼が元の姿に戻るための探求が物語の多くを駆動し、他の主要なキャラクターや組織との関係を形成しています。このシリーズは、謎解きや探偵たちとその仲間たちの関係に焦点を当てています [Data: Reports (2)]。

さらに、名探偵コナン ミステリーファイルシリーズは、エジプトの謎、人類の謎、環境の謎など、幅広い教育的なトピックをカバーしており、その教育的価値が高いことが特徴です [Data: Reports (1)]。このシリーズは、Ciaoや週刊少年サンデーSなどの著名な小学館の雑誌に連載されており、広範な影響力を持っています [Data: Reports (1)]。また、怪盗キッドや少年探偵団など、オリジナルシリーズのキャラクターやグループが登場し、ファンを引きつけ続けています [Data: Reports (1)]。

## OnePieceの主題

OnePieceの主題については、提供されたデータセットには情報が含まれていません。そのため、OnePieceの主題については一般的な知識に基づいて説明します。

OnePieceの中心的なテーマは、主人公モンキー・D・ルフィと彼の仲間たちが「ひとつなぎの大秘宝（ワンピース）」を探す冒険です。ルフィの夢は、海賊王になることであり、そのために彼は仲間たちと共にグランドラインを航海し、様々な敵や困難に立ち向かいます。この物語は、友情、冒険、夢の追求といったテーマを中心に展開されます。

## 名探偵コナンとOnePieceの主題の比較

名探偵コナンとOnePieceの主題を比較すると、いくつかの顕著な違いと共通点が見えてきます。

### 共通点
1. **探求の旅**: 両作品とも、主人公が何かを探し求める旅を描いています。コナンは元の姿に戻る方法を探し、ルフィはワンピースを探しています。
2. **仲間との絆**: 両作品とも、主人公が仲間たちと強い絆を築きながら物語が進行します。コナンは探偵仲間や少年探偵団と協力し、ルフィは海賊団の仲間たちと共に冒険します。

### 違い
1. **テーマの焦点**: 名探偵コナンは主にミステリーと謎解きに焦点を当てており、各エピソードで異なる事件が解決されます。一方、OnePieceは冒険とバトルが中心で、長期的な目標に向かって進むストーリーが展開されます。
2. **教育的要素**: 名探偵コナン ミステリーファイルシリーズは、教育的なトピックを取り入れており、読者に知識を提供することを目的としています [Data: Reports (1)]。OnePieceにはそのような明確な教育的要素は少なく、エンターテインメント性が強調されています。

このように、名探偵コナンとOnePieceは、それぞれ異なるテーマとアプローチを持ちながらも、探求と仲間との絆という共通の要素を共有しています。
CPU times: user 102 ms, sys: 12 ms, total: 114 ms
Wall time: 18.4 s
```

コミュニティレポート情報（一部）

```
{'reports': [{'id': '2',
   'title': 'Detective Conan and Key Associates',
   'occurrence weight': 1.0,
   'content': "# Detective Conan and Key Associates\n\nThe community centers around the character Conan, a detective who has been transformed into a child. Key entities include Heiji Hattori, a high school detective from Osaka and Conan's collaborator, Kogoro Mouri, the head of the detective agency visited by Conan, and Ran, Kogoro's daughter and Conan's friend. The relationships among these entities form a tightly-knit network of detectives and associates, each contributing to the overarching narrative of solving mysteries.\n\n## Conan's Central Role\n\nConan is the central figure in this community, originally a detective who has been transformed into a child. His quest to return to his original form drives much of the narrative and connects him to various other key entities. Conan's relationships with other characters, such as Heiji Hattori and Kogoro Mouri, are crucial in understanding the dynamics of this community [Data: Entities (3), Relationships (1, 4, 5)].\n\n## Heiji Hattori's Collaboration with Conan\n\nHeiji Hattori, a high school detective from Osaka, is a significant collaborator with Conan. Their partnership is essential for solving complex cases, and Heiji's background from Osaka adds a unique dimension to their investigative efforts. This collaboration highlights the importance of teamwork and shared expertise in the detective community [Data: Entities (2, 15), Relationships (1, 2)].\n\n## Kogoro Mouri's Role as a Detective Agency Head\n\nKogoro Mouri is the head of the detective agency visited by Conan. His position as a detective and his relationship with Conan and other characters, such as his daughter Ran, make him a pivotal figure in the community. Kogoro's agency serves as a hub for many of the community's activities and interactions [Data: Entities (13), Relationships (5, 14)].\n\n## Ran's Connection to Key Entities\n\nRan, the daughter of Kogoro Mouri and a friend of Conan, plays a significant role in the community. Her relationships with both her father and Conan provide emotional depth and personal stakes to the narrative. Ran's presence adds a layer of complexity to the interactions among the key entities [Data: Entities (14), Relationships (14)].\n\n## The Importance of Osaka in Heiji Hattori's Background\n\nOsaka, the place from which Heiji Hattori hails, is an important aspect of his character. This background influences his methods and perspectives as a detective, adding diversity to the investigative approaches within the community. The connection to Osaka also broadens the geographical scope of the community's activities [Data: Entities (15), Relationships (2)].",
   'rank': 7.5,
   'index_name': 'graphrag-index',
   'index_id': '2'},
  {'id': '1',

  #以下省略
```

**ローカルクエリ**

```
 # One Pieceの主題

## 冒険と友情
"One Piece"は、海賊王を目指す主人公モンキー・D・ルフィとその仲間たちの冒険を描いた物語です。物語の中心には、仲間との絆や友情が強調されています。ルフィとその仲間たちは、困難な状況に直面しても互いに支え合い、共に成長していきます。このテーマは、シリーズ全体を通じて一貫して描かれています [Data: Entities (122); Relationships (125, 130, 105, 116, 120)]。

## 自由と夢の追求
もう一つの重要なテーマは「自由」と「夢の追求」です。ルフィは自由を求めて海を渡り、仲間たちもそれぞれの夢を追い求めています。例えば、ゾロは世界一の剣士を目指し、ナミは世界中の海図を描くことを夢見ています。このように、各キャラクターの夢とその実現に向けた努力が物語の大きな柱となっています [Data: Entities (122); Relationships (125, 130, 105, 116, 120)]。

## 正義と悪
"One Piece"では、正義と悪の対立も重要なテーマです。海軍や世界政府といった権力機構が描かれる一方で、海賊たちの自由な生き方が対比されています。物語は、単純な善悪の二元論ではなく、複雑な人間関係や価値観の対立を描いています [Data: Entities (122); Relationships (125, 130, 105, 116, 120)]。

# 名探偵コナンの主題

## 謎解きと推理
"名探偵コナン"の中心テーマは、謎解きと推理です。主人公の江戸川コナン（工藤新一）は、数々の事件を解決する名探偵です。物語は、彼が遭遇する様々な犯罪や謎を解明する過程を描いています。各エピソードは、巧妙なトリックや謎解きが盛り込まれており、読者や視聴者を引き込む要素となっています [Data: Detective Conan Mystery Files Community (1); Entities (31, 3, 2)]。

## 正義と悪
"名探偵コナン"でも、正義と悪の対立が重要なテーマです。コナンは、犯罪者を追い詰め、正義を貫くために奮闘します。彼の行動は、正義感と倫理観に基づいており、犯罪者を捕まえることが彼の使命です [Data: Detective Conan Mystery Files Community (1); Entities (31, 3, 2)]。

## 科学と知識
"名探偵コナン"は、科学や知識の重要性も強調しています。コナンは、科学的な知識や論理的な推理を駆使して事件を解決します。また、シリーズには教育的な要素も含まれており、読者や視聴者に対して科学や歴史に関する知識を提供しています [Data: Detective Conan Mystery Files Community (1); Entities (31, 3, 2)]。

# 主題の比較

## 冒険と謎解き
"One Piece"と"名探偵コナン"の最も顕著な違いは、冒険と謎解きのテーマです。"One Piece"は、広大な海を舞台にした冒険物語であり、仲間との絆や夢の追求が中心テーマです。一方、"名探偵コナン"は、犯罪や謎を解決する推理物語であり、科学的な知識や論理的な推理が重要な要素です [Data: Detective Conan Mystery Files Community (1); Entities (31, 3, 2, 122)]。

## 正義と悪の描き方
両作品とも正義と悪の対立を描いていますが、そのアプローチは異なります。"One Piece"では、海賊と海軍、世界政府との対立が描かれ、自由と権力の対比が強調されています。一方、"名探偵コナン"では、犯罪者と探偵の対立が中心であり、正義感と倫理観に基づいた行動が描かれています [Data: Detective Conan Mystery Files Community (1); Entities (31, 3, 2, 122)]。

## 教育的要素
"名探偵コナン"は、科学や歴史に関する教育的な要素が強く、読者や視聴者に知識を提供することを目的としています。一方、"One Piece"は、冒険や友情、夢の追求といったテーマを通じて、読者に感動や興奮を提供することを重視しています [Data: Detective Conan Mystery Files Community (1); Entities (31, 3, 2, 122)]。

このように、"One Piece"と"名探偵コナン"は、それぞれ異なるテーマとアプローチを持ちながらも、読者や視聴者に強い影響を与える作品です。
CPU times: user 273 ms, sys: 9.66 ms, total: 283 ms
Wall time: 25.2 s
```
コミュニティレポート情報及び、ソーステキスト（一部）

```
{'reports': [{'id': '1',
   'title': 'Detective Conan Mystery Files Community',
   'content': "# Detective Conan Mystery Files Community\n\nThe community revolves around the Detective Conan Mystery Files, a learning manga series serialized in various Shogakukan magazines. Key entities include the original author Gosho Aoyama, various artists and writers such as Denjiro Maru, Yutaka Abe, and Masaru Ota, and magazines like Ciao and Weekly Shonen Sunday S. The series has multiple volumes focusing on different mysteries and has influenced other media such as anime episodes and movies.\n\n## Central Role of Detective Conan Mystery Files\n\nThe Detective Conan Mystery Files is the central entity in this community, serving as the core around which other entities revolve. This series is serialized in various Shogakukan magazines, including Ciao and Weekly Shonen Sunday S, indicating its broad reach and influence [Data: Entities (31, 41, 40); Relationships (24, 34, 33)]. The series covers a wide range of topics through its various volumes, such as Mysteries of Egypt, Mysteries of Humanity, and Mysteries of the Environment, showcasing its educational value [Data: Entities (52, 55, 48); Relationships (45, 48, 41)].\n\n## Influence of Gosho Aoyama\n\nGosho Aoyama, the original author of Detective Conan, provided the original concept for the Detective Conan Mystery Files. His involvement lends significant credibility and popularity to the series, as he is a well-known figure in the manga industry [Data: Entities (32); Relationships (25)]. Aoyama's original concept has been expanded upon by various artists and writers, making the series a collaborative effort that benefits from his initial vision.\n\n## Contributions of Various Artists and Writers\n\nThe Detective Conan Mystery Files series is a collaborative effort involving multiple artists and writers. Key contributors include Denjiro Maru, Yutaka Abe, Masaru Ota, and the Ekoda Detective Agency, among others [Data: Entities (35, 34, 37, 38); Relationships (28, 27, 30, 31)]. Each of these contributors has worked on different volumes of the series, adding their unique styles and expertise to the overall work. This collaboration has resulted in a rich and diverse series that appeals to a wide audience.\n\n## Serialization in Prominent Magazines\n\nThe Detective Conan Mystery Files series is serialized in prominent Shogakukan magazines such as Ciao and Weekly Shonen Sunday S. This serialization ensures that the series reaches a broad audience, including both young readers and fans of the original Detective Conan series [Data: Entities (41, 40); Relationships (34, 33)]. The presence of the series in these well-known magazines highlights its popularity and cultural impact.\n\n## Educational Value of the Series\n\nThe Detective Conan Mystery Files series covers a wide range of educational topics through its various volumes. These include Mysteries of Egypt, Mysteries of Humanity, Mysteries of the Environment, and many more [Data: Entities (52, 55, 48); Relationships (45, 48, 41)]. Each volume is written by different experts, such as Denjiro Maru and Masaru Ota, ensuring that the information is accurate and engaging [Data: Entities (35, 37); Relationships (28, 30)]. This educational focus makes the series valuable not just for entertainment but also for learning.\n\n## Impact on Other Media\n\nThe influence of the Detective Conan Mystery Files extends beyond manga into other media, including anime episodes and movies. For example, the tricks from the series were used in the movie 'Crossroad in the Ancient Capital,' and episodes like 'The Kidnapping Location Identification Case' and 'The White Sandy Beach Murder Case' are based on the series [Data: Entities (42, 43, 44); Relationships (35, 36, 37)]. This cross-media influence amplifies the series' impact and reach.\n\n## Recurring Characters and Groups\n\nThe Detective Conan Mystery Files features recurring characters and groups from the original Detective Conan series, such as Kaito Kid and the Detective Boys. These recurring elements help to maintain continuity and attract fans of the original series [Data: Entities (45, 46); Relationships (38, 39)]. However, some characters like Ai Haibara do not appear in all works, indicating selective inclusion based on the storyline [Data: Entities (47); Relationships (40)].",
   'index_name': 'graphrag-index',
   'index_id': '1'},
  {'id': '1',

  #中略

  'sources': [{'id': '2',
   'text': '��に遭遇した。そして、組織に盗聴器を仕掛けた結果、そのうちの一人のコードネームはジン、もう一人はウォッカだと判明した。\n新一を尋ねるため、大阪から西の高校生探偵・服部平（以下省略）
```

## クエリ②

**グローバルクエリ**

```
### 日本のアニメの特徴

日本のアニメは、その独自のスタイルと深いストーリーテリングで世界中の視聴者を魅了しています。ここでは、「One Piece」と「名探偵コナン」の二つの代表的なアニメを通じて、日本のアニメの特徴を探ってみましょう。

#### 複雑なキャラクター関係と深いストーリーテリング

日本のアニメは、複雑なキャラクター関係と深いストーリーテリングが特徴です。「名探偵コナン」では、主要キャラクター間の複雑な関係性が物語の中心となっており、例えば、コナンと灰原、赤井との関係が重要な役割を果たしています [Data: Reports (22)]。一方、「One Piece」でも、ルフィとその仲間たちの絆や敵対関係が物語を進行させる重要な要素となっています。

#### キャラクターの成長と変化

日本のアニメは、キャラクターの成長と変化を描くことが多いです。「名探偵コナン」では、コナンが元の姿に戻るための試みや、灰原が元の姿に戻るために白乾児を飲むシーンが描かれています [Data: Reports (22, 23)]。「One Piece」でも、ルフィが仲間と共に成長し、強敵に立ち向かう姿が描かれています。

#### ミステリーやサスペンスの要素

日本のアニメは、ミステリーやサスペンスの要素を取り入れることが多いです。「名探偵コナン」では、コナンが様々な事件を解決する過程が描かれており、視聴者を引き込む要素となっています [Data: Reports (22)]。「One Piece」でも、宝探しや謎解きの要素が物語にスリルを与えています。

#### 文化的背景や歴史的要素

日本のアニメは、文化的背景や歴史的要素を取り入れることが多いです。「名探偵コナン」では、キャラクターの背景や過去の出来事が物語に深みを与えています [Data: Reports (30)]。「One Piece」でも、海賊時代の歴史や伝説が物語の舞台となっています。

#### 技術的な革新と伝統的なアニメーション技術の融合

日本のアニメは、技術的な革新と伝統的なアニメーション技術の融合が特徴です。「名探偵コナン」のようなシリーズでは、デジタル技術と手描きのアニメーションが組み合わさって使用されています [Data: Reports (16)]。「One Piece」でも、最新のアニメーション技術が駆使され、視覚的に魅力的な作品が作り上げられています。

### 結論

「One Piece」と「名探偵コナン」を通じて、日本のアニメの特徴を見てきました。複雑なキャラクター関係、キャラクターの成長、ミステリーやサスペンスの要素、文化的背景や歴史的要素、そして技術的な革新と伝統の融合が、日本のアニメを特別なものにしています。これらの要素が組み合わさることで、視聴者に深い感動と興奮を提供する作品が生まれています。
CPU times: user 235 ms, sys: 3.61 ms, total: 239 ms
Wall time: 1min 12s
```

## クエリ③

**グローバルクエリ**

```
### 毛利蘭と工藤新一の関係性

毛利蘭と工藤新一の関係性は、非常に深く複雑なものです。蘭は新一の幼馴染であり、彼のことを深く信頼しています。蘭はコナンの正体が新一であることを疑っており、これが彼女の行動や感情に大きな影響を与えています。例えば、蘭は七川絢の無実を証明するために尽力し、灰原を救うなど、重要な役割を果たしています [Data: Reports (30)]。

新一もまた、蘭との関係を非常に大切にしています。彼は一時的に元の姿に戻ることがあり、その際には蘭との関係が重要なテーマとなります。新一はニューヨークでベルモットと蘭に命を救われた経験があり、この出来事は彼らの絆をさらに強固なものにしました [Data: Reports (30)]。また、新一は蘭に対してレストランで告白しようと計画しており、これも彼らの関係の深さを示しています [Data: Reports (30)]。

### One Pieceの中で毛利探偵と相性が良い人物

### One Pieceの中で工藤新一と相性が良いと考えられる人物

One Pieceのキャラクターの中で、工藤新一と相性が良いと考えられる人物を特定するためには、彼の性格や能力を考慮する必要があります。新一は非常に知的で観察力が鋭く、推理力に優れています。このため、彼と相性が良い人物は、知的な対話ができ、共に謎を解くことができるキャラクターであると考えられます。

この観点から見ると、ニコ・ロビンが最も相性が良いキャラクターとして挙げられます。ロビンは考古学者であり、歴史や謎に対する深い知識を持っています。彼女の知識と新一の推理力が組み合わさることで、非常に強力なコンビとなるでしょう。二人は共に未知の謎を解明し、新たな発見をすることができるでしょう。

以上の分析から、毛利蘭と工藤新一の関係は非常に深く、互いに強い感情と信頼を持っていることがわかります。また、One Pieceの中で新一と相性が良いと考えられる人物は、知的な対話ができるニコ・ロビンであると考えられます。
CPU times: user 225 ms, sys: 13 ms, total: 238 ms
Wall time: 1min 30s
```

## まとめ

２つの記事にわたり、Graph RAGの解説及び検証を行いました。
検証した結果、クエリ①、②、③共に、全体のテーマやエンティティ同士の関係性を深く理解した出力が返ってきたと思います。
特に面白いと感じたのは③です。
名探偵コナンの内容に馴染みのない方には分かりづらいと思いますが、工藤新一と毛利蘭の関係性が、単なる両想いではなく、「非常に深い」ものの「複雑」であると表現されていました。
人やモノの関係性を分析し、マッチングを行う上で、有益な技術になるのではないかと思っております。

グローバルクエリとローカルクエリの差異はそれほど分かりませんでしたが、次回は、もっと大きなデータセットで検証を行いたいと思います。

ビジネス実装に向けてはまだ時間がかかる技術かと思いますが、引き続きGraph RAGの発展に注視したいと思います。