PricingDocsTutorialsBlogAbout

Develop

Get Started
Store Embeddings
Generate Embeddings
Automatic Embedding Generation
Calculate Distance
Query Embeddings
Create Index
Quantization
Asynchronous Tasks
Weighted Vector Search
Troubleshooting
Single Operator
Postgres Notes
Security

Languages

Javascript
Python
Ruby
Rust

Migrate

Migrate from Postgres to Lantern Cloud
Migrate from pgvector to Lantern Cloud
Migrate from pgvector to self-hosted Lantern
Migrate from Pinecone to Lantern Cloud

Lantern HNSW

Installation

Lantern Extras

Installation
Generate Embeddings
Lantern Daemon

Lantern CLI

Installation
Generate Embeddings
Indexing Server
Daemon
Autotune Index
Product Quantization

Contributing

Dockerfile
Visual Studio Code

Languages

Javascript

In the subsequent examples, assume the following variables are defined

javascript
Copy
const embedding = [1, 2, 3];
const query = "My text input";

node-postgres

Insert embedding

javascript
Copy
await client.query("INSERT INTO books (embedding) VALUES ($1)", embedding);

Find nearest rows

javascript
Copy
const result = await client.query(
  "SELECT * FROM books ORDER BY embedding <-> $1 LIMIT 5",
  embedding
);
const result = await client.query(
  "SELECT * FROM books ORDER BY embedding <-> text_embedding('BAAI/bge-small-en', $1) LIMIT 5",
  query
);

pg-promise

Insert embedding

javascript
Copy
await db.none("INSERT INTO books (embedding) VALUES ($1)", embedding);

Find nearest rows

javascript
Copy
const result = await db.any(
  "SELECT * FROM books ORDER BY embedding <-> $1 LIMIT 5",
  embedding
);
const result = await db.any(
  "SELECT * FROM books ORDER BY embedding <-> text_embedding('BAAI/bge-small-en', $1) LIMIT 5",
  query
);

Prisma

Insert embedding

javascript
Copy
await db.books.create({ embedding });

Find nearest rows

javascript
Copy
const result =
  await Prisma.$queryRaw`SELECT * FROM books ORDER BY embedding <-> ${embedding} LIMIT 5`;
const result =
  await Prisma.$queryRaw`SELECT * FROM books ORDER BY text_embedding('BAAI/bge-small-en', ${query}) <-> book_embedding LIMIT 5`;

Kysely

Insert embedding

javascript
Copy
await db.insert({ embedding }).into("books");

Find nearest rows

javascript
Copy
const result = await db
  .select()
  .from("books")
  .orderBy(sql`embedding <-> ${embedding}`)
  .limit(5);
const result = await db
  .selectAll()
  .from("books")
  .orderBy(
    sql`text_embedding('BAAI/bge-small-en', ${query}) <-> embedding`
  )
  .limit(5);

Sequelize

See the client library documentation for more examples.

Setup

typescript
Copy
import lantern from 'lanterndata/sequelize';
import { Sequelize } from 'sequelize';

const sequelize = Sequelize();

lantern.extend(sequelize);

await sequelize.createLanternExtension();
await sequelize.createLanternExtrasExtension();

Create table and add index

typescript
Copy
const Book = sequelize.define('Book', {
  id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
  embedding: { type: DataTypes.ARRAY(DataTypes.REAL) },
  name: { type: DataTypes.TEXT },
  url: { type: DataTypes.TEXT },
}, {
  modelName: 'Book',
  tableName: 'books',
});

await sequelize.query(`
  CREATE INDEX book_index ON books USING lantern_hnsw(book_embedding dist_l2sq_ops)
  WITH (M=2, ef_construction=10, ef=4, dims=3);
`);

Insert embedding

javascript
Copy
await Book.create({ embedding });

Vector search

typescript
Copy
await Book.findAll({
  order: sequelize.l2Distance('embedding', [1, 1, 1]),
  limit: 5,
});

