SQLite-vec: vektorové rozšíření databáze SQLite

Dnes
Doba čtení: 27 minut

Sdílet

SQLite-vec
Autor: SQLite-vec, ZonerAI
Seznámíme se s vlastnostmi rozšíření databáze SQLite, které se jmenuje SQLite-vec. Umožňuje SQLite používat ve funkci vektorové databáze, zejména při zpracování přirozeného jazyka, rozpoznávání obrázků, detekci anomálií atd.

Obsah

1. SQLite-vec: vektorové rozšíření databáze SQLite

2. Koncept virtuálních tabulek v SQLite

3. Instalace rozšíření sqlite-vec

4. Základy práce s rozšířením sqlite-vec

5. Nové možnosti dotazu SELECT

6. Vizualizace výpočtů vzdáleností pro 2D vektory

7. Vytvoření a naplnění tabulky pro uložení 2D vektorů

8. Výpis obsahu tabulky se sloupcem s vektory

9. Vyhledávání na základě vzdálenosti vektorů

10. Tabulky obsahující jak sloupec s vektory, tak i sloupce s dalšími daty

11. Výpis hodnot podle vzdálenosti

12. Využití databáze SQLite s rozšířením SQLite-vec z Pythonu

13. Instalace balíčku sqllite-vec

14. Zjištění verze rozšíření SQLite-vec

15. Vytvoření virtuální tabulky s vektory

16. Naplnění tabulek s vektory

17. Dotazy: zjištění nejbližších vektorů

18. Repositář s demonstračními příklady

19. Předchozí články věnující se problematice vyhledávání podobných vektorů v databázích

20. Odkazy na Internetu

1. SQLite-vec: vektorové rozšíření databáze SQLite

V posledních několika letech můžeme sledovat poměrně výrazné a stále častější nasazování takzvaných vektorových databází. Jedná se (alespoň většinou) o specializované databáze, které umožňují ukládat vektory numerických hodnot (pevné délky) a především efektivně vyhledávat vektory podle jejich podobnosti (například se zadaným vzorem), přičemž podobností může být myšlena například vzdálenost koncových bodů vektorů v Eukleidovském prostoru, kosinus úhlu mezi vektory, výsledek skalárního součinu atd. Tyto operace se dnes používají v mnoha oblastech. Například se s nimi můžeme setkat při rozpoznávání a zpracování přirozeného jazyka (NLP – Native Language Processing), při rozpoznávání obrázků, rozpoznávání hlasů, detekci anomálií, ale i (a to zejména) v souvislosti s velkými jazykovými modely (LLM). K tomuto stále ještě aktuálnímu tématu se ještě vrátíme v samostatném článku.

Ovšem namísto specializovaných databází je možné si zvolit nějakou existující technologii, která se v praxi osvědčuje už desítky let. Na stránkách Roota jsme se již setkali s relační databází PostgreSQL, pro kterou vzniklo rozšíření nazvané pgvector. Toto rozšíření umožňuje efektivní ukládání vektorů do tabulek, ale zejména podporuje i vyhledávání vektorů na základě jejich podobnosti (navíc lze využít různé varianty indexů atd.). Ovšem nejedná se o jedinou klasickou relační databázi, která byla rozšířena i do oblasti vyhledávání podobných vektorů. Podobné rozšíření existuje i pro databázi SQLite; samotné rozšíření se jmenuje jednoduše SQLite-vec.

Dnes se seznámíme se základními vlastnostmi tohoto rozšíření a ve druhé části článku i s příklady použití SQLite-vec v aplikacích vytvářených v programovacím jazyku Python.

2. Koncept virtuálních tabulek v SQLite

V popisu vektorového rozšíření databáze SQLite se setkáme s termínem virtuální tabulka. Jedná se o potenciálně velmi užitečnou vlastnost databáze SQLite, na kterou se můžeme dívat ze dvou stran. Častější je pohled vývojáře, který SQLite používá jako běžnou SQL databázi. Z pohledu tohoto vývojáře se virtuální tabulka do značné míry podobá běžné tabulce (až na poněkud odlišný způsob její konstrukce). Typicky jsou podporovány všechny základní operace pro manipulaci s daty (insert, update, delete) i operace pro vyhledávání (query). Odlišný je však pohled vývojáře, který vytváří rozšíření pro databázi SQLite. Virtuální tabulka je totiž objektem s callback metodami, které se volají pro všechny databázové operace nad touto tabulkou. Jinými slovy to znamená, že například příkaz INSERT INTO virtuální_tabulka … bude interně převeden na volání metody příslušného (zaregistrovaného) objektu.

To, jak konkrétně bude virtuální tabulka uložena, je zcela v kompetenci příslušného objektu, tj. záleží na implementaci příslušného rozšíření. Konkrétně v případě vektorového rozšíření je každá virtuální tabulka interně uložena jako několik (konkrétně pět) běžných tabulek, což je ovšem do značné míry implementační detail.

3. Instalace rozšíření sqlite-vec

Rozšíření sqlite-vec není standardní součástí databáze SQLlite, takže je nutné ho nainstalovat zvlášť. V této kapitole si ukážeme, jakým způsobem je možné toto rozšíření přeložit do sdílené knihovny, která se poté načte do spuštěné konzole SQLite. K překladu postačují jen základní nástroje GCC nebo Clang a taktéž nástroj make.

Nejdříve je nutné nainstalovat balíček sqlite-devel (pozor, v názvu chybí trojka). Tento balíček obsahuje hlavičkové soubory použité při překladu sqlite-vec a taktéž sdílenou knihovnu libsqlite3.so:

/usr/include/sqlite3.h
/usr/include/sqlite3ext.h
/usr/lib/libsqlite3.so
/usr/lib/pkgconfig/sqlite3.pc
/usr/lib64/libsqlite3.so
/usr/lib64/pkgconfig/sqlite3.pc

Instalace tohoto balíčku vypadá na distribucích Linux s RPM následovně:

$ sudo dnf install sqlite-devel
 
Updating and loading repositories:
Repositories loaded.
Package                                      Arch        Version                                      Repository                    Size
Installing:
 sqlite-devel                                x86_64      3.47.2-5.fc42                                updates                  673.4 KiB
 
Transaction Summary:
 Installing:         1 package
 
Total size of inbound packages is 146 KiB. Need to download 146 KiB.
After this operation, 673 KiB extra will be used (install 673 KiB, remove 0 B).
Is this ok [y/N]: y
[1/1] sqlite-devel-0:3.47.2-5.fc42.x86_64                                                       100% | 617.3 KiB/s | 146.3 KiB |  00m00s
----------------------------------------------------------------------------------------------------------------------------------------
[1/1] Total                                                                                     100% | 143.4 KiB/s | 146.3 KiB |  00m01s
Running transaction
[1/3] Verify package files                                                                      100% | 166.0   B/s |   1.0   B |  00m00s
[2/3] Prepare transaction                                                                       100% |   4.0   B/s |   1.0   B |  00m00s
[3/3] Installing sqlite-devel-0:3.47.2-5.fc42.x86_64                                            100% |   1.4 MiB/s | 674.1 KiB |  00m00s
Complete!

Ve druhém kroku se provede naklonování repositáře se zdrojovými kódy rozšíření sqlite-vec:

$ git clone git@github.com:asg017/sqlite-vec.git
 
