使用 Redis 作为向量数据库

一、什么是向量数据库?

  • 向量(Vector):在机器学习和 AI 中,向量是由一系列数字组成的序列,用于数值化地描述数据的特征或语义。文本、图像、音频等非结构化数据可以通过模型转换成固定长度的向量。

  • 向量数据库:专门存储、索引和检索向量的数据库系统。可以基于向量之间的距离度量(如余弦相似度、欧氏距离等)进行高效的近邻搜索(Nearest Neighbor Search),从而实现“语义搜索”或“相似度搜索”。

  • 与传统搜索的区别

    • 传统搜索依赖于关键词精确匹配,无法识别同义词、上下文或语义抽象。
    • 向量搜索通过将数据空间映射到高维向量空间,使语义相近的内容在向量空间中距离更近,从而返回更符合用户意图的结果。

二、准备工作

本文示例使用 Python 客户端库 RedisVL,以及常见的 Python 生态组件:

# 建议在虚拟环境中安装
pip install redis pandas sentence-transformers tabulate redisvl

说明

  • redis:官方 Python 客户端。
  • pandas:用于结果展示。
  • sentence-transformers:生成文本向量。
  • tabulate:渲染 Markdown 表格。
  • redisvl:Redis 向量搜索专用扩展(可选,本文使用原生 redis.commands.search API)。

三、连接 Redis

如果你使用本地 Redis:

import redis

client = redis.Redis(host="localhost", port=6379, decode_responses=True)

如果使用 Redis Cloud,则将 hostportpassword 替换为云端实例参数:

client = redis.Redis(
    host="redis-16379.c283.us-east-1-4.ec2.cloud.redislabs.com",
    port=16379,
    password="your_password_here",
    decode_responses=True,
)

四、准备示例数据集

本文使用开源的 bikes 数据集,每条记录包含如下字段:

{
  "model": "Jigger",
  "brand": "Velorim",
  "price": 270,
  "type": "Kids bikes",
  "specs": {
    "material": "aluminium",
    "weight": "10"
  },
  "description": "Small and powerful, the Jigger is the best ride for the smallest of tikes! ..."
}

1. 拉取数据

import requests

URL = ("https://raw.githubusercontent.com/"
       "bsbodden/redis_vss_getting_started"
       "/main/data/bikes.json")
response = requests.get(URL, timeout=10)
bikes = response.json()

2. 存储到 Redis(JSON 文档)

pipeline = client.pipeline()
for i, bike in enumerate(bikes, start=1):
    key = f"bikes:{i:03}"
    pipeline.json().set(key, "$", bike)
pipeline.execute()

你可以这样读取某个字段:

client.json().get("bikes:010", "$.model")
# => ['Summit']

五、生成并存储向量嵌入

1. 选择文本嵌入模型

from sentence_transformers import SentenceTransformer

embedder = SentenceTransformer('msmarco-distilbert-base-v4')

2. 批量获取描述并生成向量

import numpy as np

# 获取所有 key
keys = sorted(client.keys("bikes:*"))

# 批量读取 description
descs = client.json().mget(keys, "$.description")
# 扁平化列表
descriptions = [item for sublist in descs for item in sublist]

# 生成嵌入并转换为 float32 列表
embeddings = embedder.encode(descriptions).astype(np.float32).tolist()
VECTOR_DIM = len(embeddings[0])  # 768

3. 插入向量字段

pipeline = client.pipeline()
for key, vec in zip(keys, embeddings):
    pipeline.json().set(key, "$.description_embeddings", vec)
pipeline.execute()

此时,每条记录都多了一个 $.description_embeddings 数组字段。

六、创建检索索引

为了同时支持基于字段和基于向量的搜索,需要创建一个 Redis Search 索引:

# 在 Redis CLI 环境中执行
FT.CREATE idx:bikes_vss ON JSON
  PREFIX 1 bikes:
  SCHEMA
    $.model                TEXT    WEIGHT 1.0 NOSTEM
    $.brand                TEXT    WEIGHT 1.0 NOSTEM
    $.price                NUMERIC
    $.type                 TAG     SEPARATOR ","
    $.description          TEXT    WEIGHT 1.0
    $.description_embeddings AS vector VECTOR FLAT \
         TYPE FLOAT32 DIM 768 DISTANCE_METRIC COSINE
  • FLAT:扁平索引;也可使用 HNSW(图索引)以提高速度与扩展性。
  • TYPE FLOAT32:32 位浮点。
  • DIM 768:向量维度。
  • DISTANCE_METRIC COSINE:余弦相似度。

