From b62f6f19a8b68703338ba749246788abdf2180bc Mon Sep 17 00:00:00 2001
From: Alex Garcia
Date: Sat, 22 Jun 2024 16:46:33 -0700
Subject: [PATCH] doc updates
---
README.md | 19 +++
examples/python-recipes/openai-sample.py | 90 +++++++++++++
site/.vitepress/config.mts | 93 ++++++++-----
site/.vitepress/theme/HeroImg.vue | 38 ++++++
site/.vitepress/theme/Sponsors.vue | 32 ++---
site/.vitepress/theme/index.ts | 3 +-
site/.vitepress/theme/style.css | 42 +++++-
site/getting-started/installation.md | 49 +++++++
site/getting-started/introduction.md | 7 +
.../quickstart.md} | 0
site/guides/arithmetic.md | 5 +
site/guides/binary-quant.md | 120 +++++++++++++++++
.../loadable.md => guides/classifiers.md} | 0
site/guides/hybrid-search.md | 0
site/guides/matryoshka.md | 49 +++++++
site/guides/performance.md | 4 +
site/guides/rag.md | 4 +
site/guides/scalar-quant.md | 27 ++++
site/guides/semantic-search.md | 0
site/index.md | 41 ++----
site/project.data.ts | 2 +-
site/public/fonts/ZillaSlab-SemiBold.otf | Bin 0 -> 111580 bytes
site/public/fonts/ZillaSlab-SemiBold.ttf | Bin 0 -> 270088 bytes
site/public/fonts/ZillaSlab-SemiBold.woff | Bin 0 -> 106796 bytes
site/public/fonts/ZillaSlab-SemiBold.woff2 | Bin 0 -> 69712 bytes
site/public/logo.dark.svg | 17 +++
site/public/logo.light.svg | 17 +++
site/using/js.md | 54 +++++++-
site/using/python.md | 126 +++++++++++++++++-
site/using/ruby.md | 2 +
tests/test-loadable.py | 7 +-
31 files changed, 751 insertions(+), 97 deletions(-)
create mode 100644 examples/python-recipes/openai-sample.py
create mode 100644 site/.vitepress/theme/HeroImg.vue
create mode 100644 site/getting-started/installation.md
create mode 100644 site/getting-started/introduction.md
rename site/{getting-started.md => getting-started/quickstart.md} (100%)
create mode 100644 site/guides/arithmetic.md
create mode 100644 site/guides/binary-quant.md
rename site/{using/loadable.md => guides/classifiers.md} (100%)
create mode 100644 site/guides/hybrid-search.md
create mode 100644 site/guides/matryoshka.md
create mode 100644 site/guides/performance.md
create mode 100644 site/guides/rag.md
create mode 100644 site/guides/scalar-quant.md
create mode 100644 site/guides/semantic-search.md
create mode 100644 site/public/fonts/ZillaSlab-SemiBold.otf
create mode 100644 site/public/fonts/ZillaSlab-SemiBold.ttf
create mode 100644 site/public/fonts/ZillaSlab-SemiBold.woff
create mode 100644 site/public/fonts/ZillaSlab-SemiBold.woff2
create mode 100644 site/public/logo.dark.svg
create mode 100644 site/public/logo.light.svg
diff --git a/README.md b/README.md
index cc756ab..f8bc302 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,25 @@ See the Sponsors section for more details.
+
+
## Sample usage
```sql
diff --git a/examples/python-recipes/openai-sample.py b/examples/python-recipes/openai-sample.py
new file mode 100644
index 0000000..c51feca
--- /dev/null
+++ b/examples/python-recipes/openai-sample.py
@@ -0,0 +1,90 @@
+# pip install openai sqlite-vec
+
+from openai import OpenAI
+import sqlite3
+import sqlite_vec
+import struct
+from typing import List
+
+
+def serialize(vector: List[float]) -> bytes:
+ """serializes a list of floats into a compact "raw bytes" format"""
+ return struct.pack("%sf" % len(vector), *vector)
+
+
+sentences = [
+ "Capri-Sun is a brand of juice concentrate–based drinks manufactured by the German company Wild and regional licensees.",
+ "George V was King of the United Kingdom and the British Dominions, and Emperor of India, from 6 May 1910 until his death in 1936.",
+ "Alaqua Cox is a Native American (Menominee) actress.",
+ "Shohei Ohtani is a Japanese professional baseball pitcher and designated hitter for the Los Angeles Dodgers of Major League Baseball.",
+ "Tamarindo, also commonly known as agua de tamarindo, is a non-alcoholic beverage made of tamarind, sugar, and water.",
+]
+
+
+client = OpenAI()
+
+# change ':memory:' to a filepath to persist data
+db = sqlite3.connect(":memory:")
+db.enable_load_extension(True)
+sqlite_vec.load(db)
+db.enable_load_extension(False)
+
+db.execute(
+ """
+ CREATE TABLE sentences(
+ id INTEGER PRIMARY KEY,
+ sentence TEXT
+ );
+ """
+)
+
+with db:
+ for i, sentence in enumerate(sentences):
+ db.execute("INSERT INTO sentences(id, sentence) VALUES(?, ?)", [i, sentence])
+
+db.execute(
+ """
+ CREATE VIRTUAL TABLE vec_sentences USING vec0(
+ id INTEGER PRIMARY KEY,
+ sentence_embedding FLOAT[1536]
+ );
+ """
+)
+
+
+with db:
+ sentence_rows = db.execute("SELECT id, sentence FROM sentences").fetchall()
+ response = client.embeddings.create(
+ input=[row[1] for row in sentence_rows], model="text-embedding-3-small"
+ )
+ for (id, _), embedding in zip(sentence_rows, response.data):
+ db.execute(
+ "INSERT INTO vec_sentences(id, sentence_embedding) VALUES(?, ?)",
+ [id, serialize(embedding.embedding)],
+ )
+
+
+query = "fruity liquids"
+query_embedding = (
+ client.embeddings.create(input=query, model="text-embedding-3-small")
+ .data[0]
+ .embedding
+)
+
+results = db.execute(
+ """
+ SELECT
+ vec_sentences.id,
+ distance,
+ sentence
+ FROM vec_sentences
+ LEFT JOIN sentences ON sentences.id = vec_sentences.id
+ WHERE sentence_embedding MATCH ?
+ AND k = 3
+ ORDER BY distance
+ """,
+ [serialize(query_embedding)],
+).fetchall()
+
+for row in results:
+ print(row)
diff --git a/site/.vitepress/config.mts b/site/.vitepress/config.mts
index 8ca2d47..447eb86 100644
--- a/site/.vitepress/config.mts
+++ b/site/.vitepress/config.mts
@@ -11,6 +11,17 @@ const VERSION = readFileSync(
"utf8"
);
+const sqliteLanuage = JSON.parse(
+ readFileSync(
+ join(
+ dirname(fileURLToPath(import.meta.url)),
+ "..",
+ "sqlite.tmlanguage.json"
+ ),
+ "utf8"
+ )
+);
+
function head(): HeadConfig[] {
return [
[
@@ -18,7 +29,7 @@ function head(): HeadConfig[] {
{
rel: "shortcut icon",
type: "image/svg+xml",
- href: "favicon.svg",
+ href: "./logo.light.svg",
},
],
[
@@ -36,22 +47,34 @@ const guides = {
text: "Guides",
collapsed: true,
items: [
- { text: "Binary Quantization", link: "/guides/binary-quant" },
- { text: "Scalar Quantization", link: "/guides/scalar-quant" },
+ { text: "Performance", link: "/guides/performance" },
{
- text: "Matryosha/Adaptive Length Embeddings",
- link: "/guides/matryoshka",
+ text: "Vector operations",
+ items: [
+ { text: "Vector Arithmetic", link: "/guides/arithmetic" },
+ { text: "Binary Quantization", link: "/guides/binary-quant" },
+ { text: "Scalar Quantization", link: "/guides/scalar-quant" },
+ {
+ text: "Matryoshka Embeddings",
+ link: "/guides/matryoshka",
+ },
+ ],
+ },
+
+ {
+ text: "Build with sqlite-vec",
+ items: [
+ { text: "Semantic Search", link: "/guides/semantic-search" },
+ { text: "Hybrid Search", link: "/guides/hybrid-search" },
+ { text: "Retrival Augmented Generation (RAG)", link: "/guides/rag" },
+ { text: "Classifiers", link: "/guides/classifiers" },
+ ],
},
- { text: "Semantic Search", link: "/guides/semantic-search" },
- { text: "Hybrid Search", link: "/guides/hybrid-search" },
- { text: "Classifiers", link: "/guides/classifiers" },
- { text: "Improving Performance", link: "/guides/improving-perf" },
],
};
function nav(): DefaultTheme.NavItem[] {
return [
- guides,
{ text: "API Reference", link: "/api-reference" },
{ text: "♥ Sponsor", link: "https://github.com/sponsors/asg017" },
{
@@ -103,17 +126,25 @@ function sidebar(): DefaultTheme.SidebarItem[] {
return [
{
text: "Getting Started",
- collapsed: false,
+ collapsed: true,
items: [
{
- text: "Quickstart",
- link: "/getting-started",
+ text: "Installation",
+ link: "/installation",
+ },
+ {
+ text: "Introduction",
+ link: "/introduction",
+ },
+ {
+ text: "Quick Start",
+ link: "/quickstart",
},
],
},
{
text: "Using with...",
- collapsed: false,
+ collapsed: true,
items: [
{ text: "Python", link: "/python" },
{ text: "JavaScript", link: "/js" },
@@ -124,7 +155,6 @@ function sidebar(): DefaultTheme.SidebarItem[] {
{ text: "WebAssembly (Browser)", link: "/wasm" },
{ text: "Datasette", link: "/datasette" },
{ text: "sqlite-utils", link: "/sqlite-utils" },
- { text: "Loadable Extension", link: "/loadable" },
],
},
guides,
@@ -135,6 +165,10 @@ function sidebar(): DefaultTheme.SidebarItem[] {
{ text: "API Reference", link: "/api-reference" },
],
},
+ {
+ text: "Sponsors",
+ link: "/sponsors",
+ },
{
text: "See also",
items: [
@@ -163,13 +197,18 @@ export default defineConfig({
head: head(),
base: "/sqlite-vec/",
themeConfig: {
+ logo: {
+ light: "/logo.dark.svg",
+ dark: "/logo.light.svg",
+ alt: "sqlite-vec logo",
+ },
+
nav: nav(),
-
sidebar: sidebar(),
-
footer: {
- message: "MIT License",
- copyright: "Copyright © 2024 Alex Garcia",
+ message: "MIT/Apache-2 License",
+ copyright:
+ 'Copyright © 2024 Alex Garcia ',
},
outline: "deep",
search: {
@@ -185,20 +224,10 @@ export default defineConfig({
},
rewrites: {
"using/:pkg.md": ":pkg.md",
- "guides/:pkg.md": ":pkg.md",
+ "getting-started/:pkg.md": ":pkg.md",
+ //"guides/:pkg.md": ":pkg.md",
},
markdown: {
- languages: [
- JSON.parse(
- readFileSync(
- join(
- dirname(fileURLToPath(import.meta.url)),
- "..",
- "sqlite.tmlanguage.json"
- ),
- "utf8"
- )
- ),
- ],
+ languages: [sqliteLanuage],
},
});
diff --git a/site/.vitepress/theme/HeroImg.vue b/site/.vitepress/theme/HeroImg.vue
new file mode 100644
index 0000000..7b19d2b
--- /dev/null
+++ b/site/.vitepress/theme/HeroImg.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
-- store 768-dimensional vectors in a vec0 virtual table
+create virtual table vec_movies using vec0(
+ synopsis_embedding float [768]
+);
+
+-- insert vectors into the table, as JSON or compact BLOBs
+insert into vec_movies(rowid, synopsis_embedding)
+ select
+ rowid,
+ embed(synopsis) as synopsis_embedding
+ from movies;
+
+-- KNN search!
+select
+ rowid,
+ distance
+from vec_movies
+where synopsis_embedding match embed( 'scary futuristic movies' )
+order by distance
+limit 20 ;
+
+
+
+
diff --git a/site/.vitepress/theme/Sponsors.vue b/site/.vitepress/theme/Sponsors.vue
index 93eea86..150c814 100644
--- a/site/.vitepress/theme/Sponsors.vue
+++ b/site/.vitepress/theme/Sponsors.vue
@@ -11,7 +11,7 @@ const sponsors = computed(() => {
{
name: "Mozilla Builders",
url: "",
- img: withBase("./mozilla.svg"),
+ img: withBase("/mozilla.svg"),
},
],
},
@@ -21,7 +21,7 @@ const sponsors = computed(() => {
{
name: "Fly.io",
url: "https://fly.io",
- img: withBase("./flyio.svg"),
+ img: withBase("/flyio.svg"),
},
],
},
@@ -31,7 +31,7 @@ const sponsors = computed(() => {
{
name: "Turso",
url: "https://turso.tech",
- img: withBase("./turso.svg"),
+ img: withBase("/turso.svg"),
},
],
},
@@ -41,7 +41,7 @@ const sponsors = computed(() => {
{
name: "SQLite Cloud",
url: "https://sqlitecloud.io",
- img: withBase("./sqlitecloud.svg"),
+ img: withBase("/sqlitecloud.svg"),
},
],
},
@@ -51,18 +51,20 @@ const sponsors = computed(() => {
-
-
diff --git a/site/.vitepress/theme/index.ts b/site/.vitepress/theme/index.ts
index 54e08a8..82048fd 100644
--- a/site/.vitepress/theme/index.ts
+++ b/site/.vitepress/theme/index.ts
@@ -4,6 +4,7 @@ import type { Theme } from "vitepress";
import DefaultTheme from "vitepress/theme";
import "./style.css";
import Sponsors from "./Sponsors.vue";
+import HeroImg from "./HeroImg.vue";
export default {
extends: DefaultTheme,
@@ -14,7 +15,7 @@ export default {
h("marquee", { class: "banner", scrollamount: "10" }, [
"🚧🚧🚧 sqlite-vec is still in beta, and this documentation is incomplete! Watch the repo for updates 🚧🚧🚧",
]),
- "home-hero-image": () => h("div", {}, [""]),
+ //"home-hero-image": () => h(HeroImg),
"aside-ads-before": () => h(Sponsors),
});
},
diff --git a/site/.vitepress/theme/style.css b/site/.vitepress/theme/style.css
index 33a6310..df4b100 100644
--- a/site/.vitepress/theme/style.css
+++ b/site/.vitepress/theme/style.css
@@ -1,3 +1,21 @@
+/*@import "https://code.cdn.mozilla.net/fonts/zilla-slab.css";*/
+
+@font-face {
+ font-family: "ZillaSlab-SemiBold";
+ src: url("/fonts/ZillaSlab-SemiBold.woff");
+ src: url("/fonts/ZillaSlab-SemiBold.woff2") format("woff2"),
+ url("/fonts/ZillaSlab-SemiBold.woff") format("woff"),
+ url("/fonts/ZillaSlab(-SemiBold).otf") format("opentype"),
+ url("/fonts/ZillaSlab-SemiBold.ttf") format("truetype");
+ font-weight: 600;
+ font-style: normal;
+}
+
+.VPHero h1,
+.VPNavBarTitle .title {
+ font-family: "ZillaSlab-SemiBold";
+ font-size: 1.5rem;
+}
/**
* Customize default theme styling by overriding CSS variables:
* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
@@ -68,6 +86,17 @@
--vp-c-danger-2: var(--vp-c-red-2);
--vp-c-danger-3: var(--vp-c-red-3);
--vp-c-danger-soft: var(--vp-c-red-soft);
+
+ --vp-c-brand-1x: #a6d189;
+ --vp-c-brand-1x: #a6da95;
+ --vp-c-brand-1x: #a6e3a1;
+}
+
+:root {
+ --vp-c-brand-1: #1e66f5;
+}
+.dark {
+ --vp-c-brand-1: #89b4fa;
}
/**
@@ -92,19 +121,20 @@
:root {
--vp-home-hero-name-color: transparent;
- --vp-home-hero-name-background: -webkit-linear-gradient(
- 120deg,
- #f5c2e7 30%,
- #94e2d5 /*#bd34fe 30%,
- #41d1ff*/
- );
+ --vp-home-hero-name-background: black;
+ /*
--vp-home-hero-image-background-image: linear-gradient(
-45deg,
#bd34fe 50%,
#47caff 50%
);
--vp-home-hero-image-filter: blur(44px);
+ */
+}
+
+.dark {
+ --vp-home-hero-name-background: white;
}
@media (min-width: 640px) {
diff --git a/site/getting-started/installation.md b/site/getting-started/installation.md
new file mode 100644
index 0000000..01a09dd
--- /dev/null
+++ b/site/getting-started/installation.md
@@ -0,0 +1,49 @@
+# Installing
+
+You have several options to include `sqlite-vec` into your projects, including
+PyPi packages for Python, NPM packages for Node.js, Gems for Ruby, and more.
+
+## With popular package managers
+
+::: code-group
+
+```bash [Python]
+pip install sqlite-vec
+```
+
+```bash [Node.js]
+npm install sqlite-vec
+```
+
+```bash [Bun]
+bun install sqlite-vec
+```
+
+```bash [Deno]
+deno add npm:sqlite-vec
+```
+
+```bash [Ruby]
+gem install sqlite-vec
+```
+
+```bash [Rust]
+cargo add sqlite-vec
+```
+
+```bash [Go]
+go get -u github.com/asg017/sqlite-vec/bindings/go/cgo
+```
+
+```bash [Datasette]
+datasette install datasette-sqlite-vec
+```
+
+```bash [sqlite-utils]
+sqlite-utils install sqlite-utils-sqlite-vec
+```
+
+:::
+
+Alternatively, you can download pre-compiled loadable extensions from the
+[`sqlite-vec` Github Releases](https://github.com/asg017/sqlite-vec/releases/latest).
diff --git a/site/getting-started/introduction.md b/site/getting-started/introduction.md
new file mode 100644
index 0000000..c827b37
--- /dev/null
+++ b/site/getting-started/introduction.md
@@ -0,0 +1,7 @@
+# Introduction to `sqlite-vec`
+
+## Intro to Vector Databases
+
+## Vector Search in SQLite with `sqlite-vec`
+
+## Getting help
diff --git a/site/getting-started.md b/site/getting-started/quickstart.md
similarity index 100%
rename from site/getting-started.md
rename to site/getting-started/quickstart.md
diff --git a/site/guides/arithmetic.md b/site/guides/arithmetic.md
new file mode 100644
index 0000000..807ac86
--- /dev/null
+++ b/site/guides/arithmetic.md
@@ -0,0 +1,5 @@
+# Vector Arithmetic
+
+- `vec_add()`
+- `vec_sub()`
+- `vec_mean()`
diff --git a/site/guides/binary-quant.md b/site/guides/binary-quant.md
new file mode 100644
index 0000000..cab8924
--- /dev/null
+++ b/site/guides/binary-quant.md
@@ -0,0 +1,120 @@
+# Binary Quantization
+
+"Quantization" refers to a variety of methods and techniques for reducing the
+size of vectors in a vector index. **Binary quantization** (BQ) refers to a
+specific technique where each individual floating point element in a vector is
+reduced to a single bit, typically by assigning `0` to negative numbers and `1`
+to positive numbers.
+
+For example, in this 8-dimensional `float32` vector:
+
+```json
+[-0.73, -0.80, 0.12, -0.73, 0.79, -0.11, 0.23, 0.97]
+```
+
+Applying binary quantization would result in the following `bit` vector:
+
+```json
+[0, 0, 1, 0, 1, 0, 1, 1]
+```
+
+The original 8-dimensional `float32` vector requires `8 * 4 = 32` bytes of space
+to store. For 1 million vectors, that would be `32MB`. On the other hand, the
+binary quantized 8-dimensional vector can be stored in a single byte — one bit
+per element. For 1 million vectors, that would be just `1MB`, a 32x reduction!
+
+Though keep in mind, you're bound to lose a lot quality when reducing 32 bits of
+information to 1 bit. [Over-sampling and re-scoring](#re-scoring) will help a
+lot.
+
+The main goal of BQ is to dramatically reduce the size of your vector index,
+resulting in faster searches and less resources. This is especially useful in
+`sqlite-vec`, which is (currently) brute-force only and meant to run on small
+devices. BQ is an easy low-cost method to make larger vector datasets easy to
+manage.
+
+## Binary Quantization `sqlite-vec`
+
+The `sqlite-vec` extension offers a `vec_quantize_binary()` SQL scalar function,
+which applies binary quanitization to a `float32` or `int8` vector. For every
+element in a given vector, it will apply `0` to negative values and `1` to
+positive values, and pack them into a `BLOB`.
+
+```sqlite
+select vec_quantize_binary('[-0.73, -0.80, 0.12, -0.73, 0.79, -0.11, 0.23, 0.97]');
+-- X'd4`
+```
+
+The single byte `0xd4` in hexadecimal is `11010100` in binary.
+
+
+
+## Demo
+
+```sqlite
+create virtual table vec_movies using vec0(
+ synopsis_embedding bit[768]
+);
+```
+
+```sqlite
+insert into vec_movies(rowid, synopsis_embedding)
+ VALUES (:id, vec_quantize_binary(:vector));
+```
+
+```sqlite
+select
+ rowid,
+ distance
+from vec_movies
+where synopsis_embedding match vec_quantize_binary(:query)
+order by distance
+limit 20;
+```
+
+### Re-scoring
+
+```sqlite
+create virtual table vec_movies using vec0(
+ synopsis_embedding float[768],
+ synopsis_embedding_coarse bit[768]
+);
+```
+
+```sqlite
+insert into vec_movies(rowid, synopsis_embedding, synopsis_embedding_coarse)
+ VALUES (:id, :vector, vec_quantize_binary(:vector));
+```
+
+```sqlite
+with coarse_matches as (
+ select
+ rowid,
+ synopsis_embedding
+ from vec_movies
+ where synopsis_embedding_coarse match vec_quantize_binary(:query)
+ order by distance
+ limit 20 * 8
+),
+select
+ rowid,
+ vec_distance_L2(synopsis_embedding, :query)
+from coarse_matches
+order by 2
+limit 20;
+```
+
+# Benchmarks
+
+## Model support
+
+Certain embedding models, like [Nomic](https://nomic.ai/)'s
+[`nomic-embed-text-v1.5`](https://huggingface.co/nomic-ai/nomic-embed-text-v1.5)
+text embedding model and
+[mixedbread.ai](https://www.mixedbread.ai/blog/mxbai-embed-2d-large-v1)'s
+[`mxbai-embed-large-v1`](https://huggingface.co/mixedbread-ai/mxbai-embed-large-v1)
+are specifically trained to perform well after binary quantization.
+
+Other embeddings models may not, but you can still try BQ and see if it works
+for your datasets. Chances are, if your vectors are normalized (ie between
+`-1.0` and `1.0`) there's a good chance you will see acceptable results with BQ.
diff --git a/site/using/loadable.md b/site/guides/classifiers.md
similarity index 100%
rename from site/using/loadable.md
rename to site/guides/classifiers.md
diff --git a/site/guides/hybrid-search.md b/site/guides/hybrid-search.md
new file mode 100644
index 0000000..e69de29
diff --git a/site/guides/matryoshka.md b/site/guides/matryoshka.md
new file mode 100644
index 0000000..db3cd5c
--- /dev/null
+++ b/site/guides/matryoshka.md
@@ -0,0 +1,49 @@
+# Matryoshka (Adaptive-Length) Embeddings
+
+Matryoshka embeddings are a new class of embedding models introduced in the
+TODO-YYY paper [_TODO title_](https://arxiv.org/abs/2205.13147). They allow one
+to truncate excess dimensions in large vector, without lossing much quality.
+
+Let's say your embedding model generate 1024-dimensional vectors. If you have 1
+million of these 1024-dimensional vectors, they would take up `4.096 GB` of
+space! You're not able to reduce the dimensions without lossing a lot of
+quality - if you were to remove half of the dimensions 512-dimensional vectors,
+you could expect to also lose 50% or more of the quality of results. There are
+other dimensional-reduction techniques, like [PCA](#TODO), but this requires a
+complicated and expensive training process.
+
+Matryoshka embeddings, on the other hand, _can_ be truncated, without losing
+quality. Using [`mixedbread.ai`](#TODO) `mxbai-embed-large-v1` model, they claim
+that
+
+They are called "Matryoshka" embeddings because ... TODO
+
+## Matryoshka Embeddings with `sqlite-vec`
+
+You can use a combination of [`vec_slice()`](/api-reference#vec_slice) and
+[`vec_normalize()`](/api-reference#vec_slice) on Matryoshka embeddings to
+truncate.
+
+```sql
+select
+ vec_normalize(vec_slice(title_embeddings, 0, 256)) as title_embeddings_256d
+from vec_articles;
+```
+
+## Benchmarks
+
+## Suppported Models
+
+https://supabase.com/blog/matryoshka-embeddings#which-granularities-were-openais-text-embedding-3-models-trained-on
+
+`text-embedding-3-small`: 1536, 512 `text-embedding-3-large`: 3072, 1024, 256
+
+https://x.com/ZainHasan6/status/1757519325202686255
+
+`text-embeddings-3-large:` 3072, 1536, 1024, 512
+
+https://www.mixedbread.ai/blog/binary-mrl
+
+`mxbai-embed-large-v1`: 1024, 512, 256, 128, 64
+
+`nomic-embed-text-v1.5`: 768, 512, 256, 128, 64
diff --git a/site/guides/performance.md b/site/guides/performance.md
new file mode 100644
index 0000000..2972957
--- /dev/null
+++ b/site/guides/performance.md
@@ -0,0 +1,4 @@
+- page_size
+- memory mapping
+- in-memory index
+- chunk_size (?)
diff --git a/site/guides/rag.md b/site/guides/rag.md
new file mode 100644
index 0000000..f860172
--- /dev/null
+++ b/site/guides/rag.md
@@ -0,0 +1,4 @@
+# Retrival Augmented Generation (RAG)
+
+- "memories"?
+- chunking
diff --git a/site/guides/scalar-quant.md b/site/guides/scalar-quant.md
new file mode 100644
index 0000000..8738a0c
--- /dev/null
+++ b/site/guides/scalar-quant.md
@@ -0,0 +1,27 @@
+# Scalar Quantization (SQ)
+
+"Quantization" refers to a variety of methods and techniques for reducing the
+size of vectors in a vector index. **Scalar quantization** (SQ) refers to a
+specific technique where each individual floating point element in a vector is
+scaled to a small element type, like `float16`, `int8`.
+
+Most embedding models generate `float32` vectors. Each `float32` takes up 4
+bytes of space. This can add up, especially when working with a large amount of
+vectors or vectors with many dimensions. However, if you scale them to `float16`
+or `int8` vectors, they only take up 2 bytes of space and 1 bytes of space
+respectively, saving you precious space at the expense of some quality.
+
+```sql
+select vec_quantize_float16(vec_f32('[]'), 'unit');
+select vec_quantize_int8(vec_f32('[]'), 'unit');
+
+select vec_quantize('float16', vec_f32('...'));
+select vec_quantize('int8', vec_f32('...'));
+select vec_quantize('bit', vec_f32('...'));
+
+select vec_quantize('sqf16', vec_f32('...'));
+select vec_quantize('sqi8', vec_f32('...'));
+select vec_quantize('bq2', vec_f32('...'));
+```
+
+## Benchmarks
diff --git a/site/guides/semantic-search.md b/site/guides/semantic-search.md
new file mode 100644
index 0000000..e69de29
diff --git a/site/index.md b/site/index.md
index cf64396..c6c31ff 100644
--- a/site/index.md
+++ b/site/index.md
@@ -9,14 +9,14 @@ hero:
actions:
- theme: brand
text: Getting Started
- link: /getting-started
+ link: /introduction
- theme: alt
text: API Reference
link: /api-reference
features:
- title: Runs everywhere
- details: On the server, in the browser with WASM, mobile devices, and more!
+ details: On laptops, servers, mobile devices, browsers with WASM, Raspberry Pis, and more!
- title: Bindings for many languages
details: Python, Ruby, Node.js/Deno/Bun, Go, Rust, and more!
- title: Only SQL
@@ -24,49 +24,24 @@ features:
---
```sqlite
+-- store 768-dimensional vectors in a vec0 virtual table
create virtual table vec_movies using vec0(
synopsis_embedding float[768]
);
+-- insert vectors into the table, as JSON or compact BLOBs
insert into vec_movies(rowid, synopsis_embedding)
select
rowid,
embed(synopsis) as synopsis_embedding
from movies;
-select rowid, distance
+-- KNN search!
+select
+ rowid,
+ distance
from vec_movies
where synopsis_embedding match embed('scary futuristic movies')
order by distance
limit 20;
```
-
----
-
-sqlite create virtual table vec_movies using vec0(
- synopsis_embedding float [768]
-);
-
-insert into vec_movies(rowid, synopsis_embedding)
- select
- rowid,
- embed(synopsis) as synopsis_embedding
- from movies;
-
-select rowid, distance
-from vec_movies
-where synopsis_embedding match embed( 'scary futuristic movies' )
-order by distance
-limit 20 ;
-
-
-
-
diff --git a/site/project.data.ts b/site/project.data.ts
index 7403c13..586bbed 100644
--- a/site/project.data.ts
+++ b/site/project.data.ts
@@ -1,9 +1,9 @@
-import { defineConfig } from "vitepress";
import { readFileSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
const PROJECT = "sqlite-vec";
+
const VERSION = readFileSync(
join(dirname(fileURLToPath(import.meta.url)), "..", "VERSION"),
"utf8"
diff --git a/site/public/fonts/ZillaSlab-SemiBold.otf b/site/public/fonts/ZillaSlab-SemiBold.otf
new file mode 100644
index 0000000000000000000000000000000000000000..f6d1a2dd01632c658e4d986f56da343683184da9
GIT binary patch
literal 111580
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