Cloning into 'sqlite-vec'...
remote: Enumerating objects: 2475, done.
remote: Counting objects: 100% (1033/1033), done.
remote: Compressing objects: 100% (234/234), done.
remote: Total 2475 (delta 873), reused 799 (delta 799), pack-reused 1442 (from 1)
Receiving objects: 100% (2475/2475), 955.37 KiB | 640.00 KiB/s, done.
Resolving deltas: 100% (1379/1379), done.

Přejdeme do adresáře s projektem:

$ cd sqlite-vec

Překlad se provede tímto příkazem:

$ make loadable static
 
mkdir -p dist
cc \
        -fPIC -shared \
        -Wall -Wextra \
        -Ivendor/ \
        -O3 \
        -lm \
        sqlite-vec.c -o dist/vec0.so
        ...
        ...
        ...
Poznámka: schválně nepoužívám make all, protože potřebujeme získat pouze statickou knihovnu a nikoli plnohodnotnou konzoli atd.

Po (doufejme že úspěšném) překladu by se v podadresáři dist měla nacházet jak sdílená knihovna vec0.so, tak i libsqlite_vec0.a (archiv s objektovým souborem vec0.o, ten ovšem nepoužijeme):

$ ls -l dist
total 360
-rw-r--r--. 1 ptisnovs ptisnovs 210222 Jan  8 16:50 libsqlite_vec0.a
-rwxr-xr-x. 1 ptisnovs ptisnovs 153120 Jan  8 16:50 vec0.so

4. Základy práce s rozšířením sqlite-vec

Ve chvíli, kdy máme k dispozici sdílenou nativní knihovnu s vektorovým rozšířením, si toto rozšíření můžeme otestovat. V této kapitole si ukážeme základy práce s vektorovým rozšířením; podrobnější popis bude uveden později.

Poznámka: ve všech dále uvedených příkladech počítám s tím, že se v aktuálním adresáři nachází i sdílená knihovna vec0.so. Samozřejmě se nejedná o ideální situaci využitelnou v produkčním nasazení; lepší bude nainstalovat sdílenou knihovnu například do adresářové struktury /opt/ atd.

Spustíme REPL databáze SQLite s předáním jména souboru, do kterého má být uloženo schéma i vlastní tabulky. Tento soubor je v případě potřeby vytvořen:

$ sqlite3 test1.db
 
SQLite version 3.47.2 2024-12-07 20:39:59
Enter ".help" for usage hints.

Příkazem .load se pokusíme o načtení rozšíření:

sqlite> .load ./vec0
Poznámka: tento příkaz se pokusí o nalezení souboru vec0.so, vec0.dylib nebo vec0.dll (podle použitého operačního systému) a pokud se to nepodaří, přidá ještě libvec0.*.

Vypíšeme si existující tabulky, přičemž by se měl vrátit prázdný seznam:

sqlite> .tables

Nyní vytvoříme novou virtuální tabulku nazvanou vec_examples, která obsahuje sloupec sample_embedding s osmiprvkovými vektory:

sqlite> create virtual table vec_examples using vec0(
  sample_embedding float[8]
);

Znovu se pokusíme o výpis existujících tabulek:

sqlite> .tables
 
vec_examples                  vec_examples_rowids
vec_examples_chunks           vec_examples_vector_chunks00
vec_examples_info

Z výpisu je patrné, že virtuální tabulka vec_examples je ve skutečnosti tvořena pěti dalšími tabulkami.

Jediná nová tabulka obsahující nějaké údaje se jmenuje vec_examples_info. Ta obsahuje metadata o verzi vektorového rozšíření:

sqlite> select * from vec_examples_info;
 
CREATE_VERSION|v0.1.7-alpha.2
CREATE_VERSION_MAJOR|0
CREATE_VERSION_MINOR|1
CREATE_VERSION_PATCH|7

5. Nové možnosti dotazu SELECT

Vektorové rozšíření nejenom že umožňuje do databáze ukládat vektory, ale navíc byl upraven i příkaz SELECT, který dokáže získat seznam nejbližších vektorů, tj. provádět klasickou operaci nazývanou vector similarity search. Jedná se o velmi užitečnou vlastnost, kterou si nyní ukážeme.

Nejdříve do virtuální tabulky vec_examples vložíme čtveřici osmiprvkových vektorů:

sqlite> insert into vec_examples(rowid, sample_embedding) values (1, '[1, 0, 0, 0, 0, 0, 0, 0]');
sqlite> insert into vec_examples(rowid, sample_embedding) values (2, '[0, 1, 0, 0, 0, 0, 0, 0]');
sqlite> insert into vec_examples(rowid, sample_embedding) values (3, '[0, 0, 1, 0, 0, 0, 0, 0]');
sqlite> insert into vec_examples(rowid, sample_embedding) values (4, '[1, 0, 1, 0, 0, 0, 0, 0]');

Nově je možné v příkazu SELECT použít pseudosloupec distance, například následujícím způsobem:

SELECT
  rowid,
  distance
FROM vec_examples
WHERE sample_embedding MATCH '[0, 0.5, 0.5, 0., 0., 0., 0., 0.]'
ORDER BY distance
LIMIT 4;

Tento příkaz by měl vrátit čtveřici hodnot – vzdáleností od vektoru, který byl zadán v příkazu SELECT v klauzuli WHERE MATCH:

3|0.70710676908493
2|0.70710676908493
4|1.22474491596222
1|1.22474491596222

Podobný příkaz, ovšem pro vektor, který je v databázi uložen:

SELECT
  rowid,
  distance
FROM vec_examples
WHERE sample_embedding MATCH '[1, 0., 0., 0., 0., 0., 0., 0.]'
ORDER BY distance
LIMIT 4;

Asi nebude velkým překvapením, že první nalezený vektor bude mít nulovou vzdálenost:

1|0.0
4|1.0
3|1.41421353816986
2|1.41421353816986

Pro čitelnější výsledky je vhodné zadat příkaz:

sqlite> .mode qbox

Zkusme si výše uvedené příkazy zadat znovu:

sqlite> select rowid, distance from vec_examples where sample_embedding match '[0, 0.5, 0.5, 0., 0., 0., 0., 0.]' order by distance limit 4;

Výsledky:

┌───────┬──────────────────┐
│ rowid │     distance     │
├───────┼──────────────────┤
│ 3     │ 0.70710676908493 │
│ 2     │ 0.70710676908493 │
│ 4     │ 1.22474491596222 │
│ 1     │ 1.22474491596222 │
└───────┴──────────────────┘

A:

sqlite> select rowid, distance from vec_examples where sample_embedding match '[1, 0., 0., 0., 0., 0., 0., 0.]' order by distance limit 4;

S výsledky:

┌───────┬──────────────────┐
│ rowid │     distance     │
├───────┼──────────────────┤
│ 1     │ 0.0              │
│ 4     │ 1.0              │
│ 3     │ 1.41421353816986 │
│ 2     │ 1.41421353816986 │
└───────┴──────────────────┘

6. Vizualizace výpočtů vzdáleností pro 2D vektory

Na 2D vektory se můžeme (i když to není zcela přesné) dívat jako na koncové souřadnice orientovaných šipek vycházejících z počátku kartézské soustavy souřadnic. V případě, že si tyto souřadnice vykreslíme do plochy, získáme například následující graf (do kterého jsem doplnil numerické souřadnice u vybraných koncových bodů):

                                       │ y
                                       │
                                       │
                                       │
                                       │                [5,5]
                     o       o         │          o   o   o
                                       │          o   o   o
                         o             │          o   o   o
                      [-4, 3]          │
                                       │
