Skip to main content

openai-simple-vectorstore

可扩展的多向量数据库接入库,内置 redis-search、milvus、milvus-lite、 pgvector、elasticsearch、sqlite-vec 与 qdrant 等后端,并提供统一的 embeddings / rerank 二阶段召回、插入、删除、刷新等管理接口。

  • redis-search 后端与 openai-redis-vectorstore 行为兼容(相同的 uid 规则与 relevance score,生成的 key 布局一致),但索引 PREFIX 由 上游的 index_name 改为 index_name + ":",以隔离同名前缀的其它索引(见版本记录)。
  • 通过工厂 + 注册表机制可低成本扩展其它向量数据库后端。

安装

作为业务方使用时,从 PyPI 安装本库并选择所需后端:

# 仅核心依赖(不含任何后端驱动,需配合下面的某个后端 extra 使用)
pip3 install openai-simple-vectorstore

# redis-search 后端(也是 create_vector_store() 的默认后端)
pip3 install "openai-simple-vectorstore[redis]"

# 仅 milvus 后端(依赖 pymilvus)
pip3 install "openai-simple-vectorstore[milvus]"

# 仅 milvus-lite 后端(嵌入式 milvus,无需单独部署,适合本地开发/测试)
pip3 install "openai-simple-vectorstore[milvus-lite]"

# 仅 pgvector 后端(依赖 psycopg2-binary)
pip3 install "openai-simple-vectorstore[pgvector]"

# 仅 elasticsearch 后端
pip3 install "openai-simple-vectorstore[elasticsearch]"

# 仅 sqlite-vec 后端(嵌入式 SQLite,无需单独部署)
pip3 install "openai-simple-vectorstore[sqlite-vec]"

# 仅 qdrant 后端(依赖 qdrant-client)
pip3 install "openai-simple-vectorstore[qdrant]"

# 全部后端
pip3 install "openai-simple-vectorstore[all]"

在仓库源码目录内本地开发时使用 pip3 install -e ".[all]";离线安装本库自身依赖时, 先准备本地 wheel 目录,再执行 pip3 install --no-index --find-links <wheel 目录> -r requirements.txt。

快速开始

选择 redis-search 后端(默认)

需先安装 redis 后端:pip3 install "openai-simple-vectorstore[redis]"。

from openai_simple_vectorstore import create_vector_store

vs = create_vector_store()  # 默认后端由 OPENAI_SIMPLE_VECTORSTORE_VECTOR_DB 决定

# 插入
uid = vs.insert("今天天气很好", kb_id="kb1", doc_id="doc1", page_id="p1")

# 二阶段召回(向量检索 + rerank 重排)
docs = vs.similarity_search_and_rerank(
    query="今天天气怎么样",
    index_name="default",
    k=3,
)
for doc in docs:
    print(doc.vs_page_content, doc.vs_embeddings_score, doc.vs_rerank_score)

# 删除 / 刷新
vs.delete(uid)
vs.flush("default")

选择 milvus 后端

from openai_simple_vectorstore import create_vector_store

vs = create_vector_store(  # 或环境变量 OPENAI_SIMPLE_VECTORSTORE_VECTOR_DB=milvus
    vector_db="milvus"
)
vs.insert("..." , kb_id="kb1", doc_id="doc1", page_id="p1")
docs = vs.similarity_search_and_rerank(query="...", index_name="default", k=3)

选择 milvus-lite 后端(嵌入式,本地开发/测试)

milvus-lite 与 milvus 使用相同的 MilvusClient API,仅连接方式不同:milvus 通过 http://host:19530 连接服务端,milvus-lite 通过本地文件路径启动进程内嵌入式数据库, 无需部署 milvus 服务。

from openai_simple_vectorstore import create_vector_store

vs = create_vector_store(
    vector_db="milvus-lite",  # 或环境变量 OPENAI_SIMPLE_VECTORSTORE_VECTOR_DB=milvus-lite
    milvus_lite_uri="./milvus_lite.db",  # 默认 OPENAI_SIMPLE_VECTORSTORE_MILVUS_LITE_URI
)
vs.insert("..." , kb_id="kb1", doc_id="doc1", page_id="p1")
docs = vs.similarity_search_and_rerank(query="...", index_name="default", k=3)

选择 sqlite-vec 后端(嵌入式,本地开发/测试)

sqlite-vec 是 SQLite 的向量搜索扩展,所有数据存在本地文件中,无需单独部署服务。 注意:需要 sqlite3 支持 loadable-extension(多数发行版 CPython 均支持)。

from openai_simple_vectorstore import create_vector_store

vs = create_vector_store(
    vector_db="sqlite-vec",  # 或环境变量 OPENAI_SIMPLE_VECTORSTORE_VECTOR_DB=sqlite-vec
    sqlite_vec_uri="./sqlite_vec.db",  # 默认 OPENAI_SIMPLE_VECTORSTORE_SQLITE_VEC_URI
)
vs.insert("..." , kb_id="kb1", doc_id="doc1", page_id="p1")
docs = vs.similarity_search_and_rerank(query="...", index_name="default", k=3)

选择 pgvector 后端(PostgreSQL 扩展)

