46.5kデモを予約するログイン無料で始める

クリスティ・バーグマン私がZillizに入社した理由

Oct 06, 20232 min read

私の名前はChristy Bergmanです。最近、サンフランシスコを拠点とするデベロッパー・アドボケイトとしてZillizに加わりました。私は、イベントの企画、参加、講演、ブログやコードチュートリアルの執筆、ドキュメントの改善、そして一般的に人々がMilvusの使い方を学ぶ手助けをする予定です。Milvusは、世界で最も人気のあるオープンソースのベクトルデータベースです(GitHubのスター数で測定)。

Zillizの前は、オープンソースのRayを開発したAnyscaleでデベロッパー・アドボケイトをしていました。それ以前は、AWSのAI/MLスペシャリスト・ソリューション・アーキテクトとして、ディープラーニングの予測に注力していました。

では、なぜZillizを選んだのか?それは、プロンプトにコンテキストを注入することでChatGPTのチャット出力を改善することへの好奇心から始まりました。その後、埋め込みをいじる探求を始め、そこから使いやすく高速なベクトルデータベースを探し始めました。このブログ記事では、私がここにたどり着くまでのステップを紹介します。

ベクターデータベースは本当に必要なのか?

当初、ベクターデータベースが必要かどうかさえ疑問でした。しかし、Pythonの変数にテキストを埋め込み、それをpicklingしたりunpicklingしたりすることを何度か試したことで、埋め込みはpickleよりも良い場所にキャッシュされるか永続化されるに違いないと思うようになりました。

Milvusは、ベクトル用に一から作られた本格的なデータベースです。世界中の何千人もの開発者がMilvusを使用しており、さまざまなベクトル検索アルゴリズム、ベクトル空間距離メトリクス、Insert/upsert、TopK、Range Search、GPUサポートなどの機能をサポートしています。商用版はZilliz Cloudと呼ばれ、99.9%のSLA可用性、自動スケーリング、AWSとGCP(Azureは近日公開予定)上で動作し、完全なSOC2コンプライアンスでクラウドアカウント上で実行することができます。

ベクターデータベースを試す

エンベッディングをベクターデータベースに取り込むには、以下のものが必要です:1)非構造化データ、2)そのデータをどのようにチャンクするかの計画、3)埋め込みモデル、4)ベクトルデータベース。

データとしては、スタンフォードAIラボのIMDB large movie review datasetを使った。これは、50,000のデータセット(50:50の割合でポジティブ/ネガティブレビューをサンプリング)を便利に処理したものである。このデータには、movie_index、生のレビューテキスト、映画の評価というカラムがある。

チャンキングのために、私はそれが非常に長くない限り、そのまま映画のレビュー全体を維持することを選択しました。非常に長いレビューについては、典型的なデフォルトの512の長さのチャンクを使用しました。つまり、長いレビューはいくつかの512文字の長さの断片に分割されました。LLMの専門用語では、これを「チャンクサイズ」と呼ぶ。

埋め込みモデルについては、どこにでもあるOpenAIの埋め込みを含め、様々なモデルを試した。一番簡単なのは、MTEB HuggingFace leaderboardのon-the-Retriever-tabで上位にランクされている、常に動いている最小のターゲットを選択することだ。その時は「e5-base-v2」に落ち着いた。埋め込みモデルの選択が、ベクトルデータベース自体から独立しているのは、実は良いことなのだ。

データベースは、FAISS、Qdrant、Chroma、Weaviate、Pinecone、そしてもちろんMilvusを試した。1)pandasからベクトルデータベースに直接ロードするのがどれだけ簡単で速いか?2) ベクターデータベースから良いクエリ結果を得るのはどれくらい簡単で、速く、調整可能か?3)LangChainを使ってRAGを実行するのはどれくらい簡単で調整可能か。

Milvusは際立っている

私が調査したすべてのデータベースの中で、Milvusはいくつかの理由で私の注意を引いた。第一に、特にpandasから直接メタデータと共にデータを挿入する場合、データサイエンティストが最初に試すアプローチであるため、ユーザーフレンドリーなエクスペリエンスを提供している。