─────────────────────────────────────[0,0]──────────────────────────────────────
                                       │                                       x
                                       │              o
                                       │
                                       │          o       o
                                       │                [5,-5]
                                       │
                                       │
                                       │
                                       │

Tento diagram obsahuje následující koncové souřadnice vektorů (použijeme je později v reálné databázi):

Souřadnice
[-5, 5]
[-4, 3]
[-3, 5]
[ 3, –5]
[ 4, –3]
[ 5, –5]
[ 3, 3]
[ 3, 4]
[ 3, 5]
[ 4, 3]
[ 4, 4]
[ 4, 5]
[ 5, 3]
[ 5, 4]
[ 5, 5]

7. Vytvoření a naplnění tabulky pro uložení 2D vektorů

Podívejme se nyní podrobněji na způsob využití rozšíření sqlite-vec. Nejdříve vytvoříme virtuální tabulku nazvanou v2, která bude obsahovat jediný explicitně zadaný sloupec s názvem embedding. Do tohoto sloupce se budou ukládat dvouprvkové vektory, přičemž každý prvek bude typu float (numerická hodnota s plovoucí řádovou čárkou):

CREATE virtual TABLE v2 USING vec0(
  embedding float[2]
);

Následně tabulku naplníme patnácti záznamy (vektory). Souřadnice těchto vektorů odpovídají diagramu, který byl uveden v předchozí kapitole:

INSERT INTO v2(rowid, embedding) VALUES(1, '[-5,  5]');
INSERT INTO v2(rowid, embedding) VALUES(2, '[-4,  3]');
INSERT INTO v2(rowid, embedding) VALUES(3, '[-3,  5]');
INSERT INTO v2(rowid, embedding) VALUES(4, '[ 3, -5]');
INSERT INTO v2(rowid, embedding) VALUES(5, '[ 4, -3]');
INSERT INTO v2(rowid, embedding) VALUES(6, '[ 5, -5]');
INSERT INTO v2(rowid, embedding) VALUES(7, '[ 3,  3]');
INSERT INTO v2(rowid, embedding) VALUES(8, '[ 3,  4]');
INSERT INTO v2(rowid, embedding) VALUES(9, '[ 3,  5]');
INSERT INTO v2(rowid, embedding) VALUES(10, '[ 4,  3]');
INSERT INTO v2(rowid, embedding) VALUES(11, '[ 4,  4]');
INSERT INTO v2(rowid, embedding) VALUES(12, '[ 4,  5]');
INSERT INTO v2(rowid, embedding) VALUES(13, '[ 5,  3]');
INSERT INTO v2(rowid, embedding) VALUES(14, '[ 5,  4]');
INSERT INTO v2(rowid, embedding) VALUES(15, '[ 5,  5]');

Pro jistotu si ověříme, že tabulka v2 skutečně obsahuje patnáct záznamů:

sqlite> select count(*) from v2;
15

8. Výpis obsahu tabulky se sloupcem s vektory

Pokusme se vypsat všech patnáct záznamů, které jsou v tabulce v2 uloženy. Nastavíme hezčí (nebo „hezčí“) způsob výpisu příkazem .mode a poté spustíme standardní dotaz select:

sqlite> .mode qbox
 
sqlite> select * from v2;

Z výpisu je patrné, že tabulka ve skutečnosti obsahuje ještě sloupec rowid, který jsme sice při definici tabulky nepožadovali, ale který byl doplněn automaticky. A taktéž je patrné, že se obsah vektorů zobrazil v hexadecimální (interní) podobě; každý vektor jako osmice bajtů:

┌───────┬─────────────────────┐
│ rowid │      embedding      │
├───────┼─────────────────────┤
│ 1     │ x'0000a0c00000a040' │
│ 2     │ x'000080c000004040' │
│ 3     │ x'000040c00000a040' │
│ 4     │ x'000040400000a0c0' │
│ 5     │ x'00008040000040c0' │
│ 6     │ x'0000a0400000a0c0' │
│ 7     │ x'0000404000004040' │
│ 8     │ x'0000404000008040' │
│ 9     │ x'000040400000a040' │
│ 10    │ x'0000804000004040' │
│ 11    │ x'0000804000008040' │
│ 12    │ x'000080400000a040' │
│ 13    │ x'0000a04000004040' │
│ 14    │ x'0000a04000008040' │
│ 15    │ x'0000a0400000a040' │
└───────┴─────────────────────┘

Abychom získali vektory v čitelné podobě, musíme použít malý trik – necháme si obsah vektorů převést na JSON, tedy v tomto případě konkrétně na seznam s dvojicí numerických hodnot:

sqlite> select rowid, vec_to_json(embedding) from v2;

Nyní bude výpis snadno čitelný:

┌───────┬────────────────────────┐
│ rowid │ vec_to_json(embedding) │
├───────┼────────────────────────┤
│ 1     │ '[-5.000000,5.000000]' │
│ 2     │ '[-4.000000,3.000000]' │
│ 3     │ '[-3.000000,5.000000]' │
│ 4     │ '[3.000000,-5.000000]' │
│ 5     │ '[4.000000,-3.000000]' │
│ 6     │ '[5.000000,-5.000000]' │
│ 7     │ '[3.000000,3.000000]'  │
│ 8     │ '[3.000000,4.000000]'  │
│ 9     │ '[3.000000,5.000000]'  │
│ 10    │ '[4.000000,3.000000]'  │
│ 11    │ '[4.000000,4.000000]'  │
│ 12    │ '[4.000000,5.000000]'  │
│ 13    │ '[5.000000,3.000000]'  │
│ 14    │ '[5.000000,4.000000]'  │
│ 15    │ '[5.000000,5.000000]'  │
└───────┴────────────────────────┘

9. Vyhledávání na základě vzdálenosti vektorů

Nyní se pokusme vyhledat tři nejbližší vektory k vektoru [-4, 4]:

SELECT rowid, distance FROM v2 WHERE embedding MATCH '[-4, 4]' ORDER BY distance LIMIT 3;

Výsledky by měly vypadat následovně (druhé dvě hodnoty odpovídají mocnině dvou, tedy vzdálenosti bodů po úhlopříčce):

┌───────┬──────────────────┐
│ rowid │     distance     │
├───────┼──────────────────┤
│ 2     │ 1.0              │
│ 3     │ 1.41421353816986 │
│ 1     │ 1.41421353816986 │
└───────┴──────────────────┘

Což si pochopitelně můžeme vizualizovat v rovině (hvězdičkou je naznačen vektor z podmínky, kolečkem vektory vrácené jako výsledek dotazu a tečkou ostatní vektory, které neodpovídají dotazu):

                                       │ y
                                       │
                                       │
                                       │
                                       │
                     o       o         │          .   .   .
                         *             │          .   .   .
                         o             │          .   .   .
                                       │
                                       │
─────────────────────────────────────[0,0]──────────────────────────────────────
                                       │                                       x
                                       │
                                       │              .
                                       │
                                       │          .       .
                                       │
                                       │
                                       │
                                       │

Podobně můžeme získat pět vektorů, které jsou nejpodobnější vektoru [4, 4]:

