You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用JavaScript(ioredis)实现Azure Redis向量余弦相似度搜索?

使用ioredis实现Azure Redis缓存的向量余弦相似度搜索

首先要确保你的Azure Redis缓存实例是Enterprise层级,并且启用了Redis Stack(包含Redisearch和RedisJSON模块)——这是实现向量搜索的基础,因为原生Redis不支持向量索引与相似度计算。

1. 安装依赖

npm install ioredis mathjs

ioredis用于和Redis交互,mathjs可选,用于客户端侧的余弦相似度计算(如果需要)。

2. 连接Azure Redis缓存

const Redis = require('ioredis');

// 从Azure门户获取你的Redis连接字符串
const redis = new Redis({
  host: 'your-redis-host.redis.cache.windows.net',
  port: 6380,
  password: 'your-redis-password',
  tls: true // Azure Redis强制要求TLS
});

3. 创建向量索引

先创建包含向量字段的搜索索引,这里假设我们存储的是文档+向量数据:

async function createVectorIndex() {
  // 索引名称:doc_index,定义向量字段为content_vector(维度假设为1536,适配常见大模型输出)
  await redis.call('FT.CREATE', 'doc_index', 'ON', 'JSON', 'PREFIX', '1', 'doc:', 
    'SCHEMA', '$.content_vector', 'AS', 'content_vector', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '1536', 'DISTANCE_METRIC', 'COSINE');
  console.log('向量索引创建成功');
}

createVectorIndex().catch(console.error);
  • DISTANCE_METRIC设置为COSINE,指定用余弦相似度计算距离
  • DIM要和你实际使用的向量维度一致(比如OpenAI的text-embedding-ada-002是1536)

4. 插入带向量的数据

async function insertDocument(docId, content, vector) {
  // 存储为JSON格式,键前缀为doc:,对应索引的PREFIX设置
  await redis.json.set(`doc:${docId}`, '$', {
    content: content,
    content_vector: vector
  });
  console.log(`文档${docId}插入成功`);
}

// 示例:插入一个测试文档(vector是1536维的float32数组)
const testVector = new Float32Array(1536).fill(0.1); // 替换为你的真实向量
insertDocument('1', '测试文档内容', testVector).catch(console.error);

5. 执行余弦相似度搜索(KNN)

用Redis的FT.SEARCH命令执行最近邻搜索,返回与目标向量最相似的Top N结果:

async function searchSimilarVectors(targetVector, topN = 5) {
  // 将目标向量转换为Redis接受的二进制格式(FLOAT32)
  const vectorBuffer = Buffer.from(targetVector.buffer);
  
  // 执行KNN搜索,使用COSINE距离
  const results = await redis.call('FT.SEARCH', 'doc_index', 
    '*=>[KNN $topN @content_vector $query_vector AS distance]', 
    'PARAMS', '2', 'topN', topN, 'query_vector', vectorBuffer,
    'RETURN', '2', '$.content', 'distance',
    'SORTBY', 'distance', 'ASC',
    'LIMIT', '0', topN);
  
  // 格式化结果
  const formattedResults = [];
  for (let i = 1; i < results.length; i += 2) {
    const docKey = results[i];
    const docData = results[i+1];
    formattedResults.push({
      docId: docKey.split(':')[1],
      content: docData['$.content'],
      cosineSimilarity: 1 - parseFloat(docData.distance) // 余弦距离转相似度(距离范围0-2,相似度=1-距离)
    });
  }
  return formattedResults;
}

// 示例:搜索与测试向量相似的文档
searchSimilarVectors(testVector, 3).then(results => {
  console.log('相似文档结果:', results);
}).catch(console.error);

注意:Redis返回的是余弦距离(范围0到2),所以相似度需要转换为1 - 距离(范围0到1,值越大越相似)。

备选:客户端侧计算余弦相似度

如果你的Redis实例不支持Redis Stack,也可以先拉取所有向量到客户端,再计算余弦相似度:

const { dot, norm } = require('mathjs');

function cosineSimilarity(vecA, vecB) {
  return dot(vecA, vecB) / (norm(vecA) * norm(vecB));
}

async function searchSimilarClientSide(targetVector) {
  // 拉取所有文档向量
  const docKeys = await redis.keys('doc:*');
  const docs = await Promise.all(docKeys.map(key => redis.json.get(key, '$')));
  
  // 计算每个文档与目标向量的相似度并排序
  const results = docs.map((doc, index) => ({
    docId: docKeys[index].split(':')[1],
    content: doc[0].content,
    cosineSimilarity: cosineSimilarity(Array.from(doc[0].content_vector), Array.from(targetVector))
  })).sort((a, b) => b.cosineSimilarity - a.cosineSimilarity);
  
  return results.slice(0, 5); // 返回Top5
}

这种方法适合数据量小的场景,数据量大时性能很差,推荐优先使用Redis Stack的原生搜索。

内容的提问来源于stack exchange,提问作者MSTr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:07:27