CLOVER🍀

That was when it all began.

Qdrantのチュートリアルから、「シンプルなNeural Searchサービスを作成する(Create a Simple Neural Search Service)」を試す

これは、なにをしたくて書いたもの?

Qdrantのチュートリアルを進めてみようシリーズです。

今回は「シンプルなNeural Searchサービスを作成する(Create a Simple Neural Search Service)」を試します。

Neural Search Service - Qdrant

ところで、Neural Searchってなんでしょうね?

少し調べてみましょう。

Amazon OpenSearchより。

何年もの間、お客様は OpenSearch k-NN でセマンティック検索アプリケーションを構築してきましたが、テキスト埋め込みモデルを検索パイプラインやインジェストパイプラインに統合するためのミドルウェアの構築が悩みの種になっていました。Amazon OpenSearch Service をご利用のお客様は、Amazon SageMaker および Amazon Bedrock との統合により Neural Search を強化できます。

Neural Search を使用すれば、OpenSearch API を使用して人間の言語で検索クエリを実行し、セマンティックな理解と類似性を組み込んだテキスト埋め込みを使用してより関連性の高い検索結果を得ることができます。

Amazon OpenSearch Service が Neural Search を導入

記事としてはこちらが良さそうですね。

  • 従来型キーワード検索
    • 検索エンジン用のルールを事前に作成する必要がある
    • キーワードの比較方法によっては正確な結果が得られるとは限らないし、目的に合わせた最適なランクが得られるとも限らない
    • 高速
  • ベクトル検索
    • テキストをベクトルに変換して使用することで、検索エンジンはテキストのコンテキストを理解できるようになる
    • 単語をベクトルに変換する過程で、意味がエンコードされる
    • 単語の関係を理解するため、キーワード検索より優れたパフォーマンスを発揮する
    • キーワード検索に比べると遅く、拡張性が低く、コストも高い
  • Neural Search

What is neural search and how does it work?

Qdrantのチュートリアルでは、人工ニューラルネットワークを使って検索結果の制度と関連性を向上させるものだと書かれていますね。
また、単純なキーワード検索を提供するだけでなく、意味も見てくれます、と。

A neural search service uses artificial neural networks to improve the accuracy and relevance of search results. Besides offering simple keyword results, this system can retrieve results by meaning. It can understand and interpret complex search queries and provide more contextually relevant output, effectively enhancing the user’s search experience.

Neural Search Service - Qdrant

とはいえですね、今の知識だとこの説明を見てもベクトル検索との違いがわかりません…。

とりあえず、チュートリアルを進めていってみましょう。

環境

今回の環境はこちら。Qdrantは172.17.0.2で動作しているものとします。

$ ./qdrant --version
qdrant 1.7.4

QdrantのWeb UIは0.1.21を使っています。

Qdrant Clientを使うPython環境。

$ python3 --version
Python 3.10.12


$ pip3 --version
pip 22.0.2 from /usr/lib/python3/dist-packages/pip (python 3.10)

Qdrantのチュートリアル「シンプルなNeural Searchサービスを作成する(Create a Simple Neural Search Service)」を試す

それでは、Qdrantのチュートリアル「シンプルなNeural Searchサービスを作成する(Create a Simple Neural Search Service)」を
ドキュメントに沿って進めていきます。

Neural Search Service - Qdrant

お題としては、スタートアップ企業のdescriptionからクエリーに最も類似した企業を探す、というもののようです。

まずはデータセットのダウンロード。

$ curl -LO https://storage.googleapis.com/generall-shared-data/startups_demo.json

こんな感じのJSON Linesですね。