Milvusはまた、ベクトルの読み込みとクエリのスピードが速いという点でも私の目を引いた。Milvusは、他のアプローチよりも明らかに軽快で、中にはこの小規模なスケールでも遅いものもありました。また、Milvusが他の選択肢をサポートしているにもかかわらず、私はその機能に注目し、他のデータベースのデフォルト設定(L2-metricによるIVF-flat網羅的検索)を選択した。

以下はpandasデータフレームをMilvusに挿入するためのgistです。完全なコードは私のGitHubにあります。

# Complete code is at: https://github.com/christy/ZillizDemos/blob/main/milvus_onboarding/hello_world_milvus.ipynb
###########
# 1.HuggingFace Hubから文変換器をダウンロードしてローカルで使用する。
###########
import os
from dotenv import load_dotenv, find_dotenv
from huggingface_hub import ログイン
_ = load_dotenv(find_dotenv())
hub_token = os.getenv("HUGGINGFACEHUB_API_TOKEN")
login(token=hub_token);

from sentence_transformers import SentenceTransformer
モデル名 = "BAAI/bge-base-en-v1.5"
retriever = SentenceTransformer(model_name, device="cuda")

# モデルパラメータを取得し、後で使用するために保存します。
MAX_SEQ_LENGTH = retriever.get_max_seq_length()
hf_eos_token_length = 1
EMBEDDING_LENGTH = retriever.get_sentence_embedding_dimension()

###########
# 2.便宜上、LangChainからチャンキング関数を選択。
###########
from langchain.text_splitter import RecursiveCharacterTextSplitter

chunk_size = MAX_SEQ_LENGTH - HF_TOKEN_EOS_LENGTH
chunk_overlap = np.round(chunk_size * 0.10, 0)

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=chunk_size、
    chunk_overlap=chunk_overlap、
    length_function=len、
)

def chunk_text(text):
    chunks = text_splitter.split_text(text)
    return [チャンク for チャンク in チャンク if チャンク].

###########
# 3.pandasのデータフレームを操作する。
# ダウンロード: https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
###########
# 1.pandas DataFrameからバッチデータを取得。
バッチ = df.head(100).copy()

# 2.主キーの型を文字列に変更。
batch["movie_index"] = batch["movie_index"].apply(lambda x: str(x))

# 3.レビューを512文字に切り詰める。
batch['chunk'] = batch['text'].apply(chunk_text)
バッチ = batch.explode('chunk', ignore_index=True)

# 4.dfの新しいカラムとしてembeddingsを追加する。
review_embeddings=torch.tensor(retriever.encode(バッチ['チャンク']))
# 埋め込みを単位長に正規化。
review_embeddings = F.normalize(review_embeddings, p=2, dim=1)

# 5.埋め込み値を `numpy.ndarray` のリストに変換。各リストには `numpy.float32` の数値が格納されている。
converted_values = list(map(np.float32, review_embeddings))
batch['embeddings'] = converted_values

# 6.インデックスを最初に、ラベルを最後に。
new_order = ["movie_index", "text", "chunk", "embeddings", "label_int", "label"].
バッチ = バッチ[new_order].

###########
# 4.milvusをインストールしてインポートする。
###########
pip install milvus pymilvus
インポート milvus, pymilvus

###########
# 5.Milvus にデータをロードするためのスキーマを定義します。
###########
# Milvusコレクション名を設定します。
COLLECTION_NAME = "movies"

fields = [
    FieldSchema(name="pk", dtype=DataType.INT64, is_primary=True, auto_id=True)、
    FieldSchema(name="movie_index",dtype=DataType.VARCHAR,max_length=8)、
    FieldSchema(name="chunk", dtype=DataType.VARCHAR, max_length=MAX_SEQ_LENGTH)、
    FieldSchema(name="embeddings",dtype=DataType.FLOAT_VECTOR,dim=EMBEDDING_LENGTH)、
    FieldSchema(name="label_int", dtype=DataType.INT64)、
    FieldSchema(name="label", dtype=DataType.VARCHAR, max_length=8)、
]

