共计 1819 个字符,预计需要花费 5 分钟才能阅读完成。
为什么需要向量数据库?
在开发 AI 驱动的 Android 应用时,我们经常需要处理 Embedding 向量——比如实现图片搜索、推荐系统或自然语言处理功能。但移动端环境带来三个核心挑战:

- 内存限制:中低端设备可能只有 4GB 内存,要同时运行应用和向量计算
- 实时性要求:用户期待搜索响应在 200ms 内完成
- 离线场景:航班、地铁等无网络环境仍需提供服务
技术方案选型
我们测试了三种主流方案在 Pixel 3(Android 12)上的表现:
| 方案 | APK 体积增量 | 查询延迟(128 维) | 精度 |
|---|---|---|---|
| SQLite-VSS | 2.1MB | 28ms | 98.7% |
| FAISS-Lite | 6.8MB | 15ms | 99.2% |
| HNSWLib | 3.4MB | 9ms | 99.5% |
最终选择 SQLite-VSS:
– 体积增加最少
– 与 Room 天然集成
– 满足大多数场景的精度要求
核心实现步骤
1. 配置依赖
// build.gradle
android {
defaultConfig {
ndk {abiFilters 'armeabi-v7a', 'arm64-v8a'}
}
}
dependencies {
implementation "androidx.room:room-ktx:2.5.0"
implementation "com.github.requery:sqlite-android:3.42.0" // 带向量扩展
}
2. 定义数据库实体
@Entity(tableName = "image_vectors")
data class ImageVector(
@PrimaryKey val id: String,
@ColumnInfo(name = "vector") val vector: FloatArray
)
@TypeConverters
class VectorConverter {
@TypeConverter
fun fromString(value: String): FloatArray {return value.split(",").map {it.toFloat() }.toFloatArray()}
@TypeConverter
fun toString(vector: FloatArray): String {return vector.joinToString(",")
}
}
3. 实现 DAO 查询
@Dao
interface VectorDao {
@Query("""
SELECT * FROM image_vectors
ORDER BY L2_DISTANCE(vector, :queryVector)
LIMIT 10
""")
suspend fun findSimilarVectors(queryVector: FloatArray): List<ImageVector>
}
性能优化实战
批量插入优化
发现直接插入 1000 条 128 维向量需要 12 秒,改进方案:
- 使用事务包裹
- 预编译语句
- 分批提交(每 200 条)
优化后代码:
suspend fun batchInsert(vectors: List<ImageVector>) {
database.runInTransaction {
val stmt = database.compileStatement("INSERT INTO image_vectors VALUES (?, ?)"
)
vectors.chunked(200).forEach { batch ->
batch.forEach { vector ->
stmt.bindString(1, vector.id)
stmt.bindString(2, vector.vector.joinToString(","))
stmt.executeInsert()
stmt.clearBindings()}
}
}
}
设备兼容性测试
在不同设备上测试 128 维向量的查询延迟:
| 设备型号 | Android 版本 | 平均延迟 |
|---|---|---|
| Pixel 3 | 12 | 28ms |
| 三星 A10s | 11 | 63ms |
| Redmi 9A | 10 | 82ms |
避坑指南
- ARMv7 兼容性:
- 必须添加
abiFilters 'armeabi-v7a' -
测试时要用 32 位设备验证
-
连接池耗尽:
- 每次查询后关闭 Cursor
-
使用
try-with-resources语法 -
向量归一化:
- 存储前先做 L2 归一化
- 否则余弦相似度计算会出错
思考与延伸
当处理 512 维以上向量时,可以考虑:
– 本地只存 ID 和低维向量
– 云端服务计算精确相似度
– 混合方案示例流程:
- 本地快速筛选 Top 50 候选
- 上传这些 ID 到云端
- 云端返回精确排序结果
这种架构在电商推荐系统中已有成功案例,您会如何设计这种混合方案?
正文完