创建完成后,通过 FT.INFO idx:bikes_vss 可以查看索引状态,确认文档是否全部就绪。

七、执行向量搜索

1. 嵌入查询文本

queries = [
    "Bike for small kids",
    "Best Mountain bikes for kids",
    "Cheap Mountain bike for kids",
    # ... 共 11 条
]
encoded_queries = embedder.encode(queries)

注意:必须使用与文档相同的模型和参数,否则语义相似度会大打折扣。

2. 构造 KNN 查询模板

from redis.commands.search.query import Query

knn_query = (
    Query("(*)=>[KNN 3 @vector $qvector AS score]")
    .sort_by("score")
    .return_fields("score", "id", "brand", "model", "description")
    .dialect(2)
)
  • (*):不过滤,检索全集。
  • KNN 3:返回最相近的 3 个向量。
  • @vector $qvector:向量字段名与占位符。
  • dialect(2):必要参数以支持向量查询语法。

3. 执行查询并展示

import pandas as pd

def run_search(queries, encoded_qs):
    rows = []
    for q, vec in zip(queries, encoded_qs):
        docs = client.ft("idx:bikes_vss") \
            .search(knn_query, {"qvector": np.array(vec, dtype=np.float32).tobytes()}) \
            .docs
        for doc in docs:
            rows.append({
                "query": q,
                "score": round(1 - float(doc.score), 2),
                "id":    doc.id,
                "brand": doc.brand,
                "model": doc.model,
                "desc":  doc.description[:100] + "..."
            })
    df = pd.DataFrame(rows)
    return df.sort_values(["query","score"], ascending=[True,False])

table = run_search(queries, encoded_queries)
print(table.to_markdown(index=False))
queryscoreidbrandmodeldesc
Best Mountain bikes for kids0.54bikes:003NordChook air 5The Chook Air 5 gives kids aged six years and …

八、总结与后续

Redis 强大的模块化生态(如 RedisJSON、RediSearch)让其成为轻量级、易上手的向量数据库方案。想深入了解更多:

  • 向量索引参数:扁平 VS HNSW、距离度量、并行构建等。
  • 多模态数据:结合 RedisAI,直接在 Redis 中进行模型推理。
  • 扩展语言客户端:C#、JavaScript、Java、Go 等,满足多种开发场景。

欢迎访问 Redis UniversityRedis AI 资源库 以获得更多学习资料。

### Redis作为向量数据库的可能性 Redis确实可以被用作向量数据库,这得益于其扩展模块RediSearch的功能增强。通过引入压缩倒排索引技术,Redis能够执行高效的向量搜索和查询操作[^3]。 #### 向量相似性搜索的支持 为了支持高效的数据检索需求,特别是对于高维数据集中的近似最近邻搜索问题,Redis提供了两种主要的算法来处理向量相似性搜索:HNSW (Hierarchical Navigable Small World graphs) 和 FLAT 算法。这两种算法允许用户根据具体应用场景选择最适合的方法来进行快速而精确的结果查找。 #### 实现向量搜索的具体方法 要利用Redis进行向量搜索,首先需要安装并配置好带有RediSearch模块的实例。之后可以通过如下Python代码片段展示如何创建一个包含向量字段的索引来存储图像特征: ```python import redis from redis.commands.search.field import VectorField, TextField from redis.commands.search.indexDefinition import IndexDefinition, IndexType # 连接到本地运行的Redis服务器 r = redis.Redis(host='localhost', port=6379) # 定义用于保存图片特征向量和其他元数据的信息结构体 schema = ( VectorField("feature_vector", "HNSW", {"TYPE": "FLOAT32", "DIM": 128, "DISTANCE_METRIC": "L2"}), TextField("image_name"), ) # 创建一个新的索引定义对象,并指定该索引应作用于HASH类型的key上 definition = IndexDefinition(prefix=['img:'], index_type=IndexType.HASH) # 使用上述参数建立名为'images_idx'的新索引 r.ft('images_idx').create_index(fields=schema, definition=definition) ``` 这段脚本展示了怎样设置一个适合多媒体文件(比如图片)特征提取后的数值型数组存取环境,在此基础上还可以进一步开发更复杂的应用程序逻辑以满足特定业务场景下的要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hello.Reader

请我喝杯咖啡吧😊

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值