SELECT rowid, distance FROM v2 WHERE embedding MATCH '[4, 4]' ORDER BY distance LIMIT 5;

Získané výsledky:

┌───────┬──────────┐
│ rowid │ distance │
├───────┼──────────┤
│ 11    │ 0.0      │
│ 14    │ 1.0      │
│ 12    │ 1.0      │
│ 10    │ 1.0      │
│ 8     │ 1.0      │
└───────┴──────────┘

Výsledných pět vrácených vektorů si opět zobrazíme v 2D rovině (první bod/vektor je totožný se zadaným vektorem):

                                       │ y
                                       │
                                       │
                                       │
                                       │
                     .       .         │          .   o   .
                         .             │          o   *   o
                         .             │          .   o   .
                                       │
                                       │
─────────────────────────────────────[0,0]──────────────────────────────────────
                                       │                                       x
                                       │
                                       │              .
                                       │
                                       │          .       .
                                       │
                                       │
                                       │
                                       │

Tři vektory nejpodobnější vektoru [3, 3]:

SELECT rowid, distance FROM v2 WHERE embedding MATCH '[3, 3]' ORDER BY distance LIMIT 3;

Výsledky:

┌───────┬──────────┐
│ rowid │ distance │
├───────┼──────────┤
│ 7     │ 0.0      │
│ 10    │ 1.0      │
│ 8     │ 1.0      │
└───────┴──────────┘

V 2D rovině budou výsledky vypadat takto:

                                       │ y
                                       │
                                       │
                                       │
                                       │
                     .       .         │          .   .   .
                         .             │          o   .   .
                         .             │          *   o   .
                                       │
                                       │
─────────────────────────────────────[0,0]──────────────────────────────────────
                                       │                                       x
                                       │
                                       │              .
                                       │
                                       │          .       .
                                       │
                                       │
                                       │
                                       │

A konečně vzdálenosti nejbližších deseti vektorů:

sqlite> SELECT rowid, distance FROM v2 WHERE embedding MATCH '[3, 3]' and k=10;

S výsledky:

┌───────┬──────────────────┐
│ rowid │     distance     │
├───────┼──────────────────┤
│ 7     │ 0.0              │
│ 10    │ 1.0              │
│ 8     │ 1.0              │
│ 11    │ 1.41421353816986 │
│ 13    │ 2.0              │
│ 9     │ 2.0              │
│ 14    │ 2.2360680103302  │
│ 12    │ 2.2360680103302  │
│ 15    │ 2.82842707633972 │
│ 5     │ 6.08276271820068 │
└───────┴──────────────────┘

10. Tabulky obsahující jak sloupec s vektory, tak i sloupce s dalšími daty

Samozřejmě je možné, aby virtuální tabulka obsahující sloupec s vektory obsahovala i další sloupce, například s původními texty (před embeddingem) atd. Ukažme si tuto vlastnost na příkladu tabulky pojmenované v3, která kromě sloupce embedding s vektory obsahuje i sloupec name, jenž může obsahovat běžný text:

CREATE virtual TABLE v3 USING vec0(
  embedding float[2],
  name text
);

Tabulku naplníme našimi patnácti vektory a navíc ještě doplníme nějaké texty:

INSERT INTO v3(rowid, embedding, name) VALUES(1, '[-5,  5]', 'one');
INSERT INTO v3(rowid, embedding, name) VALUES(2, '[-4,  3]', 'two');
INSERT INTO v3(rowid, embedding, name) VALUES(3, '[-3,  5]', 'three');
INSERT INTO v3(rowid, embedding, name) VALUES(4, '[ 3, -5]', 'four');
INSERT INTO v3(rowid, embedding, name) VALUES(5, '[ 4, -3]', 'five');
INSERT INTO v3(rowid, embedding, name) VALUES(6, '[ 5, -5]', 'six');
INSERT INTO v3(rowid, embedding, name) VALUES(7, '[ 3,  3]', 'seven');
INSERT INTO v3(rowid, embedding, name) VALUES(8, '[ 3,  4]', 'eight');
INSERT INTO v3(rowid, embedding, name) VALUES(9, '[ 3,  5]', 'nine');
INSERT INTO v3(rowid, embedding, name) VALUES(10, '[ 4,  3]', 'ten');
INSERT INTO v3(rowid, embedding, name) VALUES(11, '[ 4,  4]', 'evelen');
INSERT INTO v3(rowid, embedding, name) VALUES(12, '[ 4,  5]', 'twelve');
INSERT INTO v3(rowid, embedding, name) VALUES(13, '[ 5,  3]', 'thirteen');
INSERT INTO v3(rowid, embedding, name) VALUES(14, '[ 5,  4]', 'fourteen');
INSERT INTO v3(rowid, embedding, name) VALUES(15, '[ 5,  5]', 'fifteen');

11. Výpis hodnot podle vzdálenosti

V tomto okamžiku může dotaz (podle očekávání) obsahovat i pokyn k výpisu jak vzdálenosti, tak i obsahu získaného ze sloupce s textem:

sqlite> .mode qbox
sqlite> SELECT rowid, distance, name FROM v3 WHERE embedding MATCH '[-4, 4]' ORDER BY distance LIMIT 10;

Ze zobrazených výsledků je patrné, že vše pracuje podle očekávání, tj. vypíšou se jak vypočtené vzdálenosti, tak i obsahy sloupce name:

┌───────┬──────────────────┬────────────┐
│ rowid │     distance     │    name    │
├───────┼──────────────────┼────────────┤
│ 2     │ 1.0              │ 'two'      │
│ 3     │ 1.41421353816986 │ 'three'    │
│ 1     │ 1.41421353816986 │ 'one'      │
│ 8     │ 7.0              │ 'eight'    │
│ 9     │ 7.07106781005859 │ 'nine'     │
│ 7     │ 7.07106781005859 │ 'seven'    │
│ 11    │ 8.0              │ 'evelen'   │
│ 12    │ 8.06225776672363 │ 'twelve'   │
│ 10    │ 8.06225776672363 │ 'ten'      │
│ 14    │ 9.0              │ 'fourteen' │
└───────┴──────────────────┴────────────┘

12. Využití databáze SQLite s rozšířením SQLite-vec z Pythonu

Ve druhé části dnešního článku si ukážeme základní způsoby využití rozšíření SQLite-vec z programovacího jazyka Python. Demonstrační příklady budou postaveny nad balíčkem sqllite-vec, který však (což je logické) ke své činnosti vyžaduje i balíček sqlite3, který je v současnosti součástí standardní knihovny Pythonu (viz sqlite3 – DB-API 2.0 interface for SQLite databases. Oba balíčky zajišťují jednoduché načtení rozšíření sqlite-vec, takže se programátor nemusí příliš starat o to, kde je vlastně umístěna příslušná sdílená nativní knihovna. A současně jsou k dispozici i pomocné funkce zajišťující převod seznamů a popř. i n-dimenzionálních polí (ndarray) na vektory. Tyto konverzní funkce se používají jak při manipulaci s daty uloženými v databázi (insert, update, delete), tak i při provádění dotazů (query).

13. Instalace balíčku sqllite-vec

Druhá část tohoto článku je zaměřena na praktické ukázky použití knihovny s vektorovým rozšířením SQLlite. Musíme si tedy připravit projekt v Pythonu a následně do něj knihovnu sqlite-vec přidat formou přímé závislosti (dependency). Pro vytvoření projektu použijeme buď nástroj PDM – viz též PDM: moderní správce balíčků a virtuálních prostředí Pythonu nebo (což je v současnosti výhodnější) nástroj uv:

$ uv init test-sqlite-vec
 
Initialized project `test-sqlite-vec`

Následně do projektu přidáme nový balíček sqlite-vec, který bude nainstalován do virtuálního prostředí Pythonu:

$ uv add sqlite-vec
 
Using CPython 3.13.9 interpreter at: /usr/bin/python3.13
Creating virtual environment at: .venv
Resolved 2 packages in 258ms
Prepared 1 package in 156ms
Installed 1 package in 3ms
 + sqlite-vec==0.1.6

Výsledný projektový soubor bude vypadat takto:

[project]
name = "test-sqlite-vec"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
    "sqlite-vec>=0.1.6",
]

