Spring Boot整合Redis Stack构建本地向量数据库相似性查询
在微服务架构中,数据的高效存储与快速查询是至关重要的。Redis作为一个高性能的内存数据结构存储系统,不仅可以用作缓存、消息代理,还可以扩展为向量数据库,实现高效的相似性搜索。本文将详细介绍如何使用Spring Boot整合Redis Stack,构建本地向量数据库,并进行相似性查询。
一、Redis Stack简介
Redis Stack(也称为Redis Enterprise或Redis Cloud)是一个全面的Redis解决方案,它包括了Redis数据库、Redis搜索、Redis AI、Redis JSON等多个模块,为开发者提供了丰富的数据结构和强大的功能。其中,Redis搜索模块允许我们将Redis用作向量数据库,进行相似性搜索。
二、环境准备
在开始之前,我们需要准备以下环境:
- JDK:确保已安装Java Development Kit(JDK),版本建议为17或更高。
- Maven:用于构建和管理Java项目依赖。
- Docker:用于运行Redis Stack容器。
- Spring Boot:用于构建微服务应用。
三、Redis Stack安装与配置
我们将使用Docker来安装Redis Stack。以下是安装步骤:
-
拉取Redis Stack镜像
docker pull redis/redis-stack
-
运行Redis Stack容器
docker run -d --name redis-stack -p 6379:6379 -p 5540:5540 redis/redis-stack
这将启动Redis Stack容器,并暴露Redis服务(端口6379)和Redis Insight管理界面(端口5540)。
-
访问Redis Insight
打开浏览器,访问
http://localhost:5540
,即可进入Redis Insight管理界面,进行Redis数据库的可视化管理。
四、Spring Boot项目构建
接下来,我们将使用Spring Boot构建一个微服务应用,用于与Redis Stack进行交互,实现向量数据库的相似性查询。
-
创建Spring Boot项目
使用Spring Initializr或Maven命令创建一个新的Spring Boot项目,并添加以下依赖:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency> <!-- 其他依赖,如Spring AI(可选) --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-redis-spring-boot-starter</artifactId> <version>${spring-ai.version}</version> </dependency> </dependencies>
-
配置Redis连接
在
application.yml
或application.properties
文件中配置Redis连接信息:spring: redis: host: localhost port: 6379 # 其他配置,如密码、连接池等(可选)
-
创建Redis配置类
创建一个Redis配置类,用于配置RedisTemplate和其他必要的Bean:
@Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); return template; } // 其他配置,如HashOperations、ValueOperations等(可选) }
-
实现向量存储与查询
为了将文本或数据转换为向量,并使用Redis进行存储和查询,我们需要一个嵌入模型(如Word2Vec、BERT等)来生成向量。这里,我们假设已经有一个向量化工具(如
vectorStore
),它可以将指定的字段转换为高维向量,并存储在Redis中。@Service public class VectorService { @Autowired private RedisTemplate<String, Object> redisTemplate; // 存储向量到Redis public void storeVector(String key, double[] vector) { // 将向量序列化为字符串或其他可存储的格式(如JSON) String vectorStr = Arrays.toString(vector); redisTemplate.opsForValue().set(key, vectorStr); } // 查询与给定向量最相似的K个向量 public List<String> similaritySearch(double[] queryVector, int k) { // 将查询向量转换为与存储在Redis中相同格式的字符串(可选) String queryVectorStr = Arrays.toString(queryVector); // 使用Redis的搜索功能进行相似性搜索(这里需要实现具体的搜索逻辑) // 假设有一个`vectorStore.similaritySearch`方法可以进行相似性计算 // List<Document> results = vectorStore.similaritySearch(queryVector, k); // 返回结果(这里仅为示例,实际应返回相似向量的键或其他相关信息) // return results.stream().map(Document::getKey).collect(Collectors.toList()); // 由于Redis原生不支持向量搜索,这里可以使用第三方库或自定义实现 // 以下是一个简单的示例,使用余弦相似度进行手动计算(不推荐用于生产环境) Map<String, Double> similarityMap = new HashMap<>(); redisTemplate.keys("*").forEach(redisKey -> { String vectorStr = (String) redisTemplate.opsForValue().get(redisKey); double[] storedVector = Arrays.stream(vectorStr.replaceAll("[\\[\\]\\s]", "").split(",")) .mapToDouble(Double::parseDouble).toArray(); double similarity = cosineSimilarity(queryVector, storedVector); similarityMap.put(redisKey, similarity); }); // 按相似度排序并返回前K个结果 List<Map.Entry<String, Double>> sortedEntries = similarityMap.entrySet().stream() .sorted((e1, e2) -> Double.compare(e2.getValue(), e1.getValue())) .collect(Collectors.toList()); return sortedEntries.stream().limit(k).map(Map.Entry::getKey).collect(Collectors.toList()); } // 计算余弦相似度 private double cosineSimilarity(double[] a, double[] b) { double dotProduct = 0.0; double normA = 0.0; double normB = 0.0; for (int i = 0; i < a.length; i++) { dotProduct += a[i] * b[i]; normA += a[i] * a[i]; normB += b[i] * b[i]; } return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB)); } }
注意:上述代码中的
vectorStore.similaritySearch
方法是一个假设的方法,Redis原生并不支持向量搜索。在实际应用中,我们可以使用Redis的搜索模块(需要安装Redis Search插件)或第三方库(如Elasticsearch、FAISS等)来实现高效的向量搜索。此外,上述代码中的余弦相似度计算是手动实现的,仅用于示例,不推荐在生产环境中使用。 -
创建控制器
创建一个控制器,用于接收客户端的请求,并调用
VectorService
进行向量存储和查询:@RestController @RequestMapping("/vectors") public class VectorController { @Autowired private VectorService vectorService; // 存储向量 @PostMapping("/store") public ResponseEntity<Void> storeVector(@RequestBody Map<String, double[]> requestBody) { String key = requestBody.keySet().iterator().next(); double[] vector = requestBody.get(key); vectorService.storeVector(key, vector); return ResponseEntity.ok().build(); } // 查询相似向量 @GetMapping("/search") public ResponseEntity<List<String>> similaritySearch(@RequestParam double[] queryVector, @RequestParam int k) { List<String> similarKeys = vectorService.similaritySearch(queryVector, k); return ResponseEntity.ok(similarKeys); } }
-
运行应用
使用Maven或IDE运行Spring Boot应用,然后可以通过Postman或其他HTTP客户端发送请求,进行向量存储和查询。
五、总结
通过上述步骤,我们成功使用Spring Boot整合了Redis Stack,并构建了一个本地向量数据库,实现了相似性查询。然而,需要注意的是,Redis原生并不支持向量搜索,因此在实际应用中,我们需要借助Redis的搜索模块、