需要 PostgreSQL 已安装 pgvector 扩展(程序启动时会尝试 CREATE EXTENSION IF NOT EXISTS vector):

from openai_simple_vectorstore import create_vector_store

vs = create_vector_store(
    vector_db="pgvector",  # 或环境变量 OPENAI_SIMPLE_VECTORSTORE_VECTOR_DB=pgvector
    pgvector_url="postgresql://user:pass@localhost:5432/postgres",  # 默认 OPENAI_SIMPLE_VECTORSTORE_PGVECTOR_URL
)
vs.insert("..." , kb_id="kb1", doc_id="doc1", page_id="p1")
docs = vs.similarity_search_and_rerank(query="...", index_name="default", k=3)

选择 elasticsearch 后端

需要 Elasticsearch 8.x(dense_vector + HNSW):

from openai_simple_vectorstore import create_vector_store

vs = create_vector_store(
    vector_db="elasticsearch",  # 或环境变量 OPENAI_SIMPLE_VECTORSTORE_VECTOR_DB=elasticsearch
    es_url="http://localhost:9200",
)
vs.insert("..." , kb_id="kb1", doc_id="doc1", page_id="p1")
docs = vs.similarity_search_and_rerank(query="...", index_name="default", k=3)

选择 qdrant 后端

需要部署 Qdrant 服务(或使用 Qdrant Cloud)。使用原生 payload 过滤,无需像 milvus / sqlite-vec 那样对候选集做放大:

from openai_simple_vectorstore import create_vector_store

vs = create_vector_store(
    vector_db="qdrant",  # 或环境变量 OPENAI_SIMPLE_VECTORSTORE_VECTOR_DB=qdrant
    qdrant_url="http://localhost:6333",  # 默认 OPENAI_SIMPLE_VECTORSTORE_QDRANT_URL
    qdrant_api_key=None,                 # 默认 OPENAI_SIMPLE_VECTORSTORE_QDRANT_API_KEY
    # qdrant_prefer_grpc=True,            # 默认 OPENAI_SIMPLE_VECTORSTORE_QDRANT_PREFER_GRPC
    # qdrant_timeout=60,                  # 客户端请求超时(秒),默认 OPENAI_SIMPLE_VECTORSTORE_QDRANT_TIMEOUT
    # qdrant_on_disk=False,               # 总开关,默认 OPENAI_SIMPLE_VECTORSTORE_QDRANT_ON_DISK(False)
    # qdrant_vector_on_disk=True,         # 向量是否落盘,覆盖总开关
    # qdrant_hnsw_on_disk=True,           # HNSW 图是否落盘,覆盖总开关
    # qdrant_payload_on_disk=True,        # payload 索引是否落盘,覆盖总开关
)
vs.insert("..." , kb_id="kb1", doc_id="doc1", page_id="p1")
docs = vs.similarity_search_and_rerank(query="...", index_name="default", k=3)

qdrant 的向量、HNSW 图、payload 索引三部分是否落盘可分别配置: qdrant_vector_on_disk / qdrant_hnsw_on_disk / qdrant_payload_on_disk (对应环境变量 OPENAI_SIMPLE_VECTORSTORE_QDRANT_{VECTOR,HNSW,PAYLOAD}_ON_DISK)。 三者默认均为 False,即默认全部驻留内存,以获得最低检索延迟。qdrant_on_disk 是给三者兜底的总开关(默认 False):未单独设置的项会继承它,单独设置项优先。 落盘(mmap)可避免大图常驻内存,但检索时的随机读会变慢,建议搭配 NVMe SSD。

本地快速启动(podman):

podman run -d --name qdrant -p 6333:6333 -p 6334:6334 docker.io/qdrant/qdrant:latest

直接实例化(不依赖全局配置)

from openai_simple_vectorstore import RedisVectorStore
from openai_simple_vectorstore.base import Connection
from openai_simple_vectorstore.utils import YamlSerializer

vs = RedisVectorStore(
    redis_stack_url="redis://localhost:6379/0",
    embeddings_llm=Connection(base_url="http://localhost/v1", api_key="sk-xxx"),
    rerank_llm=Connection(base_url="http://localhost/v1", api_key="sk-xxx"),
    embeddings_model="bge-m3",
    rerank_model="bge-reranker-v2-m3",
    metadata_serializer=YamlSerializer(),
)
  • metadata_serializer 决定业务自定义元数据(metadata / vs_metadata)持久化时的序列化方式, 默认 YamlSerializer;也可传入 JsonSerializer(均定义于 openai_simple_vectorstore.utils)。

使用说明

VectorStore 对业务屏蔽后端差异,统一提供写入 / 检索 / 读取 / 删除 / 索引管理接口。 下面所有示例中的 vs 均指已创建的 VectorStore 实例。

写入

# 单条:返回 uid(格式 <index_name>:<page_id>)
uid = vs.insert(
    "今天天气很好",
    page_id="p1",          # 缺省自动生成 uuid4
    kb_id="kb1",           # 缺省 "default"
    doc_id="doc1",         # 缺省 "default"
    category="news",       # 缺省 "default"
    index_name="default",
    metadata={"author": "alice", "score": 9.5},  # 业务自定义元数据,随记录持久化
)

