springboot中余弦相似度
时间: 2025-05-25 16:15:46 浏览: 18
### 实现 Spring Boot 中的余弦相似度计算
要在 Spring Boot 项目中实现或使用余弦相似度计算,可以通过 Redis 向量数据库的支持来完成。以下是具体的说明:
#### 集成 Redis 并配置向量索引
为了支持向量数据存储以及相似性搜索功能,可以利用 Redis 的模块 `RedisJSON` 和 `RediSearch` 来创建向量字段并定义其维度和距离度量方式(如余弦相似度)。通过设置参数 `DISTANCE_METRIC COSINE` 可指定采用余弦相似度作为衡量标准[^1]。
```java
@Configuration
public class RedisConfig {
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory();
}
@Bean
public StringRedisTemplate stringRedisTemplate(LettuceConnectionFactory connectionFactory) {
return new StringRedisTemplate(connectionFactory);
}
}
```
上述代码片段展示了如何在 Spring Boot 应用程序中初始化 Redis 连接工厂,并绑定到模板类以便后续操作。
#### 数据建模与插入
当准备好了基础环境之后,则需设计好待存入的数据结构形式及其对应的键名空间规划;接着按照官方文档指引编写命令脚本或者调用 API 方法将目标对象序列化后上传至服务器端保存起来的同时为其附加必要的元属性标签用于辅助检索过滤条件匹配过程。
例如下面这个例子演示了怎样把一条记录连同它所关联的一个高维特征表示一起写入数据库当中去:
```java
@Service
public class VectorService {
private final StringRedisTemplate template;
public VectorService(StringRedisTemplate template){
this.template = template;
}
public void saveVectorData(String id, double[] vector){
Map<String,Object> dataMap=new HashMap<>();
dataMap.put("id",id);
// 将浮点数组转换为字符串列表形式适合 JSON 存储格式要求
List<Double> vecList=Arrays.stream(vector).boxed().collect(Collectors.toList());
dataMap.put("vector",vecList);
template.opsForValue().set(id,new JSONObject(dataMap).toString());
// 假设已经预先设置了FT.CREATE index_name ON JSON SCHEMA $.vector AS VECTOR FLAT DIMENSION d TYPE FLOAT DISTANCE_METRIC cosine
template.execute((RedisCallback<Void>)connection->{
connection.sendCommand(Command.HSET,id.getBytes(),new byte[][]{":vector".getBytes()},SerializationUtils.serialize(vecList));
return null;
});
}
}
```
这里需要注意的是实际部署运行前还需要额外执行一次建立全文搜索引擎索引的动作以激活矢量查询能力。
#### 查询逻辑构建
最后一步就是开发应用程序接口供外部调用来发起基于内容推荐请求时能够高效准确地返回最相近的结果集项们啦! 下面给出了一种可能版本的样子仅供参考学习之用而已哦~
```java
@RestController
@RequestMapping("/api/recommendations")
public class RecommendationController {
private final StringRedisTemplate template;
public RecommendationController(StringRedisTemplate template){
this.template=template;
}
@GetMapping("/{itemId}")
public ResponseEntity<List<Map.Entry<String,Double>>> getRecommendations(@PathVariable String itemId,@RequestParam(defaultValue="5") int topK){
Optional<byte[]> optItemVecBytes=Optional.ofNullable(template.getConnectionFactory()
.getConnection()
.stringCommands()
.get((itemId+":vector").getBytes()));
if(!optItemVecBytes.isPresent())return ResponseEntity.notFound().build();
List<Double> itemVec=(List<Double>)SerializationUtils.deserialize(optItemVecBytes.get());
Set<Tuple> results=template.opsForGeo().search(
GeoReference.fromCoordinate(new DefaultPoint(itemVec.subList(0,itemVec.size()/2),itemVec.subList(itemVec.size()/2,itemVec.size()))),
new Circle(new Point(0d,0d),Distance.ZERO),
Limit.limit(topK))
.stream()
.map(tup -> Maps.immutableEntry(tup.getKey(), tup.getScore()))
.collect(Collectors.toSet());
return ResponseEntity.ok(new ArrayList<>(results));
}
}
```
以上仅作为一个简化版示意案例分享给大家了解思路方法途径而已,在真实生产环境中还需考虑更多细节因素比如性能优化等方面的工作呢!
阅读全文
相关推荐




















