以前の記事でWeaviateをk3sクラスタ上に構築したので、コレクションを作ってみましょう。RDBで言うところのテーブルみたいなものでしょうか。
どのようなコレクションを作るか
ER図で示すのが正しいのか分かりませんが、以下のような関係性を持たせたいと思います。
・TestAのエンティティにはtitleとsummaryがあります。
・TestAは複数のTestBエンティティを持ちます。
・TestBのエンティティにはchapterとtextがあります。
事前準備
$ pip install weaviate-client
コレクションの作成
import weaviate
import weaviate.classes.config as wc
weaviate_client = weaviate.connect_to_custom(
http_host="xxx.xxx.xxx.xxx", # URL only, no http prefix
http_port=30020,
http_secure=False, # Set to True if https
grpc_host="xxx.xxx.xxx.xxx",
grpc_port=30021, # Default is 50051, WCD uses 443
grpc_secure=False, # Edit as needed
)
weaviate_client.collections.create(
name='TestA',
properties=[wc.Property(name='title',data_type=wc.DataType.TEXT),
wc.Property(name='summary',data_type=wc.DataType.TEXT)],
references=[wc.ReferenceProperty(
name='children',
target_collection='TestB'
)
],
vectorizer_config=[wc.Configure.NamedVectors.text2vec_aws(
name='textdocument_vector',
service='bedrock',
model='cohere.embed-multilingual-v3',
region='us-west-2'
)
]
)
weaviate_client.close()
・WeaviateClient.collections.create()
でコレクションを作成します。
・引数properties
はリストを取ります。ここにwc.Property
型のインスタンスを並べます。インスタンス中のdata_type
の指定はwc.DataType
を使います。
・引数references
はリストを取ります。ここにwc.ReferenceProperty
型のインスタンスを並べます。インスタンス中のtarget_collection
には、リファレンス先のコレクションの名前を指定します。
・ベクトル化の肝であるベクトライザーをコレクションに対して指定しています。その指定には引数vectorizer_config
を使いますが、これにwc.Configure.NamedVectors
以下のメソッドを指定してあげます。ここにtext2vec_openai
やらtext2vec_cohere
やらありますが、私はBedrockでcohere embeddingを使うのでtext2vec_aws
を使いました。これらベクトライザーモジュール関連についての詳細は以下が詳しいと思います。英語ですが。
ところが、これを実行すると以下のように叱られてしまいました。
$ python 10C_define_class_TestA.py
(略)
raise UnexpectedStatusCodeError(error_msg, response=res)
weaviate.exceptions.UnexpectedStatusCodeError: Collection may not have been created properly.! Unexpected status code: 422, with response body: {'error': [{'message': "property 'children': invalid dataType: reference property to nonexistent class"}]}.
/home/yterashi/.pyenv/versions/3.12.4/lib/python3.12/site-packages/weaviate/warnings.py:303: ResourceWarning: Con004: The connection to Weaviate was not closed properly. This can lead to memory leaks.
Please make sure to close the connection using `client.close()`.
/home/yterashi/.pyenv/versions/3.12.4/lib/python3.12/asyncio/selector_events.py:879: ResourceWarning: unclosed transport <_SelectorSocketTransport fd=10 read=idle write=<idle, bufsize=0>>
reference property to nonexistent class
という一文からすると、リファレンス先のコレクションTestBがまだ存在しないのが問題のようです。存在しないコレクションへのリファレンスは作ることが出来ないみたいですね。
TestB側のコレクションを作るスクリプトは以下の通りです。
import weaviate
import weaviate.classes.config as wc
weaviate_client = weaviate.connect_to_custom(
http_host="xxx.xxx.xxx.xxx", # URL only, no http prefix
http_port=30020,
http_secure=False, # Set to True if https
grpc_host="xxx.xxx.xxx.xxx",
grpc_port=30021, # Default is 50051, WCD uses 443
grpc_secure=False, # Edit as needed
)
weaviate_client.collections.create(
name='TestB',
properties=[wc.Property(name='chapter',data_type=wc.DataType.INT),
wc.Property(name='text',data_type=wc.DataType.TEXT)],
references=[wc.ReferenceProperty(
name='parent',
target_collection='TestA'
)
],
vectorizer_config=[wc.Configure.NamedVectors.text2vec_aws(
name='textdocument_vector',
service='bedrock',
model='cohere.embed-multilingual-v3',
region='us-west-2'
)
]
)
weaviate_client.close()
やはりこちらも同じようなエラーが出てしまいました。そこで、TestA側を作るスクリプトを少し変え、一旦リファレンスを設定しない事にします。
import weaviate
import weaviate.classes.config as wc
weaviate_client = weaviate.connect_to_custom(
http_host="xxx.xxx.xxx.xxx", # URL only, no http prefix
http_port=30020,
http_secure=False, # Set to True if https
grpc_host="xxx.xxx.xxx.xxx",
grpc_port=30021, # Default is 50051, WCD uses 443
grpc_secure=False, # Edit as needed
)
weaviate_client.collections.create(
name='TestA',
properties=[wc.Property(name='title',data_type=wc.DataType.TEXT),
wc.Property(name='summary',data_type=wc.DataType.TEXT)],
vectorizer_config=[wc.Configure.NamedVectors.text2vec_aws(
name='textdocument_vector',
service='bedrock',
model='cohere.embed-multilingual-v3',
region='us-west-2'
)
]
)
weaviate_client.close()
今度はうまくいきました。その次に、10D_define_class_TestB.pyも(こちらは変更せず)うまくいきました。TestB側のリファレンス作成がうまくいったのはコレクションTestAが既にできていたからですね。
リファレンスを追加する
TestA側にTestBへのリファレンス追加がやり残しになってるので、これを追加しましょう。config.add_reference
というメソッドがあります。
import weaviate
from weaviate.classes.config import ReferenceProperty
weaviate_client = weaviate.connect_to_custom(
http_host="xxx.xxx.xxx.xxx", # URL only, no http prefix
http_port=30020,
http_secure=False, # Set to True if https
grpc_host="xxx.xxx.xxx.xxx",
grpc_port=30021, # Default is 50051, WCD uses 443
grpc_secure=False, # Edit as needed
)
TestA = weaviate_client.collections.get('TestA')
try:
TestA.config.add_reference(
ReferenceProperty(
name='children',
target_collection='TestB'
)
)
except Exception as e:
print(f"エラーが発生しました。{e}")
weaviate_client.close()
エラーも返らず、うまくいったようです。ここでcurlを使い、データベースのスキーマを得ることにしましょう。以下で、json形式でデータベース全体のスキーマを得ることが出来ます。なお、ポート番号は8080が標準ですが、私の場合k3sのnodeportの都合上30020となっています。
$ curl http://xxx.xxx.xxx.xxx:30020/v1/schema > schema.json
結果は以下の通りです。
schema.json
{
"classes": [
{
"class": "TestA",
"invertedIndexConfig": {
"bm25": {
"b": 0.75,
"k1": 1.2
},
"cleanupIntervalSeconds": 60,
"stopwords": {
"additions": null,
"preset": "en",
"removals": null
}
},
"multiTenancyConfig": {
"autoTenantActivation": false,
"autoTenantCreation": false,
"enabled": false
},
"properties": [
{
"dataType": [
"text"
],
"indexFilterable": true,
"indexSearchable": true,
"moduleConfig": {
"text2vec-aws": {
"skip": false,
"vectorizePropertyName": false
}
},
"name": "title",
"tokenization": "word"
},
{
"dataType": [
"text"
],
"indexFilterable": true,
"indexSearchable": true,
"moduleConfig": {
"text2vec-aws": {
"skip": false,
"vectorizePropertyName": false
}
},
"name": "summary",
"tokenization": "word"
},
{
"dataType": [
"TestB"
],
"indexFilterable": true,
"indexSearchable": false,
"moduleConfig": {
"text2vec-aws": {
"skip": false,
"vectorizePropertyName": false
}
},
"name": "children"
}
],
"replicationConfig": {
"factor": 1
},
"shardingConfig": {
"actualCount": 1,
"actualVirtualCount": 128,
"desiredCount": 1,
"desiredVirtualCount": 128,
"function": "murmur3",
"key": "_id",
"strategy": "hash",
"virtualPerPhysical": 128
},
"vectorConfig": {
"textdocument_vector": {
"vectorIndexConfig": {
"bq": {
"enabled": false
},
"cleanupIntervalSeconds": 300,
"distance": "cosine",
"dynamicEfFactor": 8,
"dynamicEfMax": 500,
"dynamicEfMin": 100,
"ef": -1,
"efConstruction": 128,
"flatSearchCutoff": 40000,
"maxConnections": 64,
"pq": {
"bitCompression": false,
"centroids": 256,
"enabled": false,
"encoder": {
"distribution": "log-normal",
"type": "kmeans"
},
"segments": 0,
"trainingLimit": 100000
},
"skip": false,
"vectorCacheMaxObjects": 1000000000000
},
"vectorIndexType": "hnsw",
"vectorizer": {
"text2vec-aws": {
"model": "cohere.embed-multilingual-v3",
"region": "us-west-2",
"service": "bedrock",
"vectorizeClassName": true
}
}
}
}
},
{
"class": "TestB",
"invertedIndexConfig": {
"bm25": {
"b": 0.75,
"k1": 1.2
},
"cleanupIntervalSeconds": 60,
"stopwords": {
"additions": null,
"preset": "en",
"removals": null
}
},
"multiTenancyConfig": {
"autoTenantActivation": false,
"autoTenantCreation": false,
"enabled": false
},
"properties": [
{
"dataType": [
"int"
],
"indexFilterable": true,
"indexSearchable": false,
"moduleConfig": {
"text2vec-aws": {
"skip": false,
"vectorizePropertyName": false
}
},
"name": "chapter"
},
{
"dataType": [
"text"
],
"indexFilterable": true,
"indexSearchable": true,
"moduleConfig": {
"text2vec-aws": {
"skip": false,
"vectorizePropertyName": false
}
},
"name": "text",
"tokenization": "word"
},
{
"dataType": [
"TestA"
],
"indexFilterable": true,
"indexSearchable": false,
"moduleConfig": {
"text2vec-aws": {
"skip": false,
"vectorizePropertyName": false
}
},
"name": "parent"
}
],
"replicationConfig": {
"factor": 1
},
"shardingConfig": {
"actualCount": 1,
"actualVirtualCount": 128,
"desiredCount": 1,
"desiredVirtualCount": 128,
"function": "murmur3",
"key": "_id",
"strategy": "hash",
"virtualPerPhysical": 128
},
"vectorConfig": {
"textdocument_vector": {
"vectorIndexConfig": {
"bq": {
"enabled": false
},
"cleanupIntervalSeconds": 300,
"distance": "cosine",
"dynamicEfFactor": 8,
"dynamicEfMax": 500,
"dynamicEfMin": 100,
"ef": -1,
"efConstruction": 128,
"flatSearchCutoff": 40000,
"maxConnections": 64,
"pq": {
"bitCompression": false,
"centroids": 256,
"enabled": false,
"encoder": {
"distribution": "log-normal",
"type": "kmeans"
},
"segments": 0,
"trainingLimit": 100000
},
"skip": false,
"vectorCacheMaxObjects": 1000000000000
},
"vectorIndexType": "hnsw",
"vectorizer": {
"text2vec-aws": {
"model": "cohere.embed-multilingual-v3",
"region": "us-west-2",
"service": "bedrock",
"vectorizeClassName": true
}
}
}
}
}
]
}
感想
・ベクトルDBのことはよく知らないのですが、WeaviateはベクトルDBとグラフDBのハイブリッドのようなものなんですね(グラフDBのこともよく知りませんけど)
・Weaviateを操作するGUIクライアントのようなものが無くて、Pythonスクリプトを走らせるとかしないと操作できないですね、今のところ。コマンドラインで動かすより、jupyter notebookのような環境で操作する方が楽かもしれないです(と気付いた)。
・ネット上にはPython ClientのV3とV4の資料が混在していて苦労します。
次の記事は
オブジェクトの挿入、取得、全削除をやってみます。