# 批量:返回 uid 列表;texts / metadatas / page_ids 长度必须一致
uids = vs.insert_many(
    ["文本一", "文本二"],
    metadatas=[{"author": "alice"}, {"author": "bob"}],
    page_ids=["p1", "p2"],
    kb_id="kb1",
    index_name="default",
)

同一 page_id 重复写入是覆盖(upsert 语义),不会产生重复记录;调用方传入的 metadata / metadatas 不会被就地修改。

检索

# 仅向量检索:相关度 = 1 - distance,返回按相关度降序的 [Document, ...]
docs = vs.similarity_search_with_relevance_scores(
    "今天天气怎么样",
    index_name="default",
    k=5,
    kb_id="kb1",                       # 快捷过滤,等价 filters=[Filter("vs_kb_id", ["kb1"])]
    categories=["news", "tech"],       # 多值:命中其一即可
    embeddings_score_threshold=0.3,    # 低于阈值的结果直接丢弃(None 表示不过滤)
)

# 二阶段召回:先向量检索取 k*scale 条候选,再经 rerank 重排取前 k
docs = vs.similarity_search_and_rerank(
    "今天天气怎么样",
    index_name="default",
    k=3,
    scale=3,                           # 候选数 = k * scale,默认 2
    kb_ids=["kb1", "kb2"],
    rerank_score_threshold=0.5,
)

# 多索引联合检索(跨索引去重、统一排序)
docs = vs.similarity_search_with_relevance_scores(
    "查询", index_names=["idx_a", "idx_b"], k=10,
)

读取 / 删除 / 清空

item = vs.get_item(uid)      # 返回元数据 dict(含 embedding 字节);不存在返回 {}
count = vs.delete(uid)       # 返回实际删除条数
count = vs.delete_many(uids) # 按 index_name 自动分组批量删除
vs.flush("default")          # 清空该索引数据(破坏性;是否删除底层索引/表随后端而异)

flush 一律清空该索引下的数据(破坏性)。是否同时删除底层索引 / 表随后端而异: redis / milvus / milvus-lite / qdrant / sqlite-vec 会删除索引或表;elasticsearch 仅清空文档并保留 index 与 mapping;pgvector 删除共享表中该索引对应的行。

检索结果字段(Document)

similarity_search_* 返回 Document,可用 document_schema=YourModel 换成自定义模型:

字段 含义
vs_page_content 原始文本内容
vs_embedding 向量(float32 字节)
vs_embeddings_score 向量相关度 1 - distance,取值 [0, 1]
vs_rerank_score rerank 分数(仅 similarity_search_and_rerank)
vs_uid <index_name>:<page_id>
vs_index_name 命中的索引名
vs_kb_id / vs_doc_id / vs_page_id / vs_category 核心元数据
vs_metadata 业务自定义元数据 dict(如 {"author": ..., "score": ...})

过滤

from openai_simple_vectorstore.base import Filter

# tag 精确过滤:values 内多值为 OR 命中
docs = vs.similarity_search_with_relevance_scores(
    "查询", index_name="default", k=5,
    filters=[Filter(field="author", values=["alice", "bob"])],
)

# 多个 Filter 之间为 AND;numeric 用 op="range" 传 [low, high]
docs = vs.similarity_search_and_rerank(
    "查询", k=5,
    filters=[
        Filter(field="author", values=["alice"]),
        Filter(field="score", values=[7, 10], op="range"),
    ],
)

# 也接受 dict(等价 tag 精确过滤,多键为 AND);dict 形式不支持 range
docs = vs.similarity_search_with_relevance_scores(
    "查询", k=5, filters={"author": "alice", "lang": "zh"},
)

过滤字段必须先在实例上声明,未声明 / 非法取值(空值、None、low > high)会明确报错, 而不是静默忽略。

声明可过滤字段

业务自定义元数据默认会随记录持久化并在 vs_metadata 中返回;要作为过滤条件,必须显式声明:

from openai_simple_vectorstore.base import IndexField

# 简单方式:一批 tag 字段
vs = create_vector_store(filterable_metadata_fields=["author", "lang"])

# 精细方式(与上面二选一;一旦提供 declared_fields,则忽略 filterable_metadata_fields)
vs = create_vector_store(
    declared_fields=[
        IndexField(name="author", type="tag"),        # 字符串等值
        IndexField(name="tags", type="tag_multi"),    # 多值集合命中
        IndexField(name="score", type="numeric"),     # 数值,支持 op="range"
        IndexField(name="body", type="text"),         # 全文
    ],
)
  • 自定义核心字段名:构造时传 kb_id_field_name / doc_id_field_name / page_id_field_name / category_field_name,检索结果的 Document 标准字段会自动回填。
  • 更多字段模型与各后端过滤能力见下方《字段模型与过滤语义》。

索引管理

# 建索引(幂等):fields 优先于实例声明;已存在时仅增量补字段,不重建
vs.create_index("default", fields=[IndexField(name="author", type="tag")])

# 查看归一化 schema 与是否存在
info = vs.describe_index("default")
print(info.exists, [f.name for f in info.fields])

