跳到主要内容

Milvus JDBC 入门:向量写入与检索

如果项目已经使用 Java 和 JDBC,接入 Milvus 后,能不能继续用 PreparedStatement 传参数、用 ResultSet 读取结果?

jdbc-milvus 提供了这样的入口。比如,下面的命令是在文章类别中查找与给定向量最接近的两条记录:

SELECT id, title, score FROM blog_jdbc_articles
WHERE category = ?
ORDER BY embedding <-> ? LIMIT 2;

第一个参数是类别,第二个参数是向量。你仍然需要理解向量检索,但不用为这次查询重新组织一套 Java 调用方式。

一个 Mapper 中组合构造器、注解与 XML

选择数据访问方式时,并不一定要在“全部写 Lambda”和“全部写 XML”之间做决定。

以订单模块为例:带条件的列表适合构造器;按 ID 查询只有一行 SQL;统计报表需要更明确地维护语句。dbVisitor 允许这三种写法放在同一个 Mapper 接口里。

Mapper 实战:Redis 商品缓存读写

Redis 没有关系型表,怎么会和 Mapper 放在一起?关键不是把 Redis 变成 SQL 数据库,而是复用 Java 接口、参数绑定和结果映射。

例如,一个商品缓存接口可以只有三个业务方法:save、load、evict。方法背后执行的仍是 Redis 的 SET、GET 和 DEL。

Milvus 实体映射与 DAO 封装

第一次向量查询跑通后,业务代码通常还需要一个稳定的入口:新增文章、按类别检索、修改标题。每个调用方都去处理 ResultSet,并不是唯一选择。

这一篇在 jdbc-milvus 之上使用 dbVisitor,把集合映射为实体,再把操作收进一个 Mapper 接口。调用方只需要知道业务方法,不必重复处理列名和结果转换。

用 SQL 操作 Milvus:从检索到 ORM

Java 应用通常通过 Milvus SDK 写入数据和检索向量。对关系型数据库开发者来说,SQL 和 JDBC 更熟悉。jdbc-milvus 让这套使用方式也能用于 Milvus:

SELECT id, title, score FROM intro_articles -- score 为 L2 平方距离,越小越接近
WHERE category = 'java' -- 只在 Java 类别内检索
ORDER BY embedding <-> [1,0] LIMIT 2; -- 按向量距离取最近的两条

加入 dbVisitor,还可以用实体映射和查询构造器完成同样的检索:

@Table("intro_articles")
public class Article {
@Column(primary = true)
private Long id;
private String title;
private String category;
private List<Float> embedding;
// 省略标准 getter、setter
}
LambdaTemplate lambda = new LambdaTemplate(conn);
List<Article> articles = lambda.query(Article.class)
.eq(Article::getCategory, "java")
.orderByL2(Article::getEmbedding, List.of(1F, 0F))
.initPage(2, 0)
.queryForList();

公元前日期映射:两种处理方案

公元前日期在数据库中的处理是一个被长期忽视的难题。Java 的 ISO 8601 年份表示法与数据库的日期系统存在根本性差异,导致跨系统传递公元前日期时经常出现"偏移一年"或"偏移一天"的诡异 Bug。

dbVisitor 6.7.0 新增了 JulianDayTypeHandler 和 PgDateTypeHandler 两个处理器,分别从"跨库通用"和"PostgreSQL 原生"两个角度提供日期映射方式;数据库日期范围和处理器边界仍需考虑。

键值查询:将两列结果映射为 Map

在日常开发中,"查两列,组成 Map"是一个高频操作:ID 到名称的映射、编码到描述的映射、配置键到值的映射…… 以往你需要查出列表再手动遍历构建 Map。

dbVisitor 6.7.0 为构造器新增的 queryForPairs 方法,一行代码直接拿到 Map<K, V>。