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!

相关推荐
张继雁13 小时前
30~50MPa数控高压清洗:前端分级过滤逻辑,抑制硬质磨粒对喷嘴冲蚀
大数据·数据库·人工智能·机器学习·创业创新
言乐613 小时前
PythonLOLM自动生成复盘报告模型
开发语言·前端·数据库·人工智能·python
倔强的石头_13 小时前
从 KStudio 到 KSQL Developer:国产数据库的 SQL 编辑器,已经卷到这个程度了
数据库
JavaEdge.13 小时前
设定索引方法和检索设置
数据库
小蒜学长13 小时前
基于Vue.js + Spring Boot的酒店客房预订系统设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端·酒店客房预订系统
墨者阳13 小时前
KingbaseES V9R2C16 深度实测:64位事务ID、内存防护、集群备份与坏块修复四大能力全解析
数据库
事圆则缓13 小时前
聊天与引用回复的 SQL 怎么设计
数据库·sql
APItesterCris13 小时前
告别反复手工查价:用 Open‑Claw 搭建商品监控与数据分析小工具
大数据·数据库·数据仓库·自动化
来福猿13 小时前
分布式锁 Redis 实现源码分析:SETNX、过期时间与可重入设计
数据库·redis·分布式
xiangyun6113 小时前
C++ list 模拟实现(一):手撕双向链表,从节点到迭代器
数据库·c++·算法·链表·stl·list