# 漂移检测与重建(重建是破坏性的,只能显式调用)
diff = vs.compare_index_schema("default")
if diff.drifted or not diff.exists:
    vs.rebuild_index("default")               # force=True:无条件重建
# vs.rebuild_index("default", force=False)    # 仅在检测到漂移时重建

# 原生过滤索引的检查与补建(缺字段时 qdrant 仅变慢,milvus/pgvector/sqlite-vec 由元数据兜底;redis/elasticsearch 可能报错或失配)
if vs.check_index_fields("default"):
    vs.build_index_fields("default")

连接与模型参数

from openai_simple_vectorstore.base import Connection

vs = create_vector_store(
    vector_db="redis",
    redis_stack_url="redis://localhost:6379/0",
    embeddings_llm=Connection(base_url="http://localhost/v1", api_key="sk-xxx"),
    rerank_llm=Connection(base_url="http://localhost/v1", api_key="sk-xxx"),
    embeddings_model="bge-m3",
    rerank_model="bge-reranker-v2-m3",
    embeddings_dims=1024,             # 嵌入维度,需与模型输出一致(默认 1024)
    embeddings_max_size=8192,         # 单段文本上限,超出截断(默认 1024)
    rerank_max_size=8192,             # rerank 单段文本上限,超出截断(默认 1024)
    embeddings_score_threshold=None,  # None 表示不过滤,见下
    rerank_score_threshold=None,      # None 表示不过滤,见下
    redis_timeout=60,
)
  • 只传 llm 时同时用于 embeddings 与 rerank;分别配置请用 embeddings_llm / rerank_llm。
  • 各远程后端的超时可用 redis_timeout / milvus_timeout / pgvector_timeout / es_timeout / qdrant_timeout 覆盖(默认 60 秒)。
  • 两个阈值语义相同:None(默认)表示不过滤;给出数字时,低于该分数的结果被丢弃。 区别只在作用对象:embeddings_score_threshold 作用于向量相关度 1 - distance ∈ [0, 1] (因此设 0.0 等同于不过滤),rerank_score_threshold 作用于 rerank 模型分数 (取值范围由模型决定,如 bge-reranker 近似 [0, 1])。

环境变量

变量 默认值 说明
OPENAI_SIMPLE_VECTORSTORE_VECTOR_DB redis 后端:redis / redis-search / milvus / milvus-lite / pgvector / elasticsearch / sqlite-vec / qdrant
OPENAI_SIMPLE_VECTORSTORE_REDIS_STACK_URL redis://localhost:6379/0 redis-stack 地址(redis 后端)
OPENAI_SIMPLE_VECTORSTORE_REDIS_TIMEOUT 60 redis 连接/读写超时秒数(别名 REDIS_TIMEOUT)
OPENAI_SIMPLE_VECTORSTORE_MILVUS_URI http://localhost:19530 milvus 地址
OPENAI_SIMPLE_VECTORSTORE_MILVUS_TOKEN 空 milvus 鉴权 token
OPENAI_SIMPLE_VECTORSTORE_MILVUS_CONNECTION_ALIAS default milvus 连接别名
OPENAI_SIMPLE_VECTORSTORE_MILVUS_TIMEOUT 60 milvus RPC 超时秒数(别名 MILVUS_TIMEOUT)
OPENAI_SIMPLE_VECTORSTORE_MILVUS_LITE_URI ./milvus_lite.db milvus-lite 本地数据库文件路径
OPENAI_SIMPLE_VECTORSTORE_PGVECTOR_URL postgresql://localhost:5432/postgres pgvector 连接串(pgvector 后端)
OPENAI_SIMPLE_VECTORSTORE_PGVECTOR_TIMEOUT 60 pgvector 连接超时秒数(别名 PGVECTOR_TIMEOUT)
OPENAI_SIMPLE_VECTORSTORE_ELASTICSEARCH_URL http://localhost:9200 elasticsearch 地址
OPENAI_SIMPLE_VECTORSTORE_ELASTICSEARCH_API_KEY 空 elasticsearch API key(优先于账号密码)
OPENAI_SIMPLE_VECTORSTORE_ELASTICSEARCH_USERNAME 空 elasticsearch 用户名
OPENAI_SIMPLE_VECTORSTORE_ELASTICSEARCH_PASSWORD 空 elasticsearch 密码
OPENAI_SIMPLE_VECTORSTORE_ELASTICSEARCH_VERIFY_CERTS True 是否校验证书(自签 HTTPS 集群可设 false)
OPENAI_SIMPLE_VECTORSTORE_ELASTICSEARCH_TIMEOUT 60 elasticsearch 请求超时秒数(别名 ELASTICSEARCH_TIMEOUT / ES_TIMEOUT)
OPENAI_SIMPLE_VECTORSTORE_SQLITE_VEC_URI ./sqlite_vec.db sqlite-vec 本地数据库文件路径
OPENAI_SIMPLE_VECTORSTORE_QDRANT_URL http://localhost:6333 qdrant 服务地址(别名 QDRANT_URL)
OPENAI_SIMPLE_VECTORSTORE_QDRANT_API_KEY 空 qdrant API key(别名 QDRANT_API_KEY)
OPENAI_SIMPLE_VECTORSTORE_QDRANT_PREFER_GRPC False 是否优先使用 gRPC(别名 QDRANT_PREFER_GRPC)
OPENAI_SIMPLE_VECTORSTORE_QDRANT_TIMEOUT 60 qdrant-client 请求超时秒数(别名 QDRANT_TIMEOUT)
OPENAI_SIMPLE_VECTORSTORE_QDRANT_ON_DISK False 向量/HNSW/payload 是否落盘的总开关(别名 QDRANT_ON_DISK)
OPENAI_SIMPLE_VECTORSTORE_QDRANT_VECTOR_ON_DISK 继承总开关 向量列是否落盘(别名 QDRANT_VECTOR_ON_DISK)
OPENAI_SIMPLE_VECTORSTORE_QDRANT_HNSW_ON_DISK 继承总开关 HNSW 图是否落盘(别名 QDRANT_HNSW_ON_DISK)
OPENAI_SIMPLE_VECTORSTORE_QDRANT_PAYLOAD_ON_DISK 继承总开关 payload 索引是否落盘(别名 QDRANT_PAYLOAD_ON_DISK)
OPENAI_BASE_URL http://localhost/v1 OpenAI 兼容服务基础地址(embeddings / rerank 共用)
OPENAI_API_KEY 空 OpenAI 兼容服务密钥(embeddings / rerank 共用)
OPENAI_EMBEDDINGS_BASE_URL 同 OPENAI_BASE_URL embeddings 服务地址(单独覆盖)
OPENAI_EMBEDDINGS_API_KEY 同 OPENAI_API_KEY embeddings 服务密钥(单独覆盖)
OPENAI_EMBEDDINGS_MODEL bge-m3 embeddings 模型名
OPENAI_EMBEDDINGS_MAX_SIZE 1024 embeddings 单段文本上限,超出截断
OPENAI_EMBEDDINGS_DIMS 1024 嵌入向量维度(需与模型输出一致)
OPENAI_RERANK_BASE_URL 同 OPENAI_BASE_URL rerank 服务地址(单独覆盖)
OPENAI_RERANK_API_KEY 同 OPENAI_API_KEY rerank 服务密钥(单独覆盖)
OPENAI_RERANK_MODEL bge-reranker-v2-m3 rerank 模型名
OPENAI_RERANK_MAX_SIZE 1024 rerank 单段文本上限,超出截断