$ head -n 5 startups_demo.json
{"name":"SaferCodes","images":"https:\/\/safer.codes\/img\/brand\/logo-icon.png","alt":"SaferCodes Logo QR codes generator system forms for COVID-19","description":"QR codes systems for COVID-19.\nSimple tools for bars, restaurants, offices, and other small proximity businesses.","link":"https:\/\/safer.codes","city":"Chicago"}
{"name":"Human Practice","images":"https:\/\/d1qb2nb5cznatu.cloudfront.net\/startups\/i\/373036-94d1e190f12f2c919c3566ecaecbda68-thumb_jpg.jpg?buster=1396498835","alt":"Human Practice -  health care information technology","description":"Point-of-care word of mouth\nPreferral is a mobile platform that channels physicians\u2019 interest in networking with their peers to build referrals within a hospital system.\nHospitals are in a race to employ physicians, even though they lose billions each year ($40B in 2014) on employment. Why ...","link":"http:\/\/humanpractice.com","city":"Chicago"}
{"name":"StyleSeek","images":"https:\/\/d1qb2nb5cznatu.cloudfront.net\/startups\/i\/3747-bb0338d641617b54f5234a1d3bfc6fd0-thumb_jpg.jpg?buster=1329158692","alt":"StyleSeek -  e-commerce fashion mass customization online shopping","description":"Personalized e-commerce for lifestyle products\nStyleSeek is a personalized e-commerce site for lifestyle products.\nIt works across the style spectrum by enabling users (both men and women) to create and refine their unique StyleDNA.\nStyleSeek also promotes new products via its email newsletter, 100% personalized ...","link":"http:\/\/styleseek.com","city":"Chicago"}
{"name":"Scout","images":"https:\/\/d1qb2nb5cznatu.cloudfront.net\/startups\/i\/190790-dbe27fe8cda0614d644431f853b64e8f-thumb_jpg.jpg?buster=1389652078","alt":"Scout -  security consumer electronics internet of things","description":"Hassle-free Home Security\nScout is a self-installed, wireless home security system. We've created a more open, affordable and modern system than what is available on the market today. With month-to-month contracts and portable devices, Scout is a renter-friendly solution for the other ...","link":"http:\/\/www.scoutalarm.com","city":"Chicago"}
{"name":"Invitation codes","images":"https:\/\/invitation.codes\/img\/inv-brand-fb3.png","alt":"Invitation App - Share referral codes community ","description":"The referral community\nInvitation App is a social network where people post their referral codes and collect rewards on autopilot.","link":"https:\/\/invitation.codes","city":"Chicago"}

このデータは、実際のWebサイトを見た方がイメージつくかもしれませんね。

Startups List

データ量はこれくらいです。

$ ll -h startups_demo.json
-rw-rw-r-- 1 xxxxx xxxxx 22M  2月 10 21:24 startups_demo.json


$ wc -l startups_demo.json
40473 startups_demo.json

最初は、このデータをベクトルに変換します。

ライブラリーのインストール。

$ pip3 install sentence-transformers numpy pandas tqdm

バージョン。

$ pip3 list
Package                  Version
------------------------ ----------
certifi                  2024.2.2
charset-normalizer       3.3.2
click                    8.1.7
filelock                 3.13.1
fsspec                   2024.2.0
huggingface-hub          0.20.3
idna                     3.6
Jinja2                   3.1.3
joblib                   1.3.2
MarkupSafe               2.1.5
mpmath                   1.3.0
networkx                 3.2.1
nltk                     3.8.1
numpy                    1.26.4
nvidia-cublas-cu12       12.1.3.1
nvidia-cuda-cupti-cu12   12.1.105
nvidia-cuda-nvrtc-cu12   12.1.105
nvidia-cuda-runtime-cu12 12.1.105
nvidia-cudnn-cu12        8.9.2.26
nvidia-cufft-cu12        11.0.2.54
nvidia-curand-cu12       10.3.2.106
nvidia-cusolver-cu12     11.4.5.107
nvidia-cusparse-cu12     12.1.0.106
nvidia-nccl-cu12         2.19.3
nvidia-nvjitlink-cu12    12.3.101
nvidia-nvtx-cu12         12.1.105
packaging                23.2
pandas                   2.2.0
pillow                   10.2.0
pip                      22.0.2
python-dateutil          2.8.2
pytz                     2024.1
PyYAML                   6.0.1
regex                    2023.12.25
requests                 2.31.0
safetensors              0.4.2
scikit-learn             1.4.0
scipy                    1.12.0
sentence-transformers    2.3.1
sentencepiece            0.1.99
setuptools               59.6.0
six                      1.16.0
sympy                    1.12
threadpoolctl            3.2.0
tokenizers               0.15.1
torch                    2.2.0
tqdm                     4.66.1
transformers             4.37.2
triton                   2.2.0
typing_extensions        4.9.0
tzdata                   2023.4
urllib3                  2.2.0

ベクトル化には、こんなファイルを作成。