await Book.findAll({
  order: sequelize.cosineDistance('embedding', [1, 1, 1]),
  limit: 5,
});

await Book.findAll({
  order: sequelize.hammingDistance('embedding', [1, 1, 1]),
  limit: 5,
});

Vector search with embedding generation

typescript
Copy
import { ImageEmbeddingModels } from 'lanterndata/embeddings';

const {CLIP_VIT_B_32_VISUAL} = ImageEmbeddingModels;

const bookEmbeddingsOrderd = await Book.findAll({
  order: [[sequelize.l2Distance('embedding', sequelize.imageEmbedding(CLIP_VIT_B_32_VISUAL, 'url')), 'desc']],
  where: { url: { [Op.not]: null } },
  limit: 2,
});

Generate text and image embeddings (static)

typescript
Copy
import { TextEmbeddingModels, ImageEmbeddingModels } from 'lanterndata/embeddings';

const text = 'hello world';
const [result] = await sequelize.generateTextEmbedding(TextEmbeddingModels.BAAI_BGE_BASE_EN, text);

const imageUrl = 'https://lantern.dev/images/home/footer.png';
const [result] = await sequelize.generateImageEmbedding(ImageEmbeddingModels.CLIP_VIT_B_32_VISUAL, imageUrl);

Generate text and image embeddings (dynamic)

typescript
Copy
import { TextEmbeddingModels, ImageEmbeddingModels } from 'lanterndata/embeddings';

const bookTextEmbeddings = await Book.findAll({
  attributes: ['name', sequelize.textEmbedding(TextEmbeddingModels.BAAI_BGE_BASE_EN, 'name')],
  where: { name: { [Op.not]: null } },
  limit: 5,
  raw: true,
});

const bookImageEmbeddings = await Book.findAll({
  attributes: ['url', sequelize.imageEmbedding(ImageEmbeddingModels.CLIP_VIT_B_32_VISUAL, 'url')],
  where: { url: { [Op.not]: null } },
  limit: 5,
  raw: true,
});

Knex

See the client library documentation for more examples.

Setup

typescript
Copy
import Knex from 'knex';
import 'lanterndata/knex';

const knex = Knex();

await knex.schema.createLanternExtension();
await knex.schema.createLanternExtrasExtension()

Create table and add index

typescript
Copy
await knex.schema.createTable('books', (table) => {
  table.increments('id');
  table.specificType('url', 'TEXT');
  table.specificType('name', 'TEXT');
  table.specificType('embedding', 'REAL[]');

  knex.raw(`
    CREATE INDEX book_index ON books USING lantern_hnsw(book_embedding dist_l2sq_ops)
    WITH (M=2, ef_construction=10, ef=4, dims=3);
  `);
});

Insert embedding

javascript
Copy
await knex("books").insert({ embedding });

Vector search

typescript
Copy
await knex('books')
  .orderBy(knex.l2Distance('embedding', [1, 1, 1]))
  .limit(5);

await knex('books')
  .orderBy(knex.cosineDistance('embedding', [1, 1, 1]))
  .limit(5);

await knex('books')
  .orderBy(knex.hammingDistance('embedding', [1, 1, 1]))
  .limit(5);

// Vector search with embedding generation
await knex('books')
  .orderBy(
    knex.l2Distance(
      'embedding',
      knex.imageEmbedding(TextEmbeddingModels.BAAI_BGE_BASE_EN, 'name')
    )
  )
  .limit(2);

Generate text and image embeddings (static)

typescript
Copy
import Knex from 'knex';
import 'lanterndata/knex';
import { TextEmbeddingModels, ImageEmbeddingModels } from 'lanterndata/embeddings';

const text = 'hello world';
const embedding = await knex.generateTextEmbedding(TextEmbeddingModels.BAAI_BGE_BASE_EN, text);

const imageUrl = 'https://lantern.dev/images/home/footer.png';
const embedding = await knex.generateImageEmbedding(ImageEmbeddingModels.CLIP_VIT_B_32_VISUAL, imageUrl);