schema = CollectionSchema(fields, "Search imdb movie reviews")
mc = Collection(COLLECTION_NAME, schema, consistency_level="Eventually")

###########
6.ローカルのMilvusサーバー(lite)を起動する。
###########
default_server.start()
connections.connect(host='127.0.0.1'、
                  port=default_server.listen_port、
                  show_startup_banner=True)

###########
# 7.Milvusにデータを挿入します。
###########
# デフォルトを使用する代わりに、インデックスパラメータを変更する方法を示します。
index_params = {
    "index_type":"HNSW"、
    "metric_type":"COSINE"、
    「params":{'M':16, # int.4~64, num_layers
               "efConstruction":32}  # int.8~512, num_nearest_neighbors
               }
mc.create_index("embeddings", index_params)
insert_result = mc.insert(バッチ)

# 最後のエンティティが挿入された後、メモリに残っているセグメントの成長を止めるために flush を呼び出す。
mc.flush()


# 8.データベースに問い合わせる。
###########
# 検索やクエリを行う前に、データをメモリにロードする必要があります。
mc.load()

# データに関する質問のサンプルを定義します。
query = "私は医学博士ですが、どんな映画を見ればいいですか?"

# Milvusコレクションの作成に使用した埋め込みモデルを使用して、クエリを埋め込む。
query_embeddings = torch.tensor(retriever.encode([クエリ]))
# 埋め込みを単位長に正規化する。
query_embeddings = torch.nn.functional.normalize(query_embeddings, p=2, dim=1)

# 埋め込みをnp.float32のリストに変換。
query_embeddings = list(map(np.float32, query_embeddings))

# HNSWインデックスでベクトル検索を実行。
TOP_K = 3
search_params = { {検索パラメータ
    "M":16,
    "ef":32,
}
results = mc.search(
    data=query_embeddings、
    anns_field="embeddings"、
    param=search_params、
    output_fields=["movie_index", "chunk", "label"]、
    limit=TOP_K、
    consistency_level="Eventually"
    )

簡単な内定試験の後、ZillizのDeveloper Advocateの募集にオンラインフォームから応募しました。最終面接の後、Zillizチームはすぐにオファーをくれました。それで、迷うことなく承諾しました!

私には素晴らしい同僚がいます。なぜZillizに入社したかは、Yujian TangとFrank Liuのブログをご覧ください。私の上司であるChris Churiloは、私たち全員がこれほど効率よく働ける秘密の接着剤です。彼女は自分の知識と経験を活かして、私たち全員を輝かせてくれています。同僚のFilip Haltmayerは非常に忍耐強く、入社時にMilvusとZillizのあらゆることを説明してくれます。私たちのCEOであるCharles Xieは、2017年に、特に非構造化データのためのデータベースを構築するという独自のビジョンを持っていました。

次の記事

Milvusのエバンジェリズム活動を始めるにあたり、AI開発者コミュニティの皆さんと知り合えることを楽しみにしています!サンフランシスコで開催されるUnstructured DataMeetupを主催する予定です。いつも素晴らしいスピーカー、会場、共同主催者を探しています(ぜひ声をかけてください!)。私はもっとブログを書いたり、講演したりするつもりだ(ぜひ連絡を!)。あなたの非構造化データプロジェクトでオープンソースのMilvusを試したいのであれば、私がどのようにお手伝いできるかお知らせください!

私は、DataKind、Women in Data Science、Code for AmericaのSan Francisco Civil Hack nights(地元のSonoma Safe Agriculture組織に私を紹介し、interactive pesticides mapを作成した)など、いくつかのデータサイエンスのための組織に関わっています。私の新しいベクター・データベースの学びを、より大きな「善のためのデータサイエンス」コミュニティにも持ち込むので、ぜひ参加してほしい。

Updated on Jul 09, 2026