to_vector.py

from sentence_transformers import SentenceTransformer
import numpy as np
import json
import pandas as pd
from tqdm.notebook import tqdm

model = SentenceTransformer("all-MiniLM-L6-v2", device="cpu")

df = pd.read_json("./startups_demo.json", lines=True)

vectors = model.encode(
    [row.alt + ". " + row.description for row in df.itertuples()],
    show_progress_bar=True
)

print(f"vectors shape = {vectors.shape}")

np.save("startup_vectors.npy", vectors, allow_pickle=False)

Sentence Transformersのインスタンスを、モデルはall-MiniLM-L6-v2で作成。

model = SentenceTransformer("all-MiniLM-L6-v2", device="cpu")

Pandasでデータセットをパースして

df = pd.read_json("./startups_demo.json", lines=True)

各JSONデータのaltとdescriptionを.でつなげてベクトルに変換します。

vectors = model.encode(
    [row.alt + ". " + row.description for row in df.itertuples()],
    show_progress_bar=True
)

時間がかかるので、プログレスバーを表示するようにしています。

ベクトルに変換したら、次元数を表示して

print(f"vectors shape = {vectors.shape}")

ファイルとして保存します。

np.save("startup_vectors.npy", vectors, allow_pickle=False)

実行。

$ python3 to_vector.py

進捗が表示されますが、自分の環境では20分ほどかかりました…。

Batches:  20%|██████████████████████████▋                                                                                                        | 258/1265 [04:08<15:18,  1.10it/s]

次元数。384次元で、40474個のデータがあることになっています。

vectors shape = (40474, 384)

できあがったファイル。

$ ll -h startup_vectors.npy
-rw-rw-r-- 1 xxxxx xxxxx 60M  2月 10 22:16 startup_vectors.npy

中身はバイナリーです。

次は、ベクトル化したデータをQdrantにアップロードします。

Qdrant Clientをインストール。

$ pip3 install qdrant-client

この時点でのライブラリー一覧。

$ pip3 list
Package                  Version
------------------------ ----------
annotated-types          0.6.0
anyio                    4.2.0
certifi                  2024.2.2
charset-normalizer       3.3.2
click                    8.1.7
exceptiongroup           1.2.0
filelock                 3.13.1
fsspec                   2024.2.0
grpcio                   1.60.1
grpcio-tools             1.60.1
h11                      0.14.0
h2                       4.1.0
hpack                    4.0.0
httpcore                 1.0.2
httpx                    0.26.0
huggingface-hub          0.20.3
hyperframe               6.0.1
idna                     3.6
Jinja2                   3.1.3
joblib                   1.3.2
MarkupSafe               2.1.5
mpmath                   1.3.0
networkx                 3.2.1
nltk                     3.8.1
numpy                    1.26.4
nvidia-cublas-cu12       12.1.3.1
nvidia-cuda-cupti-cu12   12.1.105
nvidia-cuda-nvrtc-cu12   12.1.105
nvidia-cuda-runtime-cu12 12.1.105
nvidia-cudnn-cu12        8.9.2.26
nvidia-cufft-cu12        11.0.2.54
nvidia-curand-cu12       10.3.2.106
nvidia-cusolver-cu12     11.4.5.107
nvidia-cusparse-cu12     12.1.0.106
nvidia-nccl-cu12         2.19.3
nvidia-nvjitlink-cu12    12.3.101
nvidia-nvtx-cu12         12.1.105
packaging                23.2
pandas                   2.2.0
pillow                   10.2.0
pip                      22.0.2
portalocker              2.8.2
protobuf                 4.25.2
pydantic                 2.6.1
pydantic_core            2.16.2
python-dateutil          2.8.2
pytz                     2024.1
PyYAML                   6.0.1
qdrant-client            1.7.3
regex                    2023.12.25
requests                 2.31.0
safetensors              0.4.2
scikit-learn             1.4.0
scipy                    1.12.0
sentence-transformers    2.3.1
sentencepiece            0.1.99
setuptools               59.6.0
six                      1.16.0
sniffio                  1.3.0
sympy                    1.12
threadpoolctl            3.2.0
tokenizers               0.15.1
torch                    2.2.0
tqdm                     4.66.1
transformers             4.37.2
triton                   2.2.0
typing_extensions        4.9.0
tzdata                   2023.4
urllib3                  2.2.0

