ベクターデータベースをJSON(またはリレーショナル)データストアとして使用する

TL;DR:ベクターデータベースは、JSONのような "伝統的な "データフォーマットのCRUDをサポートしている。もしあなたが一人の開発者や小さなチームで、多くの異なるデータインフラを管理したくないのであれば、MilvusやZilliz Cloud(マネージドMilvus)を唯一のデータストアとして使用し、スケールするにつれてベクターレスコレクションを異なるデータベースに簡単に移行することができる。
ChatGPTやその他の自己回帰言語モデルの人気に後押しされ、ベクトル検索は昨年爆発的な人気を博しました。その結果、Atlas Vector SearchのようなMongoDBのようなNoSQLデータベースプロバイダから、pgvectorのようなPostgresのような伝統的なリレーショナルデータベースに至るまで、多くの企業や組織がベクトル検索のバンドワゴンに乗るのを目にしてきました。これらのベクトル検索プラグインの周りで私が耳にする一般的なメッセージは、ほとんど同じで、次のようなものです:開発者は、ベクトルに加えてテーブル/JSONを保存できるので、複数のインフラストラクチャを管理する必要がない、私たちにこだわるべきです!
この種の文言は、明らかに洗練されていないマーケティング・チームによって作られたもので、いつも私をうんざりさせる。ベクトル検索の背後にあるテクノロジーは、リレーショナルデータベースやNoSQLデータベースのストレージやクエリ戦略とは大きく異なるだけでなく、ベクトルデータベースがリレーション、JSONドキュメント、その他の構造化データソースを格納できることは、今ではかなりよく知られている。しかし、ベクトル・データベースがリレーションシップやJSONドキュメント、その他の構造化されたデータ・ソースを格納できることは、今ではかなりよく知られている。最初のポイントは、データベース管理システムに関する深い予備知識がないと簡潔に説明するのは難しいが、2番目のポイントは、いくつかの短いサンプル・コード・スニペットを通して示すのはかなり簡単だ。それがこのブログ記事の目的だ。
セットアップ
Milvusはリレーショナルデータベースのテーブルに似たコレクションという単位でデータを保存します。各コレクションは独自のスキーマを持つことができ、スキーマは固定次元のベクトルフィールドを持つ。ベクトルデータではなく、JSONドキュメントを格納するコレクションを作ってみよう。この点をよりよく説明するために、collections.connectを呼び出すなど、前と後のステップの一部を省いている:
python from pymilvus import Collection, CollectionSchema, DataType, FieldSchema
fields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True, max_length=100)、 フィールドスキーマ(name="_unused", dtype=DataType.FLOAT_VECTOR, dim=1) ]
schema = CollectionSchema(fields, "NoSQL data", enable_dynamic_field=True) collection = Collection("json_data", schema) collection.load()
ここでは、このコレクションにMilvusの[動的スキーマ](https://milvus.io/docs/dynamic_schema.md)機能を使用するように指定し、コレクションが各行に関連する "追加 "データとしてJSONペイロードを受け入れるようにしています。
これ以上のことを期待していないことを願っています。
## CRUD オペレーション
上記で作成したコレクションは、他のデータベースと同じように操作することができます。例として、govtrackから現在の米国上院議員のリスト(JSON形式)をダウンロードしてみましょう:
python
import requests
r = requests.get("https://www.govtrack.us/api/v2/role?current=true&role_type=senator")
data = r.json()["オブジェクト"].
len(data)
100
ほんの少しデータを操作するだけで、これらのドキュメントを直接Milvusに格納することができる:
``python rows = [{"_unused": [0]}|d for d in data].| d for d in data]. collection.insert(rows)
(insert count:100, delete count:0, upsert count:0, ...
ここから、そのデータに対して直接クエリーを実行することができる:
python
collection.query(
expr="政党名 'Dem%'"、
limit=1、
output_fields=["person"].
)
[{'person':{'bioguideid': 'C000127'、
'birthday': '1958-10-13'、
'cspanid': 26137、
'fediverse_webfinger':なし、
'firstname': 'Maria'、
'gender': 'female'、
'gender_label': 'Female'、
'lastname': 'Cantwell'、
'link': 'https://www.govtrack.us/congress/members/maria_cantwell/300018'、
'middlename': ''、
'name': 'Sen. Maria Cantwell [D-WA]'、
'namemod': ''、
'nickname': ''、
'osid': 'N00007836'、
'pvsid':なし、
'sortname': 'Cantwell, Maria (Sen.) [D-WA]'、
'twitterid': 'SenatorCantwell'、
'youtubeid': 'SenatorCantwell'}、
'id':447376465724036249}]
ベクターフィールドを指定せずに、付随するJSONペイロードのpartyフィールドが接頭辞として "Dem"(民主党)を持つ最初の結果に対してデータベースを照会しました。
このステップは、Milvusで構造化データ検索を実行できることを示すものですが、特に有用なクエリではありません。私の出身地であるオレゴン州の上院議員をすべて検索してみよう:
python collection.query( expr="state in ['OR']"、 limit=10、 output_fields=["person"]. )
[{'person':{'bioguideid': 'M001176'、
'birthday': '1956-10-24'、
'cspanid':1029842,
'fediverse_webfinger':なし、
'firstname': 'Jeff'、
'gender': '男性'、
'gender_label': '男性'、
'lastname': 'Merkley'、
'link': 'https://www.govtrack.us/congress/members/jeff_merkley/412325'、
'middlename': ''、
'name': 'Sen. Jeff Merkley [D-OR]'、
'namemod': ''、
'nickname': ''、
'osid': 'N00029303'、
'pvsid':なし、
'sortname': 'Merkley, Jeff (Sen.) [D-OR]'、
'twitterid': 'SenJeffMerkley'、
'youtubeid': 'SenatorJeffMerkley'}、
'id':447376465724036286},
{'person':{'bioguideid': 'W000779'、
'birthday': '1949-05-03'、
'cspanid':1962,
'fediverse_webfinger':なし、
'firstname': 'Ron'、
'gender': '男性'、
'gender_label': '男性'、
'lastname': 'Wyden'、
'link': 'https://www.govtrack.us/congress/members/ron_wyden/300100'、
'middlename': ''、
'name': 'Sen. Ron Wyden [D-OR]'、
'namemod': ''、
'nickname': ''、
'osid': 'N00007724'、
'pvsid':なし、
'sortname': 'Wyden, Ron (Sen.) [D-OR]'、
'twitterid': 'RonWyden'、
'youtubeid': 'senronwyden'}、
'id':447376465724036331}]
limit=10`を指定したにもかかわらず、2つのドキュメントしか返されませんでした(各州には上院議員が2人しかいないため)。さらにクエリを絞り込んで、上級議員だけを取得してみましょう:
python
collection.query(
expr="state in ['OR'] and senator_rank in ['senior']"、
limit=10、
output_fields=["person"])
)
[{'person':{'bioguideid': 'W000779'、
'birthday': '1949-05-03'、
'cspanid':1962,
'fediverse_webfinger':なし、
'firstname': 'Ron'、
'gender': '男性'、
'gender_label': '男性'、
'lastname': 'Wyden'、
'link': 'https://www.govtrack.us/congress/members/ron_wyden/300100'、
'middlename': ''、
'name': 'Sen. Ron Wyden [D-OR]'、
'namemod': ''、
'nickname': ''、
'osid': 'N00007724'、
'pvsid':なし、
'sortname': 'Wyden, Ron (Sen.) [D-OR]'、
'twitterid': 'RonWyden'、
'youtubeid': 'senronwyden'}、
'id':447376465724036331}]
Ron Wyden上院議員のプロフィールをもう少し詳しく更新したいかもしれません。そのためには、output_fields=["*"]でドキュメント全体を取得し、出来上がったドキュメントを更新して、古い主キーなしでデータベースに挿入し直せば簡単です:
python expr = "state in ['OR'] and senator_rank in ['senior']" res = collection.query( expr=expr、 limit=10、 output_fields=["*"]. )
python
res[0].update({
"elected_in":"1996",
"college":「スタンフォード大学
"college_major":"政治学"
})
del res[0]["id"].
(insert count:1, delete count:0, upsert count:0, ...
``python collection.delete(expr) コレクション.insert(res)
これが期待通りに動くか見てみよう。
python
collection.query(
expr=expr、
limit=10、
output_fields=["elected_in", "college", "college_major"].
)
[{'elected_in': '1996'、
'college': 'Stanford University'、
'college_major': 'Political Science'、
'id':447376465724036353}]
データは確かに私たちが行った更新と一致しています。
スクリプト全文
余計なクエリを省いて便宜上、スクリプト全体を前から後ろまで示します。milvus-lite`の代わりにZilliz Cloud free tierを使用しています:
python from milvus import default_server from pymilvus import connections from pymilvus import Collection, CollectionSchema, DataType, FieldSchema インポートリクエスト
もし milvus-lite を使用しているのであれば、これをアンコメントする。
#default_server.start() #connections.connect(host="127.0.0.1", port=default_server.listen_port)
Zillizクラウドを使用している場合はコメントを外します。
connections.connect( uri=os.environ["ZILLIZ_URI"]、 token=os.environ["ZILLIZ_TOKEN"]を指定します。 )
新しいコレクションのスキーマを作成します。Milvusの動的な
スキーマ機能を有効にします.
各行には
fields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True, max_length=100)、 フィールドスキーマ(name="_unused", dtype=DataType.FLOAT_VECTOR, dim=1) ] schema = CollectionSchema(fields, "Milvus as a JSON datastore", enable_dynamic_field=True)
では、コレクションを作成しましょう。
collection = Collection("json_data", schema) index_params = { "index_type": インデックスタイプ "index_type":"AUTOINDEX"、 "metric_type":"L2", 「params":{} } コレクション.create_index( フィールド名="_unused"、 index_params=index_params ) コレクションをロードする
米国の上院議員のJSONデータを、新しく形成されたコレクションに挿入する。
r = requests.get("https://www.govtrack.us/api/v2/role?current=true&role_type=senator") data = r.json()["オブジェクト"]. rows = [{"_unused": [0]}|d for d in data].| d for d in data]. collection.insert(行)
データベース内の最初のDemocratを取り出す
top_k = 1 collection.query( expr="state in ['OR'] and senator_rank in ['senior']"、 limit=top_k、 output_fields=["person"]) )
[{'person':{'bioguideid': 'W000779'、
'birthday': '1949-05-03'、
'cspanid':1962,
'fediverse_webfinger':なし、
'firstname': 'Ron'、
'gender': '男性'、
'gender_label': '男性'、
'lastname': 'Wyden'、
'link': 'https://www.govtrack.us/congress/members/ron_wyden/300100'、
'middlename': ''、
'name': 'Sen. Ron Wyden [D-OR]'、
'namemod': ''、
'nickname': ''、
'osid': 'N00007724'、
'pvsid':なし、
'sortname': 'Wyden, Ron (Sen.) [D-OR]'、
'twitterid': 'RonWyden'、
'youtubeid': 'senronwyden'}、
'id':447376465724036331}]
ぜひお試しください!
## `pymongo` -> `milvusmongo`
pymongo`の最も基本的なCRUD機能を実装した `milvusmongo` という小さなPythonパッケージを作りました。このパッケージはMongoDBではなくMilvusを使っています。pymongo` と同様に、 `milvusmongo` は辞書と属性の両方のスタイルをサポートしており、CRUD 呼び出しに必要なロジック (`insert_one`、`update_one`、`delete_one` など) を抽象化している。pip install milvusmongo` でインストールできる:
シェル
pip install milvus
pip install milvusmongo
これが完了したら、組み込みのMilvusインスタンスを起動し、milvusmongoと組み合わせてJSONデータに対するクエリを実行することができる。例えば
python from milvus import default_server default_server.start()
python
from milvusmongo import MongoClient
client = MongoClient("127.0.0.1", 19530)
client.insert_one(my_document)
このライブラリは、Milvus のデータストアとしての柔軟性を示すためのものであり、大規模な本番環境で使うべきものではないことに注意してください。
おわりに
Milvusは、NoSQLデータベースや語彙型テキスト検索エンジンに取って代わるためのものではありません。より重要なことは、ベクター検索をテクノロジーとして普及させることです。
しかし、だからといって他のタイプのデータをサポートしないということではありません。一人の開発者や小規模なスタートアップ企業であれば、Milvusを唯一のデータストアとして自由に使用することができます。インフラストラクチャの利用は、成長に応じていつでも最適化することができます。Milvusはクラス最高のベクトル検索機能を提供し、他のデータベースは他の形式のデータを保存し、インデックスを作成し、検索します。アプリケーションがより複雑なワークロード(結合や集計など)を必要とし始めたら、別のデータストアの使用を検討することになるでしょう。
読み続けて

Zilliz Cloud Just Landed in Claude Code
Zilliz Cloud Just Landed in Claude Code - Build AI Apps without Leaving Your Terminal

The Great AI Agent Protocol Race: Function Calling vs. MCP vs. A2A
Compare Function Calling, MCP, and A2A protocols for AI agents. Learn which standard best fits your development needs and future-proof your applications.
Milvus/Zilliz + Surveillance: How Vector Databases Transform Multi-Camera Tracking
See how Milvus vector database enhances multi-camera tracking with similarity-based matching for better surveillance in retail, warehouses and transport hubs.
