Core/ORM select(), DDL (CREATE TABLE/CREATE INDEX), reflection, and Alembic migrations all go through the standard SQLAlchemy surface — vector search is just .order_by(column.cosine_distance(q)), spelled exactly like pgvector's own comparator.
Installation
pip install milvusql-sqlalchemy
Quick start
from sqlalchemy import create_engine, select
from milvusql_sqlalchemy.types import VECTOR
engine = create_engine("milvusql:///items.db") # Milvus Lite, or a real server's URI
with engine.connect() as conn: # items: Table with an `embedding` VECTOR column
rows = conn.execute(
select(items.c.id, items.c.category)
.order_by(items.c.embedding.l2_distance([0.1] * 768))
.limit(5)
).all()
The same engine, asyncio-native, via create_async_engine and the milvusql+aio driver:
from sqlalchemy.ext.asyncio import create_async_engine
engine = create_async_engine("milvusql+aio:///items.db")
async with engine.connect() as conn:
rows = (
await conn.execute(
select(items.c.id).order_by(items.c.embedding.cosine_distance(q)).limit(5)
)
).all()
Connection URLs
milvusql:///items.db # Milvus Lite -- relative file path
milvusql:////abs/path/items.db # Milvus Lite -- absolute file path
milvusql://user:password@host:19530/db_name # a real server
milvusql://user:password@host:19530/db_name?secure=1 # TLS (https)
milvusql+aio://... # same URL forms, async engine
API
VECTOR(dim) / SPARSEVEC
from sqlalchemy import Column, Table
from milvusql_sqlalchemy.types import VECTOR, SPARSEVEC
items = Table(
"items", metadata,
Column("id", BigInteger, primary_key=True, autoincrement=True),
Column("embedding", VECTOR(768)),
Column("sparse", SPARSEVEC),
milvusql_shards=1,
milvusql_consistency_level="Strong",
)
| Comparator method | MilvusQL operator | Available on |
|---|---|---|
.l2_distance(other) |
<-> |
VECTOR |
.cosine_distance(other) |
<=> |
VECTOR |
.l1_distance(other) |
<+> |
VECTOR |
.max_inner_product(other) |
<#> |
VECTOR, SPARSEVEC |
Bind values pass through as plain list[float] — never stringified into SQL text.
hybrid_search()
Weighted multi-vector search, rendered where MilvusQL's HYBRID SEARCH ... RERANK ... sits — in place of ORDER BY:
from milvusql_sqlalchemy.hybrid import hybrid_search, weighted
select(items.c.id).order_by(
hybrid_search(
weighted(items.c.embedding.cosine_distance(dense_q), 0.7),
weighted(items.c.sparse.max_inner_product(sparse_q), 0.3),
rerank="RRF", k=60,
)
).limit(10)
DDL options
Dialect-specific Table/Index arguments, the same mechanism as mysql_engine=...:
Table(
"items", metadata, ...,
milvusql_shards=2,
milvusql_consistency_level="Bounded",
milvusql_partition_key="category",
)
Index(
"idx_embedding", items.c.embedding,
milvusql_using="HNSW",
milvusql_with={"metric_type": "COSINE", "M": 16, "ef_construction": 200},
)
Consistency level
A statement's own CONSISTENCY LEVEL clause always wins; otherwise the engine falls back to the connection's isolation level — one of Milvus's own levels (Strong, Bounded, Eventually, Session, Customized), set the normal SQLAlchemy way:
conn = engine.connect().execution_options(isolation_level="Bounded")
Alembic
Importing this dialect registers milvusql's DefaultImpl with Alembic automatically — alembic upgrade/downgrade work against a milvusql://... URL with no extra setup. Non-transactional (transactional_ddl = False): Milvus has no multi-statement rollback, so a failed migration can't be undone by Alembic — write forward-only migrations.
Examples
| Example | Shows |
|---|---|
examples/fastapi_image_search |
A FastAPI service for image search: insert images with a caption, search by query image or free text (cross-modal, via CLIP), delete |
examples/pydantic_ai_agent |
A pydantic-ai shopping-assistant agent whose only access to the catalog is through typed tools backed by a real vector search |
Development
From the workspace root (requires Python 3.12+, uv, task):
task install
task sqlalchemy:lint
task sqlalchemy:test # integration tests need Docker (testcontainers)
License
MIT
Release files for milvusql-sqlalchemy 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| milvusql_sqlalchemy-0.1.4.tar.gz | 16.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| milvusql_sqlalchemy-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.3 kB
Release files / milvusql_sqlalchemy-0.1.4.tar.gz
| Download URL | milvusql_sqlalchemy-0.1.4.tar.gz |
|---|---|
| Size | 16.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
906ebc43deb2b27be3c788387e1448f1c1be885028bbbe8b026d3d0e1b3c2741
|
|
BLAKE2b-256 checksum How to use checksums |
e73defeeb619539dfa7633a4e2afdf72268b977d6a5d13ad8cf11916e44f73dd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / milvusql_sqlalchemy-0.1.4-py3-none-any.whl
| Download URL | milvusql_sqlalchemy-0.1.4-py3-none-any.whl |
|---|---|
| Size | 20.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6462c64e6207abddfb84e5eafb6c7c606b80a47c7f5a554a875f96fcf980a0c1
|
|
BLAKE2b-256 checksum How to use checksums |
e6c91a056e2851666dfb51c02969c3fd4e31f76e22c771c50f74927a8fffebde
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|