データをQdrantにアップロードするプログラムを作成。

upload_data.py

import json
import numpy as np
from qdrant_client import QdrantClient
import qdrant_client
from qdrant_client.models import VectorParams, Distance

qdrant_client = QdrantClient(host="172.17.0.2", port=6333)

qdrant_client.recreate_collection(
    collection_name="startups",
    vectors_config=VectorParams(size=384, distance=Distance.COSINE)
)

fd = open("./startups_demo.json")

payload = map(json.loads, fd)

vectors = np.load("./startup_vectors.npy")

qdrant_client.upload_collection(
    collection_name="startups",
    vectors=vectors,
    payload=payload,
    ids=None,
    batch_size=256
)

QdrantClientのインスタンスを作成して、コレクションを作成します。コレクションがすでに存在する場合は、再作成になります。

qdrant_client = QdrantClient(host="172.17.0.2", port=6333)

qdrant_client.recreate_collection(
    collection_name="startups",
    vectors_config=VectorParams(size=384, distance=Distance.COSINE)
)

ベクトルの次元数は384、距離メトリクスはコサイン類似度です。

JSONファイルからペイロードを、numpyで保存したファイルからベクトル化したデータをそれぞれ取得します。

fd = open("./startups_demo.json")

payload = map(json.loads, fd)

vectors = np.load("./startup_vectors.npy")

Qdrantにアップロード。

qdrant_client.upload_collection(
    collection_name="startups",
    vectors=vectors,
    payload=payload,
    ids=None,
    batch_size=256
)

実行。

$ python3 upload_data.py

少し時間がかかりますが、データのアップロードはこれで完了です。

最後に検索APIを作成します。

最終的にはFastAPIを使ったREST APIとして作成するので、FastAPIおよびUvicornをインストール。

$ pip3 install fastapi uvicorn[standard]

インストールしたライブラリーの最終リスト。

$ pip3 list
Package                  Version
------------------------ ----------
annotated-types          0.6.0
anyio                    4.2.0
certifi                  2024.2.2
charset-normalizer       3.3.2
click                    8.1.7
exceptiongroup           1.2.0
fastapi                  0.109.2
filelock                 3.13.1
fsspec                   2024.2.0
grpcio                   1.60.1
grpcio-tools             1.60.1
h11                      0.14.0
h2                       4.1.0
hpack                    4.0.0
httpcore                 1.0.2
httptools                0.6.1
httpx                    0.26.0
huggingface-hub          0.20.3
hyperframe               6.0.1
idna                     3.6
Jinja2                   3.1.3
joblib                   1.3.2
MarkupSafe               2.1.5
mpmath                   1.3.0
networkx                 3.2.1
nltk                     3.8.1
numpy                    1.26.4
nvidia-cublas-cu12       12.1.3.1
nvidia-cuda-cupti-cu12   12.1.105
nvidia-cuda-nvrtc-cu12   12.1.105
nvidia-cuda-runtime-cu12 12.1.105
nvidia-cudnn-cu12        8.9.2.26
nvidia-cufft-cu12        11.0.2.54
nvidia-curand-cu12       10.3.2.106
nvidia-cusolver-cu12     11.4.5.107
nvidia-cusparse-cu12     12.1.0.106
nvidia-nccl-cu12         2.19.3
nvidia-nvjitlink-cu12    12.3.101
nvidia-nvtx-cu12         12.1.105
packaging                23.2
pandas                   2.2.0
pillow                   10.2.0
pip                      22.0.2
portalocker              2.8.2
protobuf                 4.25.2
pydantic                 2.6.1
pydantic_core            2.16.2
python-dateutil          2.8.2
python-dotenv            1.0.1
pytz                     2024.1
PyYAML                   6.0.1
qdrant-client            1.7.3
regex                    2023.12.25
requests                 2.31.0
safetensors              0.4.2
scikit-learn             1.4.0
scipy                    1.12.0
sentence-transformers    2.3.1
sentencepiece            0.1.99
setuptools               59.6.0
six                      1.16.0
sniffio                  1.3.0
starlette                0.36.3
sympy                    1.12
threadpoolctl            3.2.0
tokenizers               0.15.1
torch                    2.2.0
tqdm                     4.66.1
transformers             4.37.2
triton                   2.2.0
typing_extensions        4.9.0
tzdata                   2023.4
urllib3                  2.2.0
uvicorn                  0.27.1
uvloop                   0.19.0
watchfiles               0.21.0
websockets               12.0

