手軽に始める類似文書検索：最初の一歩目

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255988/46c62c66-6750-e52e-1407-8d9fb7a78c02.png)

この記事は READYFOR Advent Calendar 2023 の8日目の記事です。

エンジニアリングマネージャーの岡村です。
直近の取り組みを踏まえ類似度検索について書きます。

LLMの登場により専門家領域に留まらず活用出来るようになってきました。
この記事では手軽に類似度検索を始める最初の一歩を紹介出来たらと思います。


### 類似度検索とは
類似度検索とはデータセット内の「類似性」に基づいて情報を探し出す手法です。このアプローチではデータポイント間の距離や関連性を測定し、クエリに最も近い結果を見つけ出すというものです。キーワード検索が特定の単語の一致に重点を置くのに対し、類似度検索はデータの「内容」や「意味」の理解に重点を置きます。活用事例としては推薦システム、画像認識、テキスト分析等があります。これらの活用事例にそった類似度のメトリクスを測る必要があります。


### 類似度を測定するメトリクス
類似度検索における「類似性」を測定するためのメトリクスを紹介します。

例えば、ユークリッド距離は、物理的な空間における二点間の直線距離を測定するのに理想的です。これは、位置データや3Dモデリングに適しています。一方で、マンハッタン距離は、道路や都市環境など、直線的な移動が制限されている状況での距離測定に適しています。そして、コサイン類似度は、方向性や意味の類似性が重要なテキスト分析や文書検索に非常に有用です。

これらのメトリクスを理解することは、類似度検索システムの構築において不可欠です。特に、大量のデータの中から最も関連性の高い情報を迅速に見つけるための効率的な方法を開発する際に重要です。

### k-Nearest Neighbors（k-NN）
データポイントからの「最も近いデータ」を見つける手法です。このアプローチは多様なデータセットでの応用が可能です。データポイント間の距離を測定し、最も近いk個のデータポイントを基に分類や予測を行います。このアルゴリズムは、特に分類問題やレコメンデーションシステムなど、様々なシナリオに適用できます。

### 類似文書検索
類似度の判定は、テキスト分析における重要な課題の一つです。これは推薦システム、検索エンジン、内容分類など様々なアプリケーションで利用されています。このプロセスでは、類似度のメトリクスとk-NNアルゴリズムが重要な役割を果たします。

まず、類似度のメトリクスですが特にコサイン類似度は、テキストデータに適しています。各文書や単語は高次元空間上の点として表現されます。コサイン類似度は、これらのベクトル間の角度を測定し、その方向の近さに基づいて類似度を評価します。これにより、内容が似ている文書は高い類似度スコアを、異なる内容の文書は低いスコアを得ることになります。

次に、k-NNアルゴリズムを利用することで、特定のテキストに最も類似した文書を効率的に見つけることができます。例えば、ある文書に基づいて関連する文書を探索する際、その文書のベクトル表現とデータセット内の他の文書のベクトルとを比較し、最も近いk個の文書を選び出します。ここでの「近さ」は、選択した類似度メトリクス（例えばコサイン類似度）によって測定されます。

この組み合わせにより、文書類似度の判定は、単なるキーワード検索を超え、テキストの深い意味的な関連性を捉えることが可能になります。その結果、関連性の高い情報が取得可能となります。

### 類似文書度検索を実現するためのシステム

#### Elasticsearch
Elasticsearchは、広く使用されている検索エンジンで、リアルタイムの全文検索と分析が可能です。文書のインデックス化、検索、分析などの機能を提供し、拡張性とスケーラビリティに優れています。

#### OpenSearch
Elasticsearchがデュアルライセンスに移行したことによりライセンス変更前のElasticsearchをベースとしたOpenSearchが開発されました。OpenSearchはElasticsearchのフォークであるため、基本的な機能やアーキテクチャは類似していますが、OpenSearchはさらにコミュニティ主導の開発に重点を置いています。

#### Apache Solr
Apache Solrは、強力な全文検索機能を備えた別の人気のあるオープンソース検索プラットフォームです。高度なカスタマイズが可能であり、大規模なデータセットに対応できます。

#### Google Cloud Search
Google Cloud Searchは、Googleの強力な検索技術を活用したクラウドベースの検索サービスです。機械学習を活用した検索機能を提供し、特にGoogleのエコシステム内での統合に優れています。

#### どれが良いの？
選定は環境によって変わるとため一概には言えませんがこれから作るのであればGoogleCloudSearchが一般的なのかと感じています。弊社ではAWSを活用していることもありOpenSearchを採用しています。