兼容 openai-redis-vectorstore:OPENAI_REDIS_VECTORSTORE_REDIS_STACK_URL、 OPENAI_EMBEDDINGS_*、OPENAI_RERANK_*、OPENAI_BASE_URL、OPENAI_API_KEY 等变量可直接使用。

扩展新的向量数据库后端

继承共享抽象基类 VectorStore 并实现以下方法,再注册到工厂即可:

  1. 实现 get_cached_vectorstore(引擎的获取与缓存)
  2. 实现 _search_index,返回 [(page_id, distance, item), ...]
  3. 实现 get_item / delete / delete_many / flush
from openai_simple_vectorstore.base import VectorStore, IndexField
from openai_simple_vectorstore.registry import register_vector_store, create_vector_store

class MyStore(VectorStore):
    def get_cached_vectorstore(self, **kwargs): ...
    def _search_index(self, engine, query_embedding, index_name,
                      filters, filter_expression, k): ...
    def get_item(self, uid): ...
    def delete(self, uid): ...
    def delete_many(self, uids): ...
    def flush(self, index_name=None): ...

    # 可选的统一字段模型 / 能力矩阵 / schema 查询契约
    def _capabilities(self): ...
    def _describe_index(self, index_name): ...
    def _ensure_index_created(self, index_name, fields): ...

register_vector_store("mydb", MyStore)
vs = create_vector_store(vector_db="mydb")

base 会统一处理 embeddings 生成、rerank、过滤、去重、排序、relevance_score 与 Document 组装,后端只需专注各自的检索实现。

字段模型与过滤语义