検索を行う部分は、クラスとして作成します。

neural_searcher.py

from qdrant_client import QdrantClient
from sentence_transformers import SentenceTransformer

class NeuralSearcher:
    def __init__(self, collection_name):
        self.collection_name = collection_name
        self.model = SentenceTransformer("all-MiniLM-L6-v2", device="cpu")
        self.qdrant_client = QdrantClient(host="172.17.0.2", port=6333)

    def search(self, text: str):
        vector = self.model.encode(text).tolist()

        search_result = self.qdrant_client.search(
            collection_name=self.collection_name,
            query_vector=vector,
            query_filter=None,
            limit=5
        )

        payloads = [hit.payload for hit in search_result]

        return payloads

引数のテキストをベクトル化して、Qdrantで検索します。

    def search(self, text: str):
        vector = self.model.encode(text).tolist()

        search_result = self.qdrant_client.search(
            collection_name=self.collection_name,
            query_vector=vector,
            query_filter=None,
            limit=5
        )

        payloads = [hit.payload for hit in search_result]

        return payloads

Neural Searchと言っても特別なことをしているわけではなく、ふつうにQdrantで検索しているだけですね。

このクラスを使ったREST APIの作成。

service.py

from fastapi import FastAPI
from neural_searcher import NeuralSearcher

app = FastAPI()

neural_searcher = NeuralSearcher(collection_name="startups")

@app.get("/api/search")
def search(q: str):
    return {"result": neural_searcher.search(q)}

Uvicornで起動します。

$ uvicorn service:app

確認してみましょう。

「programmer」で検索してみます。

$ curl -s localhost:8000/api/search?q=programmer | jq
{
  "result": [
    {
      "alt": "Codesmith -  education developer tools",
      "city": "Los Angeles",
      "description": "Teaching software engineering through an immersive academy\nCodesmith teaches students across the US modern programing with Javascript so they can take roles as Software Engineers or launch their own ventures after graduating. We're transforming Software Engineering Education through our immersive platform and academies ...",
      "images": "https://d1qb2nb5cznatu.cloudfront.net/startups/i/642848-65eea9a4e5699f0b74ab44d434c94d2c-thumb_jpg.jpg?buster=1427735306",
      "link": "http://codesmith.io",
      "name": "Codesmith"
    },
    {
      "alt": "HackerEarth -  marketplaces recruiting college recruiting programming",
      "city": "Bangalore",
      "description": "Helping companies find the smartest programmers\nHackerEarth is building an engaged community of developers with a deep skill graph of each developer on the network. Developers can come and participate in online programming challenges (https://www.hackerearth.com/challenges) and Hackathons and solve problems ...",
      "images": "https://d1qb2nb5cznatu.cloudfront.net/startups/i/134498-a29b2f7d1ddd293823db1253417a42ce-thumb_jpg.jpg?buster=1354195180",
      "link": "https://www.hackerearth.com",
      "name": "HackerEarth"
    },
    {
      "alt": "Makers Academy -  education software",
      "city": "London",
      "description": "Europe's first coding bootcamp\nFor over a year now, Makers Academy has been training web developers. We've placed our graduates in a variety of London-based tech companies ranging from Sky to Pivotal Labs.\nWe're now taking the things we've learned by teaching students face-to-face to build ...",
      "images": "https://d1qb2nb5cznatu.cloudfront.net/startups/i/206002-fdcb0badf8882cd406be854f70594d98-thumb_jpg.jpg?buster=1391786676",
      "link": "http://www.makersacademy.com",
      "name": "Makers Academy"
    },
    {
      "alt": "Coderletics -  e-commerce education entrepreneur software engineering",
      "city": "Munich",
      "description": "Build websites and apps without having to become a developer.\nBuild websites and apps without having to become a developer. Get the superpowers to realize your own ideas.",
      "images": "https://d1qb2nb5cznatu.cloudfront.net/startups/i/495430-2c0a070c846eba14a9a24aa562384ec3-thumb_jpg.jpg?buster=1411645139",
      "link": "http://www.coderletics.com",
      "name": "Coderletics"
    },
    {
      "alt": "Hack Reactor -  education recruiting web development",
      "city": "San Francisco",
      "description": "The CS Degree for the 21st Century.\nLearn the skills needed to become a Software Engineer in an intensive course that runs 12 hours a day, 6 days per week, for 3 months. The course is based in JavaScript, with an emphasis on modern tools and frameworks like Angular.js, Backbone.js, Node.js, jQuery, ...",
      "images": "https://d1qb2nb5cznatu.cloudfront.net/startups/i/171224-6f1a18f4cf2d02f2b0610e23dd91ea27-thumb_jpg.jpg?buster=1377810081",
      "link": "http://www.hackreactor.com/",
      "name": "Hack Reactor"
    }
  ]
}