Od této chvíle je nutné všechny dále uvedené příklady spouštět takto:

$ uv run jméno_skriptu

Dále si můžete doinstalovat – i když to dnes není zapotřebí – i užitečný balíček sqlite-utils, který vlastně slouží jako manažer celého ekosystému postaveného nad SQLite:

$ uv add sqlite-utils
 
Resolved 12 packages in 363ms
Prepared 9 packages in 428ms
Installed 9 packages in 22ms
 + click==8.3.1
 + click-default-group==1.2.4
 + pip==25.3
 + pluggy==1.6.0
 + python-dateutil==2.9.0.post0
 + six==1.17.0
 + sqlite-fts4==1.0.3
 + sqlite-utils==3.39
 + tabulate==0.9.0

Jak se tento balíček používá? Jedná se o nový příkaz, kterým lze například doinstalovat další rozšíření knihovny SQLite atd. Pro zajímavost si uveďme příklad jeho použití:

$ uv run sqlite-utils install sqlite-utils-sqlite-vec
 
Collecting sqlite-utils-sqlite-vec
  Downloading sqlite_utils_sqlite_vec-0.1.6-py3-none-any.whl.metadata (275 bytes)
Requirement already satisfied: sqlite-utils in ./.venv/lib64/python3.13/site-packages (from sqlite-utils-sqlite-vec) (3.39)
Requirement already satisfied: sqlite-vec==0.1.6 in ./.venv/lib64/python3.13/site-packages (from sqlite-utils-sqlite-vec) (0.1.6)
Requirement already satisfied: sqlite-fts4 in ./.venv/lib64/python3.13/site-packages (from sqlite-utils->sqlite-utils-sqlite-vec) (1.0.3)
Requirement already satisfied: click>=8.3.1 in ./.venv/lib64/python3.13/site-packages (from sqlite-utils->sqlite-utils-sqlite-vec) (8.3.1)
Requirement already satisfied: click-default-group>=1.2.3 in ./.venv/lib64/python3.13/site-packages (from sqlite-utils->sqlite-utils-sqlite-vec) (1.2.4)
Requirement already satisfied: tabulate in ./.venv/lib64/python3.13/site-packages (from sqlite-utils->sqlite-utils-sqlite-vec) (0.9.0)
Requirement already satisfied: python-dateutil in ./.venv/lib64/python3.13/site-packages (from sqlite-utils->sqlite-utils-sqlite-vec) (2.9.0.post0)
Requirement already satisfied: pluggy in ./.venv/lib64/python3.13/site-packages (from sqlite-utils->sqlite-utils-sqlite-vec) (1.6.0)
Requirement already satisfied: pip in ./.venv/lib64/python3.13/site-packages (from sqlite-utils->sqlite-utils-sqlite-vec) (25.3)
Requirement already satisfied: six>=1.5 in ./.venv/lib64/python3.13/site-packages (from python-dateutil->sqlite-utils->sqlite-utils-sqlite-vec) (1.17.0)
Downloading sqlite_utils_sqlite_vec-0.1.6-py3-none-any.whl (2.3 kB)
Installing collected packages: sqlite-utils-sqlite-vec
Successfully installed sqlite-utils-sqlite-vec-0.1.6

Výsledný projektový soubor bude vypadat takto:

[project]
name = "test-sqlite-vec"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
    "sqlite-utils>=3.39",
    "sqlite-vec>=0.1.6",
]

14. Zjištění verze rozšíření SQLite-vec

Nyní, když již máme nainstalovány všechny potřebné balíčky Pythonu, si můžeme vyzkoušet, jakým způsobem se s balíčkem sqlite-vecpracuje. V dnešním prvním Pythonovském demonstračním příkladu je nejdříve provedeno připojení k databázi uložené v souboru v0.db. Pokud tato databáze a/nebo soubor neexistuje, dojde k jejich vytvoření:

db = sqlite3.connect("v0.db")

Následně načteme vektorové rozšíření. Tato operace by měla proběhnout korektně, protože nativní sdílená knihovna je součástí virtuálního prostředí Pythonu:

db.enable_load_extension(True)
sqlite_vec.load(db)
db.enable_load_extension(False)

V posledním kroku si necháme vypsat verzi rozšíření:

vec_version, = db.execute("select vec_version()").fetchone()
print(f"vec_version={vec_version}")

Pokud byly dodrženy všechny kroky uvedené v předchozí kapitole, měl by tento příklad vypsat:

vec_version=v0.1.6

Následuje výpis celého zdrojového kódu tohoto demonstračního příkladu:

# Knihovna SQLite s rozšířením SQLite-vec
#
# - připojení k databázi uložené v souboru
# - databáze je v případě potřeby vytvořena (nový soubor)
# - načtení rozšíření SQLite-vec
# - tisk verze rozšíření SQLite-vec
 
import sqlite3
import sqlite_vec
 
# připojení k databázi uložené v souboru
# v případě potřeby je databáze vytvořena
db = sqlite3.connect("v0.db")
 
# načtení rozšíření SQLite-vec
db.enable_load_extension(True)
sqlite_vec.load(db)
db.enable_load_extension(False)
 
# tisk verze rozšíření SQLite-vec
vec_version, = db.execute("select vec_version()").fetchone()
print(f"vec_version={vec_version}")

SQLite navíc umožňuje vytvoření databáze pouze v operační paměti, tj. bez toho, aby se databáze ukládala do reálného souboru. Pro tento účel je nutné při připojování k databází použít „magické“ jméno :memory::

db = sqlite3.connect(":memory:")

Skript po této úpravě bude vypadat následovně:

# Knihovna SQLite s rozšířením SQLite-vec
#
# - připojení k databázi uložené v paměti
# - databáze je (nutně) vždy vytvořena
# - načtení rozšíření SQLite-vec
# - tisk verze rozšíření SQLite-vec
 
import sqlite3
import sqlite_vec
 
# připojení k databázi uložené v paměti
# databáze je vždy vytvořena
db = sqlite3.connect(":memory:")
 
# načtení rozšíření SQLite-vec
db.enable_load_extension(True)
sqlite_vec.load(db)
db.enable_load_extension(False)
 
# tisk verze rozšíření SQLite-vec
vec_version, = db.execute("select vec_version()").fetchone()
print(f"vec_version={vec_version}")

Výsledkem však bude naprosto stejná zpráva s informací o verzi vektorového rozšíření:

vec_version=v0.1.6

