sqlite-vec一个SQLite3高效向量搜索扩展--JDBC环境使用

最近要用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代码如下:

java 复制代码
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!](https://github.com/asg017/sqlite-vec "GitHub - asg017/sqlite-vec: A vector search SQLite extension that runs anywhere!")

相关推荐
TDengine (老段)16 分钟前
TDengine 数学函数 FLOOR 用户手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
大气层煮月亮1 小时前
Oracle EBS ERP开发——报表生成Excel标准模板设计
数据库·oracle·excel
云和数据.ChenGuang1 小时前
达梦数据库的命名空间
数据库·oracle
三三木木七2 小时前
mysql拒绝连接
数据库·mysql
蹦跶的小羊羔2 小时前
sql数据库语法
数据库·sql
唐古乌梁海2 小时前
【mysql】InnoDB的聚簇索引和非聚簇索引工作原理
数据库·mysql
我变秃了也没变强2 小时前
pgsql配置密码复杂度策略
数据库·postgresql
PawSQL2 小时前
企业级SQL审核工具PawSQL介绍(1) - 六大核心能力
数据库·sql·oracle
幼稚园的山代王2 小时前
NoSQL介绍
数据库·nosql
猫林老师2 小时前
HarmonyOS线程模型与性能优化实战
数据库·分布式·harmonyos