各引擎通过统一的字段声明 / 能力矩阵 / schema 查询接口,向业务暴露"哪些扩展字段可过滤、索引现状如何":

  • IndexField:声明字段类型,支持 tag / tag_multi / numeric / text / vector; 向量字段必须给出 dims,并与引擎配置的 embeddings_dims 一致。
  • capabilities():返回能力矩阵(Capabilities)——indexed_types 表示后端建成 原生可过滤列的类型(如 redis、elasticsearch),meta_filter_types 表示在元数据上做 Python/表达式侧兜底过滤的类型(如 milvus / sqlite-vec / pgvector 的部分类型)。
  • describe_index(index_name):返回归一化的 IndexSchemaInfo——exists=False 表示 索引尚未创建(此时 fields 返回声明/期望字段,方便业务预创建)。索引存在且后端有可读的 逐字段线上 schema 时返回线上真实字段(redis / elasticsearch / milvus / milvus-lite); qdrant / pgvector / sqlite-vec 无逐字段线上 schema(payload / metadata JSON),fields 恒为声明字段。
  • create_index(index_name, fields):按声明的 IndexField 列表构建索引(显式传入的 fields 优先于实例构造时的 declared_fields);已存在时仅补齐可增量添加的部分 (redis FT.ALTER / elasticsearch put_mapping / qdrant payload 索引),不会重建。
  • compare_index_schema(index_name) / rebuild_index(index_name, force=...):只读检测 线上 schema 与期望是否漂移;返回的 IndexDiff 中 exists=False 表示索引已不存在 (如被外部删除),drifted=True 表示字段 / 维度 / 距离度量不一致。重建一律是破坏性的 (删除并重新索引、丢失该索引下的数据),只能显式调用 rebuild_index(force=True 无条件重建,force=False 仅在检测到漂移时重建),不会在创建 / ensure 索引时自动触发。
  • check_index_fields(index_name) / build_index_fields(index_name):检查声明字段中 哪些缺少后端原生过滤索引(IndexFieldStatus.missing),并按需补建。补建是显式 API, 不会在 ensure / 写入路径上隐式执行——缺字段时 qdrant 仍能正确过滤(仅变慢), milvus / pgvector / sqlite-vec 由元数据侧兜底,redis / elasticsearch 则会过滤报错或 失配;建议由调用方主动调用补建。例外:首次创建索引(redis FT.CREATE / elasticsearch 建 index / qdrant 建 collection)时会按当时声明一并建好原生索引, 仅当之后新增字段时才需要显式补建。

过滤统一使用 Filter 对象(tag 精确、tag_multi 多值命中、numeric 区间 via op="range"); base 把归一化后的 filters 传入各后端的 engine/search。后端只需实现 _build_filter_expression(filters, filter_expression) 把归一化过滤器组装为原生过滤表达式。

  • 索引初始化一次性:引擎实例首次执行 ensure_*(建表 / 建 collection / 建 index) 时完成创建或存在性探测,之后所有读写路径不再重复探测(内部 _index_ready / _table_ready 标记)。若索引被外部删除或 schema 漂移,用 compare_index_schema 检测后显式 rebuild_index,而不是期望每次操作都自动 ensure。
  • redis tag_multi 的逗号限制:RediSearch 对 HASH 字段的 TAG 以逗号分隔且 不解析反斜杠转义(实测 a\,b 会被拆成两个标签),因此单个标签值内部不能包含 逗号;普通多值标签(元素本身不含分隔符)可被正确索引与过滤。

概念说明

  • uid:<index_name>:<page_id>,用于唯一定位一条记录。
  • relevance_score:1 - distance,取值 [0, 1],越大越相关。
  • 二阶段召回:similarity_search_and_rerank 先用向量检索取 k * scale 条候选, 再经 rerank 重排取前 k 条。
  • 检索错误诊断:任一后端的向量检索(含超时、连接失败等)都会在抛出前 记录并返回带后端地址 + 索引名 + 检索参数的 RuntimeError,便于定位, 不会把底层驱动的原始调用堆栈直接抛给调用方;索引不存在(未初始化)仍按 空结果处理。
  • 连接/查询超时:各远程后端默认 60 秒(OPENAI_SIMPLE_VECTORSTORE_*_TIMEOUT, qdrant 见上文),也可在实例化时用 redis_timeout / milvus_timeout / pgvector_timeout / es_timeout 覆盖(qdrant_timeout 同理)。
  • elasticsearch 批量写入非事务:insert_many 逐条写入,任一条失败时会尽力 回滚(删除)本次已写入的文档后再抛出,尽量表现为“全成功或全不写入”,但 ES 无多 文档事务,回滚本身失败时仅记录 warning,不掩盖原始异常。
  • elasticsearch numeric 字段:numeric 映射为 float,ES 默认 coerce=true,因此字符串数值(如 "7")会被接受并转换为数值,属预期行为。

开发与测试

python3 -m pytest -q

跑 pytest 时的覆盖率门槛在 pytest.ini 中(--cov-fail-under=90); .coveragerc 的 fail_under=80 只作用于单独执行 coverage report 的场合。

测试分两类:

  • 单元测试(test_unit.py / test_engines_*.py):全部基于内存 fake,离线可跑。
  • 真实嵌入式/外部服务集成测试(test_engines_integration.py):优先使用真实数据库 跑完整链路(本地 OpenAI 兼容 HTTP stub 提供 embeddings/rerank,覆盖 base 真实 HTTP 路径):
    • milvus-lite:进程内嵌入,直接运行;

    • sqlite-vec:需要 sqlite3 支持 loadable-extension,否则自动跳过 (本机 python.org 构建默认不支持,可用支持扩展的 Homebrew python3 执行);

    • pgvector:外部服务,通过 OPENAI_SIMPLE_VECTORSTORE_PGVECTOR_URL 指定连接串, 连接可达才执行。例如:

      podman run -d --name pgvector-pg17 -p 55432:5432 \
        -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres \
        docker.io/pgvector/pgvector:pg17
      
      OPENAI_SIMPLE_VECTORSTORE_PGVECTOR_URL='postgresql://postgres:postgres@localhost:55432/postgres' \
        python3 -m pytest test_engines_integration.py -q
      
    • qdrant:外部服务,安装 qdrant-client 且通过 OPENAI_SIMPLE_VECTORSTORE_QDRANT_URL 指定的服务可达才执行。例如:

      podman run -d --name qdrant -p 6333:6333 -p 6334:6334 docker.io/qdrant/qdrant:latest
      
      OPENAI_SIMPLE_VECTORSTORE_QDRANT_URL='http://localhost:6333' \
        python3 -m pytest test_engines_integration.py -q
      

      未安装 qdrant-client 时,test_engines_qdrant.py 会注入内存 fake 客户端, 离线即可完整覆盖 qdrant 引擎逻辑。

    • redis:外部服务,需带 RediSearch 的 redis-stack(或内置 search 模块的 Redis 8), 通过 OPENAI_SIMPLE_VECTORSTORE_REDIS_STACK_URL 指定地址且 FT._LIST 可用才执行; 普通 redis 会自动跳过。例如:

      podman run -d --name redis-stack -p 6379:6379 docker.io/redis/redis-stack:latest
      
      OPENAI_SIMPLE_VECTORSTORE_REDIS_STACK_URL='redis://localhost:6379/0' \
        python3 -m pytest test_engines_integration.py -q
      
