watsonx.data Milvus + watsonx.ai RAGハンズオン Part2: ベクトルDB Milvusに入ったデータで類似検索してみよう!

この内容は2024年11月27日(水)にホテル雅叙園東京で開催された「[IBM TechXchange Japan 2024](https://www.linkedin.com/posts/ibm_ibmtechxchange-activity-7270719294588542976-rA6u?utm_source=share&utm_medium=member_desktop)」で実施したwatsonxハンズオン「さわってみよう ベクトル・データベース watsonx.dataでRAG体験」の内容です。QiitaではPart1, Part2, Part3, Part4の四部構成で、　この投稿は**Part2**となります。

- [Part1: Excelをベクトル化してベクトルDB Milvusに入れよう](https://qiita.com/nishikyon/items/81a6de44aaf52f49eb0f/)
-  **Part2: ベクトルDB Milvusに入ったデータで類似検索してみよう!(当投稿)**
- [Parr3: ベクトルDB Milvusとwatsonx.ai LLMでRAGを構成して、質問をしてみよう!](https://qiita.com/nishikyon/items/a275d7a557e11d1b2d6b/)
- [Part4: ベクトルDB Milvusとwatsonx.ai LLMでRAGを構成して、チャットアプリを作成してみよう!](https://qiita.com/nishikyon/items/7cd7949cd993cc449ca9/)

# 0.前提
- [Part1: Excelをベクトル化してベクトルDB Milvusに入れよう](https://qiita.com/nishikyon/items/81a6de44aaf52f49eb0f/)を実施済み

 - [Part1: Excelをベクトル化してベクトルDB Milvusに入れよう](https://qiita.com/nishikyon/items/81a6de44aaf52f49eb0f/)と同じ実施環境

# 1. ベクトルDB Milvusに入ったデータで類似検索してみよう!
この内容はjupyter notebook https://github.com/IBM/japan-technology/blob/main/techxchange/2024-watsonx-handson-1/notebooks/techxchange_handson_02_similarity_search_03_RAG.ipynb の「2. ベクトルDB Milvusに入ったデータで類似検索してみよう!」 とほぼ同じです。Link先notebookはwatsonx.ai Studioでの実行を前提としていますが、当内容はLocalも含め一般的なpython実行環境が前提です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/49999aba-55bd-437e-0cea-2e582256c26b.png)

以下1〜5は[Part1: Excelをベクトル化してベクトルDB Milvusに入れよう](https://qiita.com/nishikyon/items/81a6de44aaf52f49eb0f/)の1〜5と全く同じです。

### 1. 必要なライブラリーのインストール
必要に応じてpipにて以下のライブラリーを導入します:
```sh
pip install 'ibm-watsonx-ai>=1.1.15'
pip install 'langchain>=0.3.3'
pip install 'langchain-ibm>=0.3.1'
pip install 'langchain-milvus>=0.1.6'
pip install 'langchain-community>=0.3.2'
pip install 'pymilvus>=2.4.8'
```

### 2. apikeyの設定
apikey をセットしてください。
IBM Cloud環境でのAPIKEYの取得方法は[こちら](https://qiita.com/nishikyon/items/fa8b951267efbe911fe7)を参考にしてください。

またwatsonx.dataとwatsonx.ai Studioは同じAPIKEYである前提で同じ変数を使用していますので、もし違う場合は2つ変数を準備するようにしてください。
```py
apikey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
```

### 3. Milvus接続情報の設定
Milvus接続情報の値をセットしてください。
- Milvus Host名
- Milvus Port番号

Milvus接続情報の詳細取得手順は[こちら](https://github.com/IBM/japan-technology/tree/main/techxchange/2024-watsonx-handson-1/watsonx_data_get_milvus_info.md) を参照してください。

またmy_connection_argsに設定するkeyの詳細は[pymilvusのMilvusClientのパラメータ](https://milvus.io/api-reference/pymilvus/v2.5.x/MilvusClient/Client/MilvusClient.md)を参照してください。

```py
milvus_host="xxx.xxx.xxx.com"
milvus_port="YYYY"

# Milvus接続情報パラメータののセット
my_connection_args ={
 'uri': f'https://{milvus_host}:{milvus_port}', 
 'token': f'ibmlhapikey:{apikey}'
}
```

### 4. watsonx.ai Studio Project idの設定
watsonx.ai Studioで実行する場合は、このノートブックが実行されるプロジェクトからProject idを取得します。 watsonx.ai Studio以外で実行する場合は、Project idを入力してください。

**Hint**: project_id はプロジェクトを表示し、管理タブから project_id を取得可能です.

```py
import os
try:
    project_id = os.environ["PROJECT_ID"]
except KeyError:
    project_id = "<ProjrctID>"
```

### 5.watsonx.aiのAuthentication用のエンドポイントのURLの設定
Waston Machine Learningのインスタンスを作成したリージョンで決まります。 https://ibm.github.io/watson-machine-learning-sdk/setup_cloud.html#authentication より

Dallas: https://us-south.ml.cloud.ibm.com
London: https://eu-gb.ml.cloud.ibm.com
Frankfurt: https://eu-de.ml.cloud.ibm.com
Tokyo: https://jp-tok.ml.cloud.ibm.com

```py
watsonx_url = "https://us-south.ml.cloud.ibm.com" #ダラスの場合
```

### 6. 必要ライブラリーのImport
```py
import pandas as pd
from langchain.schema.document import Document
import json
from langchain_milvus import Milvus
import os
from ibm_watsonx_ai.metanames import EmbedTextParamsMetaNames
from langchain_ibm import WatsonxEmbeddings
from ibm_watsonx_ai.foundation_models.utils.enums import EmbeddingTypes
```

### 7. Embeddingモデルの取得
[Part1: Excelをベクトル化してベクトルDB Milvusに入れよう](https://qiita.com/nishikyon/items/81a6de44aaf52f49eb0f/)の11と全く同じです。
ここでは`intfloat/multilingual-e5-large`を使います

- https://huggingface.co/intfloat/multilingual-e5-large
- https://dataplatform.cloud.ibm.com/docs/content/wsj/analyze-data/fm-models-embed.html?context=wx&locale=ja#multilingual-e5-large

LangChainで使用できるwatsonx.aiのEmbeddingモデルintfloat/multilingual-e5-largeがあるので、今回はこちらを使用します:
- https://python.langchain.com/docs/integrations/text_embedding/ibm_watsonx/


> 尚、`intfloat/multilingual-e5-large`はオープンソースで公開されているので、watsonx.aiのEmbeddingモデルを使用しなくとも、ローカルにダウンロードすることで使用可能です。 その場合のコードはこちらです(今回は使用しません)
> ```py
> from langchain_huggingface import HuggingFaceEmbeddings
>from tqdm.autonotebook import tqdm
>
>embeddings = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-large")
>```

<br>
下記は`apikey`はMilvusと同じものを使用しています。異なる場合は変数`apikey`を変更してください。

```py
# watsonx.aiのEmbeddingモデル取得
embed_params = {
    EmbedTextParamsMetaNames.TRUNCATE_INPUT_TOKENS: 512,
    EmbedTextParamsMetaNames.RETURN_OPTIONS: {"input_text": True},
}

embeddings = WatsonxEmbeddings(
    model_id="intfloat/multilingual-e5-large",
    url=watsonx_url,
    apikey=apikey,
    project_id=project_id
    )
```

### 8. ベクトルDB Milvusに接続
```py
from langchain_milvus import Milvus

vector_store = Milvus(
    embeddings,
    connection_args =my_connection_args,
    collection_name = my_collection
)
```

### 9. ベクトルDBでテキスト類似検索してみます
参考: LangChain ドキュメント: [Vector stores → Search ](https://python.langchain.com/docs/concepts/vectorstores/#search)

基本、類似度が高い順でリストされます。いろいろなオプションで検索してみます。

#### 9-1. similarity_search: オプションなし デフォルト
similarity_searchを使用した基本の検索です。類似度が高い順に4件出力されます。
```py
# オプションなし
query = "IBM TechXchange Japanとは?"
docs = vector_store.similarity_search(query)

for doc in docs:
    print({"content": doc.page_content[0:100], "metadata": doc.metadata} )
    print("---------")

```

出力:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/6681d1b8-1a15-411a-5889-5923a95dc49c.png)



#### 9-2. similarity_search: 結果の取得数をkで指定(デフォルトは4)
引数kを追加して件数を指定します。
```py
# 結果の取得数をkで指定(デフォルトは4)

docs = vector_store.similarity_search(query, k=10)

for doc in docs:
    print({"content": doc.page_content[0:100], "metadata": doc.metadata} )
    print("---------")
```
k=10と指定したので類似度が高い順に10件出力されます。
出力:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/2654a9bb-869d-748f-27ff-137e322dc95f.png)


#### 9-3. similarity_search_with_score: 類似度のスコアも一緒に出力
similarity_search_with_scoreを使うと類似度のスコアも一緒に取得できます。引数はsimilarity_searchと同じです。kで件数の指定が可能です。

- スコアはコサイン類似度の場合は、1に近いほど類似度が高いです。
```py
# 類似度のスコアも一緒に出してみます
# スコアはコサイン類似度の場合は、1に近いほど類似度が高いです。

docs = vector_store.similarity_search_with_score(query, k=10)
for doc, score in docs:
    print({"score": score, "content": doc.page_content[0:100], "metadata": doc.metadata} )
    print("---------")
```
scoreに類似度が入ります。これを使用して類似度が低いものは上位でも候補から外すようなことが可能になります。
出力:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/1d91461c-a3bb-dd6c-a468-8fd6f710bfa0.png)


#### 9-4. similarity_search_with_score exprオプション: 'Category': '概要'　でフィルター

せっかく列を別にしているので、'Category'を指定してそれに合致するもののみで検索します。
exprオプションを使用します。

```py
# 'Category': '概要'　でフィルターしてみます
docs = vector_store.similarity_search_with_score(query, k=10, expr="Category=='概要'")
for doc, score in docs:
    print({"score": score, "content": doc.page_content[0:100], "metadata": doc.metadata} )
    print("---------")

```
`Category=='概要'`のみから検索されています。
出力:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/fece6e13-a154-5675-8034-5816e7697e6a.png)



以上で「Part2: ベクトルDB Milvusに入ったデータで類似検索してみよう!」は完了です。

次の「[Part3: ベクトルDB Milvusとwatsonx.ai LLMでRAGを構成して、質問をしてみよう!](https://qiita.com/nishikyon/items/a275d7a557e11d1b2d6b/)」に進んでください。