15. Vytvoření virtuální tabulky s vektory

V dalším kroku pochopitelně budeme muset vytvořit tabulku, která obsahuje sloupec nebo sloupce určené pro uložení vektorů (pochopitelně s předem známým počtem prvků). Je přitom nutné, aby již bylo načteno vektorové rozšíření, což jsme si ukázali v předchozí kapitole.

Při práci s relačními databázemi v Pythonu se typicky postupuje takovým způsobem, že se nejdříve získá kurzor a další příkazy pro manipulaci s daty nebo pro dotazy se provádí přes tento objekt. Ovšem standardní balíček sqlite3 nabízí v tomto případě „zkratku“, protože příkazy pro manipulaci s daty (ale i například pro vytvoření tabulky atd.) lze provádět přímo nad objektem, který získáme po připojení k databázi.

Celý postup, při kterém vytvoříme virtuální tabulku, tedy může vypadat následovně:

db = sqlite3.connect("v1.db")
 
TABLE_STATEMENT = """
    CREATE virtual TABLE v1 USING vec0(
        embedding float[2]
    );
"""
 
db.execute(TABLE_STATEMENT)
 
db.commit()
db.close()

Následuje úplný zdrojový kód dnešního třetího demonstračního příkladu napsaného v Pythonu:

# Knihovna SQLite s rozšířením SQLite-vec
#
# - připojení k databázi uložené v souboru
# - databáze je v případě potřeby vytvořena
# - načtení rozšíření SQLite-vec
# - vytvoření virtuální tabulky s jedním sloupcem
# - nepoužívá se kurzor (zkrácený zápis)
 
import sqlite3
import sqlite_vec
 
# připojení k databázi uložené v souboru
# v případě potřeby je databáze vytvořena
db = sqlite3.connect("v1.db")
 
# načtení rozšíření SQLite-vec
db.enable_load_extension(True)
sqlite_vec.load(db)
db.enable_load_extension(False)
 
TABLE_STATEMENT = """
    CREATE virtual TABLE v1 USING vec0(
        embedding float[2]
    );
"""
 
# vytvoření virtuální tabulky
result = db.execute(TABLE_STATEMENT)
print(result)
 
db.commit()
db.close()

V praxi je však výhodnější se explicitnímu odpojení od databáze vyhnout (kvůli nutnosti zachytávání výjimek atd.) a použít namísto toho context manager. Zápis je čitelnější, kratší a navíc i bezpečnější (databázi zavře i při vzniku výjimky):

with sqlite3.connect("v1.db") as db:
    TABLE_STATEMENT = """
        CREATE virtual TABLE v1 USING vec0(
            embedding float[2]
        );
    """
 
    db.execute(TABLE_STATEMENT)
 
    db.commit()

Výsledná podoba demonstračního příkladu:

# Knihovna SQLite s rozšířením SQLite-vec
#
# - připojení k databázi uložené v souboru
# - databáze je v případě potřeby vytvořena
# - načtení rozšíření SQLite-vec
# - vytvoření virtuální tabulky s jedním sloupcem
# - využití kontext manažeru
# - nepoužívá se kurzor (zkrácený zápis)
 
import sqlite3
import sqlite_vec
 
# připojení k databázi uložené v souboru
# v případě potřeby je databáze vytvořena
with sqlite3.connect("v1.db") as db:
    # načtení rozšíření SQLite-vec
    db.enable_load_extension(True)
    sqlite_vec.load(db)
    db.enable_load_extension(False)
 
    TABLE_STATEMENT = """
        CREATE virtual TABLE v1 USING vec0(
            embedding float[2]
        );
    """
 
    # vytvoření virtuální tabulky
    result = db.execute(TABLE_STATEMENT)
    print(result)
 
    db.commit()

16. Naplnění tabulek s vektory

Tabulku, resp. přesněji řečeno virtuální tabulku, která byla vytvořena skripty uvedenými v předchozí kapitole, je pochopitelně možné naplnit záznamy, které obsahují dvouprvkové vektory. V knihovně sqlite_vec je mj. dostupná i funkce nazvaná serialize_float32, která dokáže převést obsah běžného Pythonovského seznamu na vektor, jenž je možné uložit do databáze. Můžeme tedy provést například tuto operaci:

INSERT_STATEMENT = "INSERT INTO v2(embedding) VALUES(?)"
 
db.execute(INSERT_STATEMENT, [sqlite_vec.serialize_float32([1, 2])])

V tomto demonstračním příkladu opět používáme „zkratku“, protože voláme přímo metodu execute nad objektem získaným po připojení do databáze. V případě, že se použije odlišná databáze (což zde nemá smysl) by se musel vytvořit kurzor:

# Knihovna SQLite s rozšířením SQLite-vec
#
# - připojení k databázi uložené v souboru
# - databáze je v případě potřeby vytvořena
# - načtení rozšíření SQLite-vec
# - vytvoření virtuální tabulky
# - naplnění tabulky několika vektory
 
import sqlite3
import sqlite_vec
 
# připojení k databázi uložené v souboru
# v případě potřeby je databáze vytvořena
with sqlite3.connect("v2.db") as db:
    # načtení rozšíření SQLite-vec
    db.enable_load_extension(True)
    sqlite_vec.load(db)
    db.enable_load_extension(False)
 
    TABLE_STATEMENT = """
        CREATE virtual TABLE v2 USING vec0(
            embedding float[2]
        );
    """
 
    db.execute(TABLE_STATEMENT)
 
    INSERT_STATEMENT = "INSERT INTO v2(embedding) VALUES(?)"
 
    db.execute(INSERT_STATEMENT, [sqlite_vec.serialize_float32([1, 2])])
    db.execute(INSERT_STATEMENT, [sqlite_vec.serialize_float32([1, 2])])
    db.execute(INSERT_STATEMENT, [sqlite_vec.serialize_float32([1, 2])])
 
    db.commit()

Výše uvedený demonstrační příklad nyní nepatrně upravíme, a to tak, abychom do (nové) virtuální tabulky uložili všech patnáct vektorů v 2D, které byly použity v úvodní části dnešního článku. Vektory jsou původně reprezentovány seznamem seznamů a do tabulky jsou vloženy ve smyčce (což ovšem není nejrychlejší způsob):

# Knihovna SQLite s rozšířením SQLite-vec
#
# - připojení k databázi uložené v souboru
# - databáze je v případě potřeby vytvořena
# - načtení rozšíření SQLite-vec
# - vytvoření virtuální tabulky
# - naplnění tabulky patnácti vektory
 
import sqlite3
import sqlite_vec
 
# připojení k databázi uložené v souboru
# v případě potřeby je databáze vytvořena
with sqlite3.connect("v2.db") as db:
    # načtení rozšíření SQLite-vec
    db.enable_load_extension(True)
    sqlite_vec.load(db)
    db.enable_load_extension(False)
 
    TABLE_STATEMENT = """
    CREATE virtual TABLE v2 USING vec0(
        embedding float[2]
    );
    """
 
    db.execute(TABLE_STATEMENT)
 
    INSERT_STATEMENT = "INSERT INTO v2(rowid, embedding) VALUES(?, ?)"
 
    data_to_insert = [
        [1, [-5,  5]],
        [2, [-4,  3]],
        [3, [-3,  5]],
        [4, [ 3, -5]],
        [5, [ 4, -3]],
        [6, [ 5, -5]],
        [7, [ 3,  3]],
        [8, [ 3,  4]],
        [9, [ 3,  5]],
        [10, [ 4,  3]],
        [11, [ 4,  4]],
        [12, [ 4,  5]],
        [13, [ 5,  3]],
        [14, [ 5,  4]],
        [15, [ 5,  5]],
    ]
 
    for data in data_to_insert:
        print(f"Inserting {data[1]}")
        db.execute(INSERT_STATEMENT, [data[0], sqlite_vec.serialize_float32(data[1])])
 
    db.commit()