# 真实嵌入式/外部后端(milvus-lite / sqlite-vec / pgvector / qdrant / redis,按运行时能力自动启用)
python3 -m pytest test_engines_integration.py -q

版本记录

0.3.1(2026-10-02)

  • 索引生命周期收敛:ensure_*(建表 / collection / index)改为每个引擎实例只探测 一次(内部 _index_ready / _table_ready),读写热路径不再重复探测;新增 IndexDiff.exists 区分"未创建"与"漂移";新增 check_index_fields / build_index_fields 按需补建后端原生过滤索引(显式 API,不在 ensure / 写入路径隐式触发)。
  • qdrant 落盘拆分可配:向量 / HNSW 图 / payload 索引三部分是否落盘可分别配置 (qdrant_vector_on_disk / qdrant_hnsw_on_disk / qdrant_payload_on_disk, qdrant_on_disk 为兜底总开关);默认全部走内存(False,相对 0.3.0 的行为变更)。
  • 统一检索错误诊断:任一后端的向量检索(含超时、连接失败)抛出带后端地址 + 索引名 + 检索参数的 RuntimeError,并用结构化 index_missing 标记只吞"真正未建索引",避免按 文案子串匹配误吞真实错误。
  • 可配置超时:redis / milvus / pgvector / elasticsearch / qdrant 新增连接与请求超时 (*_timeout 参数或 OPENAI_SIMPLE_VECTORSTORE_*_TIMEOUT,默认 60 秒),redisvl 的 SearchIndex 同样受 socket 超时约束。
  • 跨引擎正确性修复:
    • redis:tag_multi 改为直接以 TAG 分隔符拼接/拆分(RediSearch HASH 不解析反斜杠转义), FT.INFO 兼容 RESP2/RESP3 与 dims= / DIM 两种向量参数,describe_index 返回线上 FT schema,flush glob 转义并清理缓存引擎,PREFIX 改为 index_name + ":" 以隔离 同名前缀索引(旧索引需 rebuild_index 后生效);
    • pgvector:共享表 to_regclass 为 NULL 视为"未建表"(不再建幻影表),每连接锁改用 WeakKeyDictionary 安装,批量写入改为整批事务 + 失败回滚,filter_expression 字面 % 转义;
    • sqlite-vec:整批写入持有连接锁并支持回滚,读/删不再隐式建表;
    • milvus / milvus-lite:含单引号的 page_id 回退到自建转义表达式,删除不再因可见性滞后 短路,describe_index 缺失向量维度时逐级回退;
    • elasticsearch:insert_many 中途失败时回滚,覆盖写恢复批处理前旧文档;
    • qdrant:filter_expression 的 must/should/must_not 归一,numeric 等值过滤改用 Range(gte=v, lte=v)。
  • 过滤与字段模型加固:Filter 取值归一(字符串不逐字符拆分、集合排序、接受单个 Filter/dict),拒绝未声明字段、空值 / None、非法 op 与 low > high;numeric 取值 统一转 float;tag_multi 全后端恒返回 list;核心 id 字段恒按字符串解码; create_index(index_name, fields=...) 保留与向量同名的显式声明并合并进实例声明。
  • 打包:requires-python 提升至 >=3.10,核心依赖补 numpy 并同步 requirements.txt, pydantic>=2 与各 extras 增加版本下界,entry-points 导入时自动注册。
  • 审计回归(round4 / round5 / round6 / round7 / round8):新增 test_audit_round4.py / test_audit_round5.py / test_audit_round6.py / test_audit_round7.py / test_audit_round8.py,分支覆盖率 100%。round5 / round6 另修复: redis 向量 datatype 配置生效且 capabilities 不再把 text 当作可过滤类型; elasticsearch num_candidates 封顶 10000;qdrant 无 FloatIndexParams 时 numeric 索引 保持 float;sqlite-vec ensure_table 加锁并双重检查;并统一澄清 flush / describe_index / 引擎缓存等注释与 README 表述。round7 / round8 另修复: 自定义 document_schema 不含标准分数字段时(README 允许只传子模型)检索排序 / rerank 不再抛 AttributeError / ValueError(排序改用内部计算的分数,写入 rerank 分数时容忍 缺失字段);milvus-lite 不再在模块顶层硬导入 pymilvus.milvus_client.index.IndexParams (改为回退分支内惰性导入,并优先尝试旧签名),避免旧版 pymilvus 下整个后端 import 失败。