またビジネスにおいては特にデータの入出力方法を検討する必要があります、例えばFaissでIndexを作成しファイル保存する事を考えた際、セキュリティやストレージを考慮する必用があります。
管理コストが高くなるためOpenSearchにIndexを作ることでこのあたりの管理を簡略化しています。またOpenSearchではFaissエンジンがサポートされています。

※Faissとは
高速な類似度検索: Faissは高次元ベクトル間の類似度検索（特にコサイン類似度を含む）に特化しており、大規模なデータセットに対しても高速な検索を提供します。機械学習との連携: Faissは機械学習モデルから得られる埋め込みベクトルの処理に適しています。

### OpenSearchを利用した類似度検索システムの構築手順
#### データの準備
データの準備と前処理は、類似度検索システムの成功において非常に重要なステップです。特にOpenSearchやFaissを使用する際には、以下のポイントに注意してデータを準備する必要があります。

- データの前処理
  - クレンジング
      - データから不要または誤った情報を除去します。これには、不完全なレコードの削除、誤ったフォーマットの修正などが含まれます。
  - 文字列の標準形式化
    - データを一定の標準形式に変換します。テキストデータの場合、大文字を小文字に変換したり、句読点を除去したりすることが含まれます。
- トークン化とベクトル化
  - テキストデータをトークン（単語やフレーズ）に分割し、それらを数値ベクトルに変換します。OpenAIなどのLLMを利用すると良いでしょう。
  - 次元削減
    - 高次元データセットの場合、主成分分析やt-SNEなどの技術を使用して次元数を減らすことが有効です。


#### インデックスの作成
OpenSearchで新しいインデックスを作成し、インデックスに追加します。

##### インデックス作成とマッピング設定
```python
from opensearchpy import OpenSearch, RequestsHttpConnection

# OpenSearchへの接続
# OpenSearchインスタンスの作成

mapping = {
    "properties": {
        "my_vector": {
            "type": "knn_vector",
            "dimension": 128,  # ベクターの次元数
            }
        },
        "title": {
            "type": "text"
        },
        "content": {
            "type": "text"
        }
    }
}

# インデックスの作成とマッピングの設定
if not search.indices.exists(index_name):
    search.indices.create(index=index_name, body={"mappings": mapping})
```
##### インデックスの追加

```python
from opensearchpy import OpenSearch, RequestsHttpConnection

# OpenSearchへの接続
# OpenSearchインスタンスの作成

# インデックスを作成するデータ
document = {
    "title": "サンプルドキュメント",
    "content": "これはOpenSearchにインデックスされるサンプルのテキストです。",
    "my_vector": [0.5, 0.6, ...]  # 128次元のベクター
}

# ドキュメントをインデックスに追加
response = search.index(index=index_name, body=document)
print(response)

```


##### 検索

```python
from opensearchpy import OpenSearch, RequestsHttpConnection

# OpenSearchへの接続
# OpenSearchインスタンスの作成

# インデックス名
index_name = 'my_index'

# 検索するためのベクター
search_vector = [0.3, 0.4, ...]  # 128次元のベクター

# KNN検索クエリ
knn_query = {
    "size": 10,  # 取得するドキュメントの数
    "query": {
        "knn": {
            "my_vector": {
                "vector": search_vector,
                "k": 5  # 返すべき最も近い隣接点の数
            }
        }
    }
}

# クエリの実行
response = search.search(index=index_name, body=knn_query)
print(response)

```

## 類似度検索の活用事例
類似検索技術は多岐にわたる用途で活用されています。その一部を紹介します。

1. Slackからのデータ収集による社内問い合わせの類似検索
Slackから収集したデータを用いて、社内の問い合わせに対する類似検索です。

2. 類似プロジェクト検索
過去に行われたプロジェクトのデータベースを活用し、現在計画中または進行中のプロジェクトと類似する過去のプロジェクトを検索します。

3. 類似プロジェクトを参考にしたプロジェクト生成サポート
新しいプロジェクトのアイデア生成や計画段階においても役立ちます。過去の類似プロジェクトを参考にすることで、新たなアプローチのインスピレーションを得ることができます。

類似度検索はより的確な情報発見に寄与し大きなインパクトをもたらすと考えています。これからもLLMを活用した様々なアプローチを追求出来たらと思います。

--- 
明日は中村さんの記事が公開される予定です！

READYFOR アドベントカレンダー 2023
https://qiita.com/advent-calendar/2023/readyfor