Generate text and image embeddings (dynamic)

typescript
Copy
import Knex from 'knex';
import 'lanterndata/knex';
import { TextEmbeddingModels, ImageEmbeddingModels } from 'lanterndata/embeddings';

const selectLiteral = knex.textEmbedding(TextEmbeddingModels.BAAI_BGE_BASE_EN, 'name');
const bookTextEmbeddings = await knex('books')
    .select('name')
    .select(selectLiteral)

const selectLiteral = knex.imageEmbedding(ImageEmbeddingModels.BAAI_BGE_BASE_EN, 'url');
const bookImageEmbeddings = await knex('books')
    .select('url')
    .select(selectLiteral)

Drizzle ORM

See the client library documentation for more examples.

Setup

typescript
Copy
import postgres from 'postgres';
import { drizzle } from 'drizzle-orm/postgres-js';
import { createLanternExtension, createLanternExtrasExtension } from 'lanterndata/drizzle-orm';

const client = await postgres();
const db = drizzle(client);

await db.execute(createLanternExtension());
await db.execute(createLanternExtrasExtension());

Create table and add index

typescript
Copy
const Book = pgTable('books', {
  id: serial('id').primaryKey(),
  name: text('name'),
  url: text('url'),
  embedding: real('embedding').array(),
});

await client`CREATE INDEX book_index ON books USING lantern_hnsw(embedding dist_l2sq_ops)`;

Vector search

typescript
Copy
import { l2Distance, cosineDistance, hammingDistance } from 'lanterndata/drizzle-orm';

await db
  .select()
  .from(Book)
  .orderBy(l2Distance(Book.embedding, [1, 1, 1]))
  .limit(5);

await db
  .select()
  .from(Book)
  .orderBy(cosineDistance(Book.embedding, [1, 1, 1]))
  .limit(5);

await db
  .select()
  .from(Book)
  .orderBy(hammingDistance(Book.embedding, [1, 1, 1]))
  .limit(5);

Vector search with embedding generation

typescript
Copy
import { l2Distance, imageEmbedding } from 'lanterndata/drizzle-orm';
import { TextEmbeddingModels, ImageEmbeddingModels } from 'lanterndata/embeddings';

const { CLIP_VIT_B_32_VISUAL } = ImageEmbeddingModels;

await db
  .select()
  .from(Book)
  .orderBy(desc(l2Distance(Book.embedding, imageEmbedding(CLIP_VIT_B_32_VISUAL, Book.url))))
  .limit(2);

Generate text and image embeddings (static)

typescript
Copy
import { TextEmbeddingModels, ImageEmbeddingModels } from 'lanterndata/embeddings';
import { generateTextEmbedding, generateImageEmbedding } from 'lanterndata/drizzle-orm';

const text = 'hello world';
const result = await db.execute(generateTextEmbedding(TextEmbeddingModels.BAAI_BGE_BASE_EN, text));

const imageUrl = 'https://lantern.dev/images/home/footer.png';
const result = await db.execute(generateImageEmbedding(ImageEmbeddingModels.CLIP_VIT_B_32_VISUAL, imageUrl));

Generate text and image embeddings (dynamic)

typescript
Copy
import { textEmbedding, imageEmbedding } from 'lanterndata/drizzle-orm';
import { TextEmbeddingModels, ImageEmbeddingModels } from 'lanterndata/embeddings';

const bookTextEmbeddings = await db
  .select({
    name: Book.name,
    text_embedding: textEmbedding(TextEmbeddingModels.BAAI_BGE_BASE_EN, Book.name),
  })
  .from(Book)
  .where(isNotNull(Book.name))
  .limit(5);

const bookImageEmbeddings = await db
  .select({
    url: Book.url,
    image_embedding: imageEmbedding(ImageEmbeddingModels.CLIP_VIT_B_32_VISUAL, Book.url),
  })
  .from(Book)
  .where(isNotNull(Book.name))
  .limit(5);