0.3.0(2026-09-24)

  • 新增 qdrant 后端(原生 payload 过滤、uuid5 point id 映射、可配置 on_disk, 同时作用于向量、HNSW 图与 payload 索引),并补齐 capabilities / describe_index / create_index / 漂移检测与重建。
  • create_index(index_name, fields=...) 语义统一:显式传入的 fields 优先于实例构造时的 declared_fields,redis / elasticsearch / qdrant 均生效;已存在索引时按可增量方式补齐 字段(redis FT.ALTER ... SCHEMA ADD、elasticsearch put_mapping、qdrant payload 索引)。
  • 索引重建收敛为显式调用:rebuild_index 不再在创建 / ensure 时自动触发;新增只读的 compare_index_schema 漂移检测(force=False 仅在漂移时重建)。
  • 修复 redis 索引 schema 漂移误报:FT.INFO 向量参数兼容 dims= / DIM 键值对两种格式, 字段类型与向量维度 / 距离度量归一化后比对。
  • 移除未被调用的死钩子 _prepare_engine(milvus / milvus-lite / pgvector / elasticsearch / sqlite-vec)。
  • 包元数据完善:描述列出全部后端并补充 embeddings / rerank 关键词。

0.2.0(2026-09-08)

  • 演进为完整字段模型:新增 IndexField 声明(tag / tag_multi / numeric / text / vector)、capabilities() 能力矩阵、describe_index() 归一化 schema 查询、create_index() schema 声明建索引。
  • 过滤 DSL 升级为统一的 Filter(含 numeric 区间 op="range")并新增 validate_filters; 各引擎 _search_index 收敛为 (engine, query_embedding, index_name, filters, filter_expression, k), 移除旧的 kb_ids / categories 参数(内部经 Filter 适配为 vs_kb_id / vs_category 字段)。
  • redis / elasticsearch / milvus / milvus-lite / pgvector / sqlite-vec 全部适配新签名, 并补齐 capabilities / describe_index / _ensure_index_created。
  • Document 新增 vs_metadata 字段:检索结果携带业务自定义元数据(如声明 IndexField 的可过滤标量 vs_score),非标准 vs_* 模型字段在 _extract_custom_metadata 中聚拢。
  • milvus(独立部署)insert / delete 不再显式 flush():写入后检索可见依赖服务端自动落盘 (cacheFlushInterval,默认约 3s),有短暂写后读不一致窗口;集成测试据此改为有界轮询收敛。
  • 覆盖率提升至 97%(阈值 90%)。

0.1.0(2026-09-08)

  • 首个正式版本:在 redis-search 与 milvus 基础上新增 pgvector、elasticsearch、 sqlite-vec 三个后端(factory + registry 注册,支持 extras 选择性安装)。
  • 统一 embeddings / rerank 二阶段召回、插入 / 删除 / 更新(upsert)/ 查询 / 刷新等接口。
  • 新增 kb / category 元数据过滤语义:各引擎在向量候选上按元数据过滤。
  • milvus(独立部署)与 milvus-lite 支持同 page_id 更新(upsert)与删除后立即可见。
  • elasticsearch 显式声明 kb / doc / category 等 keyword 映射以支持过滤,并自动迁移旧 schema。
  • 新增对 pgvector / elasticsearch / sqlite-vec / milvus 真实外部服务的端到端测试 (test_engines_integration.py),覆盖率 96%(阈值 90%)。

License

MIT

Metadata

Release files for openai-simple-vectorstore 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for openai-simple-vectorstore 0.3.1
File Size Uploaded
openai_simple_vectorstore-0.3.1.tar.gz 111.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for openai-simple-vectorstore 0.3.1
File Interpreter ABI Platform
openai_simple_vectorstore-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 217.8 kB

Release files / openai_simple_vectorstore-0.3.1.tar.gz

Download URL openai_simple_vectorstore-0.3.1.tar.gz
Size 111.0 kB
Tags Source
SHA-256 checksum
How to use checksums
c7e67cf6c35e54b777d763b877c757ff7041b3df85fe5fd71c24c5efe4b59df4
BLAKE2b-256 checksum
How to use checksums
5337c74ae69b8c8a10b4f919c426862ca7538d519e0bdf41c7ea2ffc607960c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Release files / openai_simple_vectorstore-0.3.1-py3-none-any.whl

Download URL openai_simple_vectorstore-0.3.1-py3-none-any.whl
Size 106.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e58cb9906f5ebd81404ad6e1c7d2d58353dc6a3f28959fd8ca57b6ce02ac618d
BLAKE2b-256 checksum
How to use checksums
cae18fe07ac327cdfc540f946090c9ab19d2d5b7cb0ea017868ae0a6d58931c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Release history Release notifications | RSS feed

0.3.2

2 release files

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page