Files
2026-07-13 12:47:42 +08:00

247 lines
8.1 KiB
Python

# Copyright 2025-present the zvec project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import pytest
from zvec import (
CollectionSchema,
CollectionStats,
FieldSchema,
VectorSchema,
HnswIndexParam,
InvertIndexParam,
DataType,
IndexType,
MetricType,
)
# ----------------------------
# FieldSchema Test Case
# ----------------------------
class TestFieldSchema:
def test_default(self):
field = FieldSchema("field", data_type=DataType.FLOAT)
assert field.name == "field"
assert field.data_type == DataType.FLOAT
assert field.nullable is False
assert field.index_param is None
def test_custom(self):
field_1 = FieldSchema(
name="float",
data_type=DataType.FLOAT,
nullable=True,
index_param=InvertIndexParam(),
)
assert field_1.name == "float"
assert field_1.data_type == DataType.FLOAT
assert field_1.nullable is True
assert field_1.index_param.enable_range_optimization is False
field_2 = FieldSchema(
name="str",
data_type=DataType.STRING,
nullable=True,
index_param=InvertIndexParam(enable_range_optimization=True),
)
assert field_2.name == "str"
assert field_2.data_type == DataType.STRING
assert field_2.nullable is True
assert field_2.index_param.enable_range_optimization is True
def test_readonly(self):
field = FieldSchema(
name="float",
data_type=DataType.FLOAT,
nullable=True,
index_param=InvertIndexParam(),
)
import sys
if sys.version_info >= (3, 11):
match_pattern = r"(can't set attribute|has no setter|readonly attribute)"
else:
match_pattern = r"can't set attribute"
with pytest.raises(AttributeError, match=match_pattern):
field.index_param = InvertIndexParam(enable_range_optimization=True)
# ----------------------------
# VectorSchema Test Case
# ----------------------------
class TestVectorSchema:
def test_default(self):
field = VectorSchema("vector", data_type=DataType.VECTOR_FP32, dimension=128)
assert field.name == "vector"
assert field.data_type == DataType.VECTOR_FP32
assert field.dimension == 128
assert field.index_param is not None
assert field.index_param.type == IndexType.FLAT
assert field.index_param.metric_type == MetricType.IP
def test_custom(self):
field = VectorSchema(
name="vector",
data_type=DataType.VECTOR_INT8,
dimension=512,
index_param=HnswIndexParam(
metric_type=MetricType.COSINE, m=15, ef_construction=300
),
)
assert field.name == "vector"
assert field.data_type == DataType.VECTOR_INT8
assert field.index_param.metric_type == MetricType.COSINE
assert field.index_param.m == 15
assert field.index_param.ef_construction == 300
def test_readonly(self):
field = VectorSchema(
name="vector",
dimension=128,
data_type=DataType.VECTOR_INT8,
)
import sys
if sys.version_info >= (3, 11):
match_pattern = r"(can't set attribute|has no setter|readonly attribute)"
else:
match_pattern = r"can't set attribute"
with pytest.raises(AttributeError, match=match_pattern):
field.dimension = 4
# ----------------------------
# CollectionSchema Test Case
# ----------------------------
class TestCollectionSchema:
def test_collection_schema_with_single_field(self):
collection_schema = CollectionSchema(
name="test_collection",
fields=FieldSchema(
name="id",
data_type=DataType.INT64,
index_param=InvertIndexParam(),
nullable=False,
),
vectors=VectorSchema(
name="vector",
data_type=DataType.VECTOR_INT8,
dimension=128,
index_param=HnswIndexParam(),
),
)
assert collection_schema is not None
assert collection_schema.name == "test_collection"
assert len(collection_schema.fields) == 1
assert len(collection_schema.vectors) == 1
field = collection_schema.field("id")
assert field is not None
assert field.name == "id"
assert field.data_type == DataType.INT64
assert not field.nullable
assert field.index_param.type == IndexType.INVERT
assert not field.index_param.enable_range_optimization
vector = collection_schema.vector("vector")
assert vector is not None
assert vector.name == "vector"
assert vector.data_type == DataType.VECTOR_INT8
assert vector.dimension == 128
assert vector.index_param.type == IndexType.HNSW
assert vector.index_param.m == 50
assert vector.index_param.ef_construction == 500
assert vector.index_param.metric_type == MetricType.IP
def test_collection_schema_with_multi_fields(self):
collection_schema = CollectionSchema(
name="test_collection",
fields=[
FieldSchema(
"id",
DataType.INT64,
nullable=False,
index_param=InvertIndexParam(enable_range_optimization=True),
),
FieldSchema(
"name",
DataType.STRING,
nullable=False,
index_param=InvertIndexParam(),
),
FieldSchema(
"weight",
DataType.INT32,
nullable=True,
),
],
vectors=[
VectorSchema(
"dense",
DataType.VECTOR_FP32,
dimension=128,
index_param=HnswIndexParam(),
),
VectorSchema(
"sparse", DataType.SPARSE_VECTOR_FP32, index_param=HnswIndexParam()
),
],
)
assert collection_schema is not None
assert collection_schema.name == "test_collection"
assert len(collection_schema.fields) == 3
assert len(collection_schema.vectors) == 2
field_id = collection_schema.field("id")
assert field_id is not None
assert field_id.name == "id"
assert field_id.data_type == DataType.INT64
assert not field_id.nullable
assert field_id.index_param.type == IndexType.INVERT
dense = collection_schema.vector("dense")
assert dense is not None
assert dense.name == "dense"
assert dense.data_type == DataType.VECTOR_FP32
assert dense.dimension == 128
assert dense.index_param.type == IndexType.HNSW
sparse = collection_schema.vector("sparse")
assert sparse is not None
assert sparse.name == "sparse"
assert sparse.data_type == DataType.SPARSE_VECTOR_FP32
assert sparse.dimension == 0
assert sparse.index_param.type == IndexType.HNSW
assert str(collection_schema) is not None
# ----------------------------
# CollectionStats Test Case
# ----------------------------
class TestCollectionStats:
"""
The constructor of CollectionStats is not provided.
It can only be obtained through collection.stats()
"""
def test_collection_stats(self):
stats = CollectionStats()
assert stats is not None