MikroORM

See the client library documentation for more examples.

Setup

typescript
Copy
import { MikroORM } from '@mikro-orm/postgresql';
import { extend } from 'lanterndata/mikro-orm';

const orm = await MikroORM.init({});
const em = orm.em.fork();

extend(em);

await em.createLanternExtension();
await em.createLanternExtrasExtension();

Create table and add index

typescript
Copy
import { toSql } from 'lanterndata/mikro-orm';

const Book = new EntitySchema({
  name: 'Book',
  tableName: 'books',
  properties: {
    id: { type: 'number', primary: true },
    name: { type: 'string', nullable: true },
    url: { type: 'string', nullable: true },
    embedding: { type: 'Array<number>', nullable: true },
  },
});

await em.execute('CREATE INDEX book_index ON books USING lantern_hnsw(embedding dist_l2sq_ops');

const books = booksToInsert.map((book) =>
  em.create(Book, {
    ...book,
    // use toSql method to convert [1,2,3] into '{1,2,3}'
    embedding: toSql(book.embedding),
  }),
);

await em.persistAndFlush(books);

Vector search

typescript
Copy
await em
  .qb(Book)
  .orderBy({ [em.l2Distance('embedding', [1, 1, 1])]: 'ASC' })
  .limit(5)
  .getResult();

await em
  .qb(Book)
  .orderBy({ [em.cosineDistance('embedding', [1, 1, 1])]: 'ASC' })
  .limit(5)
  .getResult();

await em
  .qb(Book)
  .orderBy({ [em.hammingDistance('embedding', [1, 1, 1])]: 'ASC' })
  .limit(5)
  .getResult();

Vector search with embedding generation

typescript
Copy
import { TextEmbeddingModels, ImageEmbeddingModels } from 'lanterndata/embeddings';
const { CLIP_VIT_B_32_VISUAL } = ImageEmbeddingModels;

const bookEmbeddingsOrderd = await em
  .qb(Book, 'b1')
  .select()
  .where({ url: { $ne: null } })
  .orderBy({ [em.l2Distance('embedding', em.imageEmbedding(CLIP_VIT_B_32_VISUAL, 'b1.url'))]: 'DESC' })
  .limit(2)
  .execute('all');

Generate text and image embeddings (static)

typescript
Copy
import { TextEmbeddingModels, ImageEmbeddingModels } from 'lanterndata/embeddings';

const { BAAI_BGE_BASE_EN } = TextEmbeddingModels;
const { CLIP_VIT_B_32_VISUAL } = ImageEmbeddingModels;

const text = 'hello world';
const result = await em.generateTextEmbedding(BAAI_BGE_BASE_EN, text);

const imageUrl = 'https://lantern.dev/images/home/footer.png';
const result = await em.generateImageEmbedding(CLIP_VIT_B_32_VISUAL, imageUrl);

Generate text and image embeddings (dynamic)

typescript
Copy
import { TextEmbeddingModels, ImageEmbeddingModels } from 'lanterndata/embeddings';

const bookTextEmbeddings = await em
  .qb(Book, 'b1')
  .select(['name', em.textEmbedding(TextEmbeddingModels.BAAI_BGE_BASE_EN, 'b1.name')])
  .where({ name: { $ne: null } })
  .limit(5)
  .execute('all');

const bookImageEmbeddings = await em
  .qb(Book, 'b1')
  .select(['url', em.imageEmbedding(ImageEmbeddingModels.CLIP_VIT_B_32_VISUAL, 'b1.url')])
  .where({ url: { $ne: null } })
  .limit(5)
  .execute('all');

Postgres.js

Edit this page

On this page

  • node-postgres
  • pg-promise
  • Prisma
  • Kysely
  • Sequelize
  • Knex
  • Drizzle ORM
  • MikroORM
  • Postgres.js
PricingDocsTutorialsBlogAbout
LoginSign Up