17. Dotazy: zjištění nejbližších vektorů

V poslední dvojici demonstračních příkladů nejenže vytvoříme virtuální tabulku a naplníme ji daty (vektory), ale taktéž provedeme dotaz, který zjistí tři nejbližší vektory k vektoru zadanému. Se znalostmi z předchozích kapitol by měl být tento příklad snadno pochopitelný:

# Knihovna SQLite s rozšířením SQLite-vec
#
# - připojení k databázi uložené v paměti
# - načtení rozšíření SQLite-vec
# - vytvoření virtuální tabulky
# - naplnění tabulky patnácti vektory
# - nalezení tří vektorů nejbližích k [-4, 4]
 
import sqlite3
import sqlite_vec
 
# připojení k databázi uložené v souboru
# v případě potřeby je databáze vytvořena
with sqlite3.connect(":memory:") as db:
    # načtení rozšíření SQLite-vec
    db.enable_load_extension(True)
    sqlite_vec.load(db)
    db.enable_load_extension(False)
 
    TABLE_STATEMENT = """
    CREATE virtual TABLE v2 USING vec0(
        embedding float[2]
    );
    """
 
    db.execute(TABLE_STATEMENT)
 
    INSERT_STATEMENT = "INSERT INTO v2(rowid, embedding) VALUES(?, ?)"
 
    data_to_insert = [
        [1, [-5,  5]],
        [2, [-4,  3]],
        [3, [-3,  5]],
        [4, [ 3, -5]],
        [5, [ 4, -3]],
        [6, [ 5, -5]],
        [7, [ 3,  3]],
        [8, [ 3,  4]],
        [9, [ 3,  5]],
        [10, [ 4,  3]],
        [11, [ 4,  4]],
        [12, [ 4,  5]],
        [13, [ 5,  3]],
        [14, [ 5,  4]],
        [15, [ 5,  5]],
    ]
 
    for data in data_to_insert:
        print(f"Inserting {data[1]}")
        db.execute(INSERT_STATEMENT, [data[0], sqlite_vec.serialize_float32(data[1])])
 
    db.commit()
 
    SELECT_STATEMENT = """
        SELECT
          rowid,
          distance
        FROM v2
        WHERE embedding MATCH ?
        ORDER BY distance
        LIMIT 3
    """
 
    print()
    print("Finding vectors close to [-4, 4]")
    results = db.execute(SELECT_STATEMENT, [sqlite_vec.serialize_float32([-4, 4])]).fetchall()
 
    for result in results:
        print(result)

V dnešním posledním demonstračním příkladu je naznačeno, že i hodnota předaná v klauzuli LIMIT je volitelná, resp. že se jedná o parametr, který může být databázi předán při pokládání dotazu:

Školení Zabbix

# Knihovna SQLite s rozšířením SQLite-vec
#
# - připojení k databázi uložené v paměti
# - načtení rozšíření SQLite-vec
# - vytvoření virtuální tabulky
# - naplnění tabulky patnácti vektory
# - nalezení pěti vektorů nejbližích k [4, 4]
 
import sqlite3
import sqlite_vec
 
# připojení k databázi uložené v souboru
# v případě potřeby je databáze vytvořena
with sqlite3.connect(":memory:") as db:
    # načtení rozšíření SQLite-vec
    db.enable_load_extension(True)
    sqlite_vec.load(db)
    db.enable_load_extension(False)
 
    TABLE_STATEMENT = """
    CREATE virtual TABLE v2 USING vec0(
        embedding float[2]
    );
    """
 
    db.execute(TABLE_STATEMENT)
 
    INSERT_STATEMENT = "INSERT INTO v2(rowid, embedding) VALUES(?, ?)"
 
    data_to_insert = [
        [1, [-5,  5]],
        [2, [-4,  3]],
        [3, [-3,  5]],
        [4, [ 3, -5]],
        [5, [ 4, -3]],
        [6, [ 5, -5]],
        [7, [ 3,  3]],
        [8, [ 3,  4]],
        [9, [ 3,  5]],
        [10, [ 4,  3]],
        [11, [ 4,  4]],
        [12, [ 4,  5]],
        [13, [ 5,  3]],
        [14, [ 5,  4]],
        [15, [ 5,  5]],
    ]
 
    for data in data_to_insert:
        print(f"Inserting {data[1]}")
        db.execute(INSERT_STATEMENT, [data[0], sqlite_vec.serialize_float32(data[1])])
 
    db.commit()
 
    SELECT_STATEMENT = """
        SELECT
          rowid,
          distance
        FROM v2
        WHERE embedding MATCH ?
        ORDER BY distance
        LIMIT ?
    """
 
    print()
    print("Finding vectors close to [4, 4]")
    results = db.execute(SELECT_STATEMENT, [sqlite_vec.serialize_float32([4, 4]), 5]).fetchall()
 
    for result in results:
        print(result)

18. Repositář s demonstračními příklady

Demonstrační příklady, s nimiž jsme se dnes seznámili a které jsou určeny pro Python 3.11 (a libovolnou vyšší verzi Pythonu) a knihovnu SQLite s rozšíření SQLite-vec, jsou dostupné, jak je zvykem, na GitHubu. V tabulce níže jsou uvedeny odkazy na jednotlivé zdrojové kódy i na definice formulářů:

# Příklad Stručný popis Adresa
1 pyproject.toml projektový soubor pro všechny demonstrační příklady https://github.com/tisnik/most-popular-python-libs/blob/master/sqlite-vec-tests/pyproject.toml
2 intro_file.py tisk informace o verzi vektorového rozšíření sqlite-vec, verze s databází uložené v souboru https://github.com/tisnik/most-popular-python-libs/blob/master/sqlite-vec-tests/intro_file.py
3 intro_mem.py tisk informace o verzi vektorového rozšíření sqlite-vec, verze s databází uložené v operační paměti https://github.com/tisnik/most-popular-python-libs/blob/master/sqlite-vec-tests/intro_mem.py
       
4 create_table1.py vytvoření virtuální tabulky s jedním sloupcem pro vektory, základní způsob zápisu https://github.com/tisnik/most-popular-python-libs/blob/master/sqlite-vec-tests/create_table1.py
5 create_table2.py vytvoření virtuální tabulky s jedním sloupcem s vektory, použití kontext manažeru https://github.com/tisnik/most-popular-python-libs/blob/master/sqlite-vec-tests/create_table2.py
       
6 fill_in_table1.py naplnění virtuální tabulky několika vektory, základní varianta https://github.com/tisnik/most-popular-python-libs/blob/master/sqlite-vec-tests/fill_in_table1.py
7 fill_in_table2.py naplnění virtuální tabulky patnácti vektory, rozšiřitelná varianta https://github.com/tisnik/most-popular-python-libs/blob/master/sqlite-vec-tests/fill_in_table2.py
       