「sns」で検索。

$ curl -s localhost:8000/api/search?q=sns | jq
{
  "result": [
    {
      "alt": "Altr think -  digital media music photography sns",
      "city": "Tokyo",
      "description": "With Contents Without Any Words\n\"&\" is SNS App without any words.\nWe are forcusing on Nonverbal communication via Pic and Sound on MAP.\nIn \"&\", you can connect your content (Pic or Sound) to stranger's one directly by only 3 taps.\nAnd you can get the whole view of these connections on MAP anytime, ...",
      "images": "https://d1qb2nb5cznatu.cloudfront.net/startups/i/208649-087b94437db023d390c9ca8d5e7a840c-thumb_jpg.jpg?buster=1368621734",
      "link": "http://www.altrthink.com",
      "name": "Altr think"
    },
    {
      "alt": "SNMsystems -  it and cybersecurity",
      "city": "Washington DC",
      "description": "SNMsystems is a small IT company. Hope to get Fed IT contracts",
      "images": "https://angel.co/images/shared/nopic_startup.png",
      "link": "http://www.snmsystemsllc.com",
      "name": "SNMsystems"
    },
    {
      "alt": "Scalix -  messaging",
      "city": "New York",
      "description": "",
      "images": "https://d1qb2nb5cznatu.cloudfront.net/startups/i/47943-5f0518a6ead7a7c40ae8b9b1b050ead5-thumb_jpg.jpg?buster=1407857314",
      "link": "http://www.scalix.com/",
      "name": "Scalix"
    },
    {
      "alt": "Syndicated Content Network -  advertising content delivery magazine Bloggers",
      "city": "Tel Aviv",
      "description": "Online Content Exchange\nSyndicated Content Network (SCN) is an advanced technology platform enabling distribution of online content from creators to publishers. It has the potential to become one of the web's most widely used platforms.\nAround the world there are millions of publishers ...",
      "images": "https://d1qb2nb5cznatu.cloudfront.net/startups/i/509023-e659bbdd6cf26e36490394927f2688e7-thumb_jpg.jpg?buster=1413127099",
      "link": "http://To be advised",
      "name": "Syndicated Content Network"
    },
    {
      "alt": "Snyc -  mobile telecommunications messaging Behavioural Science",
      "city": "Los Angeles",
      "description": "Send last minute plans to all your best friends with one tap\nWe believe smartphone use is approaching a tipping point in which the flood of social media and phone communication will become more distracting and cumbersome than helpful and fun. Status streamlines communication by integrating status updates into your phone's ...",
      "images": "https://d1qb2nb5cznatu.cloudfront.net/startups/i/267172-ffa8a56690b6719bddc83f453fd040a2-thumb_jpg.jpg?buster=1414446321",
      "link": "http://www.snyc.io",
      "name": "Snyc"
    }
  ]
}

なんとなく、それっぽい感じになっている気がします。

ちなみに、このアプリケーションはQdrantのデモとして公開されていて、Neural Searchと全文検索を切り替えて試すことができるようです。

Semantic Search Demo - Qdrant

気になる人は試してみるとよいかと。

おわりに

Qdrantのチュートリアルから、「シンプルなNeural Searchサービスを作成する(Create a Simple Neural Search Service)」を試して
みました。

Qdrantの使い方自体はQuickstartやチュートリアルのセマンティック検索と変わらないのですが、Sentence Transformersを使った
データのベクトル化とファイル保存、Qdrantへのアップロードから検索サービスの作成まで押さえられて良かったかなと思います。