chat
背景
类似的,给出向量数据库的表字段+索引。
我初步想的,大概需要 gitHistoryCommit(提交记录);
gitHistoryFile(提交文件,冗余commitId);
gitHistoryMethod(提交函数,冗余 fileId)。
每个字段都要有 repoId,时间。其他的你看着设计。
设计
向量数据库(Milvus)完整表设计(Java SDK 2.6.13)
一、表清单与原因
| 表名 | 对应图实体 | 需要原因 |
|---|---|---|
gitHistoryCommit |
GitHistoryCommit |
提交级语义检索,用于“自然语言 → 提交” |
gitHistoryFile |
GitHistoryFile |
文件级语义检索,用于“功能描述 → 文件” |
gitHistoryDiffHunk |
GitHistoryDiffHunk |
细粒度变更块检索,用于“类似修改模式”的匹配(例如查找相似的 bug 修复片段) |
gitHistoryMethod |
GitHistoryFunction |
函数级语义检索,用于代码片段相似匹配、推荐相似实现 |
为什么需要 DiffHunk 表?
虽然 DiffHunk 是中间实体,但它的 newCode 和 oldCode 包含变更的具体内容,可以用于检索“历史上类似的修改”。例如:查找“所有增加空指针检查的 diff 块”,直接检索 diff hunk 比检索函数更精确。因此保留该表。
二、通用设计原则(Java SDK 2.6.13)
- 分区键:所有表均以
repoId作为分区键(isPartitionKey(true)),实现多仓库物理隔离。 - 标量索引:对过滤字段(
repoId、commitHash、fileId、methodId、时间戳等)创建 INVERTED 索引。 - 向量索引:使用 HNSW,度量类型 COSINE,参数
M=16,efConstruction=200。 - 向量维度:1536(适配
text-embedding-3-small等模型)。 - 自动主键:
id字段自增,类型Int64。
三、Collection 1: gitHistoryCommit
3.1 字段定义
| 字段名 | 类型 | 是否向量 | 说明 | 索引 |
|---|---|---|---|---|
id |
INT64 | 否 | 自增主键 | 主键 |
commitHash |
VARCHAR(40) | 否 | 完整 commit SHA | INVERTED |
repoId |
VARCHAR(128) | 否 | 仓库标识(分区键) | INVERTED |
authorTime |
INT64 | 否 | 提交时间戳(秒) | INVERTED |
summary |
VARCHAR(1024) | 否 | 提交摘要(message + 变更文件列表) | 无 |
embedding |
FLOAT_VECTOR(1536) | ✅ | 语义向量 | HNSW(COSINE) |
3.2 Java 创建代码
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
import io.milvus.v2.service.index.request.CreateIndexReq;
public class CreateCommitCollection {
public static void create(MilvusClientV2 client, String collectionName) {
// 1. 定义 Schema
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.addField(DataType.Int64, "id", true, true); // 主键,自增
schema.addField(DataType.VarChar, "commitHash", 40, false);
schema.addField(DataType.VarChar, "repoId", 128, false).setPartitionKey(true);
schema.addField(DataType.Int64, "authorTime", false);
schema.addField(DataType.VarChar, "summary", 1024, false);
schema.addField(DataType.FloatVector, "embedding", 1536, false);
// 2. 创建 Collection
CreateCollectionReq createReq = CreateCollectionReq.builder()
.collectionName(collectionName)
.collectionSchema(schema)
.build();
client.createCollection(createReq);
// 3. 创建标量索引
client.createIndex(CreateIndexReq.builder()
.collectionName(collectionName)
.fieldName("commitHash")
.indexType(IndexParam.IndexType.INVERTED)
.build());
client.createIndex(CreateIndexReq.builder()
.collectionName(collectionName)
.fieldName("repoId")
.indexType(IndexParam.IndexType.INVERTED)
.build());
client.createIndex(CreateIndexReq.builder()
.collectionName(collectionName)
.fieldName("authorTime")
.indexType(IndexParam.IndexType.INVERTED)
.build());
// 4. 创建向量索引
IndexParam indexParam = IndexParam.builder()
.fieldName("embedding")
.indexType(IndexParam.IndexType.HNSW)
.metricType(IndexParam.MetricType.COSINE)
.extraParam("M", 16)
.extraParam("efConstruction", 200)
.build();
client.createIndex(CreateIndexReq.builder()
.collectionName(collectionName)
.indexParam(indexParam)
.build());
}
}
四、Collection 2: gitHistoryFile
4.1 字段定义
| 字段名 | 类型 | 是否向量 | 说明 | 索引 |
|---|---|---|---|---|
id |
INT64 | 否 | 自增主键 | 主键 |
fileId |
VARCHAR(512) | 否 | 文件唯一标识({repoId}:{path}) |
INVERTED |
filePath |
VARCHAR(1024) | 否 | 文件路径 | INVERTED |
repoId |
VARCHAR(128) | 否 | 仓库标识(分区键) | INVERTED |
lastCommitHash |
VARCHAR(40) | 否 | 最后修改的 commit hash | INVERTED |
language |
VARCHAR(32) | 否 | 编程语言 | INVERTED |
updateTime |
INT64 | 否 | 解析时间戳(秒) | INVERTED |
description |
VARCHAR(2048) | 否 | 文件描述(文件名+路径+主要类/函数摘要) | 无 |
embedding |
FLOAT_VECTOR(1536) | ✅ | 语义向量 | HNSW(COSINE) |
4.2 Java 创建代码
public class CreateFileCollection {
public static void create(MilvusClientV2 client, String collectionName) {
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.addField(DataType.Int64, "id", true, true);
schema.addField(DataType.VarChar, "fileId", 512, false);
schema.addField(DataType.VarChar, "filePath", 1024, false);
schema.addField(DataType.VarChar, "repoId", 128, false).setPartitionKey(true);
schema.addField(DataType.VarChar, "lastCommitHash", 40, false);
schema.addField(DataType.VarChar, "language", 32, false);
schema.addField(DataType.Int64, "updateTime", false);
schema.addField(DataType.VarChar, "description", 2048, false);
schema.addField(DataType.FloatVector, "embedding", 1536, false);
client.createCollection(CreateCollectionReq.builder()
.collectionName(collectionName)
.collectionSchema(schema)
.build());
// 标量索引
for (String field : Arrays.asList("fileId", "filePath", "repoId", "lastCommitHash", "language", "updateTime")) {
client.createIndex(CreateIndexReq.builder()
.collectionName(collectionName)
.fieldName(field)
.indexType(IndexParam.IndexType.INVERTED)
.build());
}
// 向量索引
IndexParam indexParam = IndexParam.builder()
.fieldName("embedding")
.indexType(IndexParam.IndexType.HNSW)
.metricType(IndexParam.MetricType.COSINE)
.extraParam("M", 16)
.extraParam("efConstruction", 200)
.build();
client.createIndex(CreateIndexReq.builder()
.collectionName(collectionName)
.indexParam(indexParam)
.build());
}
}
五、Collection 3: gitHistoryDiffHunk
5.1 字段定义
| 字段名 | 类型 | 是否向量 | 说明 | 索引 |
|---|---|---|---|---|
id |
INT64 | 否 | 自增主键 | 主键 |
diffId |
VARCHAR(512) | 否 | diff 块唯一标识({commitHash}:{filePath}:{startLine}) |
INVERTED |
commitHash |
VARCHAR(40) | 否 | 所属 commit hash | INVERTED |
filePath |
VARCHAR(1024) | 否 | 所属文件路径 | INVERTED |
repoId |
VARCHAR(128) | 否 | 仓库标识(分区键) | INVERTED |
changeType |
VARCHAR(16) | 否 | add / delete / modify |
INVERTED |
commitTime |
INT64 | 否 | 所属 commit 的时间戳(冗余,便于时间过滤) | INVERTED |
newCode |
VARCHAR(4096) | 否 | 变更后的代码片段(可截断) | 无 |
embedding |
FLOAT_VECTOR(1536) | ✅ | 语义向量(基于 newCode + changeType) |
HNSW(COSINE) |
5.2 Java 创建代码
public class CreateDiffHunkCollection {
public static void create(MilvusClientV2 client, String collectionName) {
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.addField(DataType.Int64, "id", true, true);
schema.addField(DataType.VarChar, "diffId", 512, false);
schema.addField(DataType.VarChar, "commitHash", 40, false);
schema.addField(DataType.VarChar, "filePath", 1024, false);
schema.addField(DataType.VarChar, "repoId", 128, false).setPartitionKey(true);
schema.addField(DataType.VarChar, "changeType", 16, false);
schema.addField(DataType.Int64, "commitTime", false);
schema.addField(DataType.VarChar, "newCode", 4096, false);
schema.addField(DataType.FloatVector, "embedding", 1536, false);
client.createCollection(CreateCollectionReq.builder()
.collectionName(collectionName)
.collectionSchema(schema)
.build());
// 标量索引
for (String field : Arrays.asList("diffId", "commitHash", "filePath", "repoId", "changeType", "commitTime")) {
client.createIndex(CreateIndexReq.builder()
.collectionName(collectionName)
.fieldName(field)
.indexType(IndexParam.IndexType.INVERTED)
.build());
}
// 向量索引
IndexParam indexParam = IndexParam.builder()
.fieldName("embedding")
.indexType(IndexParam.IndexType.HNSW)
.metricType(IndexParam.MetricType.COSINE)
.extraParam("M", 16)
.extraParam("efConstruction", 200)
.build();
client.createIndex(CreateIndexReq.builder()
.collectionName(collectionName)
.indexParam(indexParam)
.build());
}
}
六、Collection 4: gitHistoryMethod
6.1 字段定义
| 字段名 | 类型 | 是否向量 | 说明 | 索引 |
|---|---|---|---|---|
id |
INT64 | 否 | 自增主键 | 主键 |
methodId |
VARCHAR(512) | 否 | 函数唯一标识({fileId}:{name}:{startLine}) |
INVERTED |
methodName |
VARCHAR(256) | 否 | 函数名 | INVERTED |
fileId |
VARCHAR(512) | 否 | 所属文件 ID | INVERTED |
filePath |
VARCHAR(1024) | 否 | 所属文件路径 | INVERTED |
repoId |
VARCHAR(128) | 否 | 仓库标识(分区键) | INVERTED |
commitHash |
VARCHAR(40) | 否 | 最近修改该函数的 commit hash | INVERTED |
signature |
VARCHAR(1024) | 否 | 函数签名 | 无 |
bodySnippet |
VARCHAR(4096) | 否 | 函数体代码片段(截断) | 无 |
language |
VARCHAR(32) | 否 | 编程语言 | INVERTED |
updateTime |
INT64 | 否 | 解析时间戳 | INVERTED |
embedding |
FLOAT_VECTOR(1536) | ✅ | 语义向量(基于 signature + bodySnippet) |
HNSW(COSINE) |
6.2 Java 创建代码
public class CreateMethodCollection {
public static void create(MilvusClientV2 client, String collectionName) {
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.addField(DataType.Int64, "id", true, true);
schema.addField(DataType.VarChar, "methodId", 512, false);
schema.addField(DataType.VarChar, "methodName", 256, false);
schema.addField(DataType.VarChar, "fileId", 512, false);
schema.addField(DataType.VarChar, "filePath", 1024, false);
schema.addField(DataType.VarChar, "repoId", 128, false).setPartitionKey(true);
schema.addField(DataType.VarChar, "commitHash", 40, false);
schema.addField(DataType.VarChar, "signature", 1024, false);
schema.addField(DataType.VarChar, "bodySnippet", 4096, false);
schema.addField(DataType.VarChar, "language", 32, false);
schema.addField(DataType.Int64, "updateTime", false);
schema.addField(DataType.FloatVector, "embedding", 1536, false);
client.createCollection(CreateCollectionReq.builder()
.collectionName(collectionName)
.collectionSchema(schema)
.build());
// 标量索引
for (String field : Arrays.asList("methodId", "methodName", "fileId", "filePath",
"repoId", "commitHash", "language", "updateTime")) {
client.createIndex(CreateIndexReq.builder()
.collectionName(collectionName)
.fieldName(field)
.indexType(IndexParam.IndexType.INVERTED)
.build());
}
// 向量索引
IndexParam indexParam = IndexParam.builder()
.fieldName("embedding")
.indexType(IndexParam.IndexType.HNSW)
.metricType(IndexParam.MetricType.COSINE)
.extraParam("M", 16)
.extraParam("efConstruction", 200)
.build();
client.createIndex(CreateIndexReq.builder()
.collectionName(collectionName)
.indexParam(indexParam)
.build());
}
}
七、向量生成策略汇总
| 表 | 输入内容 | 生成说明 |
|---|---|---|
gitHistoryCommit |
summary = message + " modified: " + 文件路径列表 |
调用 embedding 模型(如 OpenAI) |
gitHistoryFile |
description = filePath + " language:" + language + 可选的主要类/函数名列表 |
同上 |
gitHistoryDiffHunk |
newCode + " type:" + changeType |
截取前 4096 字符,避免超长 |
gitHistoryMethod |
signature + "\n" + bodySnippet |
截取前 4096 字符 |
八、Java 插入数据示例(以 gitHistoryCommit 为例)
import io.milvus.v2.service.vector.request.InsertReq;
import java.util.*;
public class InsertCommit {
public static void insert(MilvusClientV2 client, String collectionName) {
List<Map<String, Object>> rows = new ArrayList<>();
Map<String, Object> row = new HashMap<>();
row.put("commitHash", "abc123");
row.put("repoId", "myorg/myrepo");
row.put("authorTime", 1700000000L);
row.put("summary", "fix: 登录超时处理,修改了 auth.py");
row.put("embedding", generateEmbedding("fix: 登录超时处理,修改了 auth.py")); // 1536维向量
rows.add(row);
InsertReq insertReq = InsertReq.builder()
.collectionName(collectionName)
.data(rows)
.build();
client.insert(insertReq);
}
}
九、总结
- 4 张表覆盖提交、文件、diff 块、函数四个粒度,满足不同层次的语义检索需求。
- 冗余字段:
repoId(分区键)、commitTime(在 diff 表中)、updateTime等,支持高效过滤。 - 索引完备:标量字段使用 INVERTED 索引,向量字段使用 HNSW(COSINE)。
- Java SDK 2.6.13 兼容的 API 风格(使用
MilvusClientV2、CreateCollectionReq等)。
此设计可直接用于批量解析脚本的向量入库逻辑。