8 query1.py dotaz vracející tři nejbližší vektory k vektoru [-4, 4] https://github.com/tisnik/most-popular-python-libs/blob/master/sqlite-vec-tests/query1.py
9 query2.py dotaz vracející pět nejbližších vektorů k vektoru [4, 4] https://github.com/tisnik/most-popular-python-libs/blob/master/sqlite-vec-tests/query2.py

19. Předchozí články věnující se problematice vyhledávání podobných vektorů v databázích

Na stránkách Roota jsme se již několikrát setkali s problematikou vyhledávání vektorů v databázích (ať již se jedná o mainstreamové databáze, nebo o databáze specializované). Následují odkazy na tyto články:

  1. pgvector: vektorová databáze postavená na Postgresu
    https://www.root.cz/clanky/pgvector-vektorova-databaze-postavena-na-postgresu/
  2. Rozšíření PostgreSQL jménem pgvector, embedding a sémantické vyhledávání (1. část)
    https://www.root.cz/clanky/rozsireni-postgresql-jmenem-pgvector-embedding-a-semanticke-vyhledavani-1-cast/
  3. FAISS: knihovna pro rychlé a efektivní vyhledávání podobných vektorů
    https://www.root.cz/clanky/faiss-knihovna-pro-rychle-a-efektivni-vyhledavani-podobnych-vektoru/
  4. FAISS: knihovna pro rychlé a efektivní vyhledávání podobných vektorů (2. část)
    https://www.root.cz/clanky/faiss-knihovna-pro-rychle-a-efektivni-vyhledavani-podobnych-vektoru-2-cast/
  5. Knihovna FAISS a embedding: základ jazykových modelů
    https://www.root.cz/clanky/knihovna-faiss-a-embedding-zaklad-jazykovych-modelu/

20. Odkazy na Internetu

  1. sqlite-vec repository
    https://github.com/asg017/sqlite-vec
  2. SQlite-vec
    https://builders.mozilla.or­g/project/sqlite-vec/
  3. How to use sqlite-vec to store and query vector embeddings
    https://dev.to/stephenc222/how-to-use-sqlite-vec-to-store-and-query-vector-embeddings-58mf
  4. SQLite-Vector
    https://www.sqlite.ai/sqlite-vector
  5. Vector database
    https://en.wikipedia.org/wi­ki/Vector_database
  6. Nearest neighbor search
    https://en.wikipedia.org/wi­ki/Nearest_neighbor_search#Ap­proximation_methods
  7. RAG – Retrieval-augmented generation
    https://en.wikipedia.org/wi­ki/Retrieval-augmented_generation
  8. pgvector na GitHubu
    https://github.com/pgvector/pgvector
  9. Why we replaced Pinecone with PGVector
    https://www.confident-ai.com/blog/why-we-replaced-pinecone-with-pgvector
  10. PostgreSQL as VectorDB – Beginner Tutorial
    https://www.youtube.com/wat­ch?v=Ff3tJ4pJEa4
  11. What is a Vector Database? (neobsahuje odpověď na otázku v titulku :-)
    https://www.youtube.com/wat­ch?v=t9IDoenf-lo
  12. PGVector: Turn PostgreSQL Into A Vector Database
    https://www.youtube.com/wat­ch?v=j1QcPSLj7u0
  13. Milvus
    https://milvus.io/
  14. Vector Databases simply explained! (Embeddings & Indexes)
    https://www.youtube.com/wat­ch?v=dN0lsF2cvm4
  15. Vector databases are so hot right now. WTF are they?
    https://www.youtube.com/wat­ch?v=klTvEwg3oJ4
  16. Step-by-Step Guide to Installing “pgvector” and Loading Data in PostgreSQL
    https://medium.com/@besttechreads/step-by-step-guide-to-installing-pgvector-and-loading-data-in-postgresql-f2cffb5dec43
  17. Best 17 Vector Databases for 2025
    https://lakefs.io/blog/12-vector-databases-2023/
  18. Top 15 Vector Databases that You Must Try in 2025
    https://www.geeksforgeeks.org/top-vector-databases/
  19. Picking a vector database: a comparison and guide for 2023
    https://benchmark.vectorvi­ew.ai/vectordbs.html
  20. Top 9 Vector Databases as of Feburary 2025
    https://www.shakudo.io/blog/top-9-vector-databases
  21. What is a vector database?
    https://www.ibm.com/think/to­pics/vector-database
  22. SQL injection
    https://en.wikipedia.org/wi­ki/SQL_injection
  23. Cosine similarity
    https://en.wikipedia.org/wi­ki/Cosine_similarity
  24. Hammingova vzdálenost
    https://cs.wikipedia.org/wi­ki/Hammingova_vzd%C3%A1le­nost
  25. Jaccard index
    https://en.wikipedia.org/wi­ki/Jaccard_index
  26. Manhattanská metrika
    https://cs.wikipedia.org/wi­ki/Manhattansk%C3%A1_metri­ka
  27. FAISS (Facebook AI Similarity Search)
    https://en.wikipedia.org/wiki/FAISS
  28. FAISS documentation
    https://faiss.ai/
  29. Introduction to Facebook AI Similarity Search (Faiss)
    https://www.pinecone.io/le­arn/series/faiss/faiss-tutorial/
  30. Faiss: Efficient Similarity Search and Clustering of Dense Vectors
    https://medium.com/@pankaj_pan­dey/faiss-efficient-similarity-search-and-clustering-of-dense-vectors-dace1df1e235
  31. Cosine Distance vs Dot Product vs Euclidean in vector similarity search
    https://medium.com/data-science-collective/cosine-distance-vs-dot-product-vs-euclidean-in-vector-similarity-search-227a6db32edb
  32. F16C
    https://en.wikipedia.org/wiki/F16C
  33. FP16 (AVX-512)
    https://en.wikipedia.org/wiki/AVX-512#FP16
  34. Top 8 Vector Databases in 2025: Features, Use Cases, and Comparisons
    https://synapsefabric.com/top-8-vector-databases-in-2025-features-use-cases-and-comparisons/
  35. Is FAISS a Vector Database? Complete Guide
    https://mljourney.com/is-faiss-a-vector-database-complete-guide/
  36. FAISS and sentence-transformers in 5 Minutes
    https://www.stephendiehl.com/pos­ts/faiss/
  37. Sentence Transformer: Quickstart
    https://sbert.net/docs/qu­ickstart.html#sentence-transformer
  38. Sentence Transformers: Embeddings, Retrieval, and Reranking
    https://pypi.org/project/sentence-transformers/
  39. uv
    https://docs.astral.sh/uv/
  40. A Gentle Introduction to Retrieval Augmented Generation (RAG)
    https://wandb.ai/cosmo3769/RAG/re­ports/A-Gentle-Introduction-to-Retrieval-Augmented-Generation-RAG---Vmlldzo1MjM4Mjk1
  41. The Beginner’s Guide to Text Embeddings
    https://www.deepset.ai/blog/the-beginners-guide-to-text-embeddings
  42. SQLite: Run-Time Loadable Extensions
    https://sqlite.org/loadext.html
  43. SQLite: Load An Extension
    https://sqlite.org/c3ref/lo­ad_extension.html
  44. The Virtual Table Mechanism Of SQLite
    https://sqlite.org/vtab.html

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.