最近要用SQLite3,之前放出来了SQLiteUtile工具,方便操作。今天发现AIGC方面,RAG知识库需要使用向量数据库,来存储知识信息。一般呢都是用mysql,但无奈的是mysql就是不让用。突然又发现SQLite3有向量库扩展组件,索性直接搞下来。用了一下。还可以。
SQLite3的向量库扩展extension,是个开源项目,名字叫sqlite-vec。目前我用到最新版本是0.1.5,配套使用的JDBC是SQLite3.47.0
使用需要注意的是,根据操作系统的不同,下载不同的Release版本库,一般linux要so的,windows要dll的。另外还要注意,下载64位版本的话,JDK、操作系统都得是配套的64位,否则会出现找不到模块的问题。
windows开发环境中,下载sqlite-vec-0.1.5-loadable-windows-x86_64.tar.gz。解压缩后得到vec0.dll。
在工程路径下创建一个extension文件夹,将vec0.dll放进去,便于程序运行时指定相对路径,访问到dll或者so。
demo代码如下:
package org.superx.demo.sqltools;
import org.sqlite.SQLiteConfig;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/***
*@title DemoSQLiteVec
*@description JDBC环境下SQLite扩展sqlite-vec的使用,向量数据库支持。这个示例工程,只能运行一次。二次运行请把./data/sqlite_vec.db删掉
*@author superX
*@version 1.0.0
*@create 2024/11/20 下午3:51
**/
public class DemoSQLiteVec {
public static void main(String[] args) {
// SQLite 连接字符串,建立一个向量数据库
String url = "jdbc:sqlite:.\\data\\sqlite_vec.db";
// 创建向量表的SQL语句
String createTableSQL = "create virtual table IF NOT EXISTS vec_examples using vec0(sample_embedding float[8])";
String insertDataSQL1 = "insert into vec_examples(rowid, sample_embedding) " +
"values" +
"(1, '[-0.200, 0.250, 0.341, -0.211, 0.645, 0.935, -0.316, -0.924]')," +
"(2, '[0.443, -0.501, 0.355, -0.771, 0.707, -0.708, -0.185, 0.362]')," +
"(3, '[0.716, -0.927, 0.134, 0.052, -0.669, 0.793, -0.634, -0.162]')," +
"(4, '[-0.710, 0.330, 0.656, 0.041, -0.990, 0.726, 0.385, -0.958]')";
String selectSQL = "select rowid,distance " +
"from vec_examples " +
"where sample_embedding match '[0.890, 0.544, 0.825, 0.961, 0.358, 0.0196, 0.521, 0.175]' " +
"order by distance limit 2";
//数据内容表,只能通过rowid来进行关联
String createTableSQL2 = "CREATE TABLE IF NOT EXISTS vec_metadata (rowid INTEGER PRIMARY KEY, describe TEXT, label TEXT)";
String insertDataSQL2 = "insert into vec_metadata(rowid, describe, label) " +
"values" +
"(1,'数据描述1','数据标签1')," +
"(2,'数据描述2','数据标签2')," +
"(3,'数据描述3','数据标签3')," +
"(4,'数据描述4','数据标签4')";
//数据内容表,只能通过rowid来进行关联查询。而且要注意,vec_examples的查询必须是独立的子查询,否则总是会报错
//[SQLITE_ERROR] SQL error or missing database (A LIMIT or 'k = ?' constraint is required on vec0 knn queries.)
String selectSQL2 = "SELECT ve.rowid, ve.sample_embedding, vm.describe, vm.label " +
"FROM (SELECT rowid, sample_embedding, distance " +
" FROM vec_examples " +
" WHERE sample_embedding MATCH '[0.890, 0.544, 0.825, 0.961, 0.358, 0.0196, 0.521, 0.175]' " +
" ORDER BY distance " +
" LIMIT 2) ve " +
"JOIN vec_metadata vm ON ve.rowid = vm.rowid ";
// 创建sqlite配置对象,启用加载扩展功能
SQLiteConfig config = new SQLiteConfig();
config.enableLoadExtension(true);
// 使用配置初始化数据库连接
try (Connection conn = DriverManager.getConnection(url, config.toProperties());
Statement stmt = conn.createStatement()) {
// 加载sqlite-vec扩展库,注意这里dll只能在windows下使用,如果是linux应该是so
stmt.execute("SELECT load_extension('./extension/vec0.dll')");
// 建表
stmt.execute(createTableSQL);
// 插入数据
stmt.execute(insertDataSQL1);
// 查询数据
ResultSet rs = stmt.executeQuery(selectSQL);
// 打印结果
while (rs.next()) {
int id = rs.getInt("rowid");
float a = rs.getFloat("distance");
System.out.println("Row ID: " + id + " distance: " + a);
}
//创建关联信息表、插入数据并查询
stmt.execute(createTableSQL2);
stmt.execute(insertDataSQL2);
ResultSet rs2 = stmt.executeQuery(selectSQL2);
while (rs2.next()) {
int id = rs2.getInt("rowid");
String describe = rs2.getString("describe");
String label = rs2.getString("label");
System.out.println("Row ID: " + id + " describe: " + describe + " label: " + label);
}
/* CMD打印信息结果:代表成功
Row ID: 2 distance: 2.3868737
Row ID: 1 distance: 2.389785
Row ID: 2 describe: 数据描述2 label: 数据标签2
Row ID: 1 describe: 数据描述1 label: 数据标签1
*/
} catch (Exception e) {
e.printStackTrace();
}
}
}
sqlite-vec创建的向量表限制还是比较多的,virtual table ,using vec0,里面不能随便增加字段。增加字段会报错。所以虚拟向量表是依靠rowid与其他表关联的。这一点要注意!!!
即一般我们做RAG应用时,会embeding文本成向量,然后把向量、文本成对儿存储,再用向量检索机制来寻找最相似的向量对应的文本。使用sqlite-vec的话,需要最少创建2张表。
1张虚拟向量表,只存储rowid和向量信息。另一张表,存储rowid和文本信息,或其它标签信息。检索时,需要进行双表关联检索才能得到想要的信息。如demo
另外需要注意的是,双表关联的语法也有要求。因为sqlite-vec实现是用KNN进行相似搜索,所以查询虚拟向量表时,必须是单表查询,且必须指定limit记录数。所以,关联操作必须以子查询方式进行关联。其它方式都会报错:
[SQLITE_ERROR] SQL error or missing database (A LIMIT or 'k = ?' constraint is required on vec0 knn queries.)
上面的坑为各位踩过了。demo只能运行一遍,因为第二遍运行insert时会报主键冲突,所以多次运行的话,运行前最好把./data/sqlite_vec.db删掉。
SQLite向量扩展开源项目链接,需要其它系统的链接库,自己下载即可:
GitHub - asg017/sqlite-vec: A vector search SQLite extension that runs anywhere!