Code Monkey home page Code Monkey logo

yusufhilmi / client-vector-search Goto Github PK

View Code? Open in Web Editor NEW
149.0 5.0 9.0 322 KB

A client side vector search library that can embed, store, search, and cache vectors. Works on the browser and node. It outperforms OpenAI's text-embedding-ada-002 and is way faster than Pinecone and other VectorDBs.

Home Page: https://www.npmjs.com/package/client-vector-search

License: MIT License

TypeScript 100.00%
embedding-models embedding-vectors embeddings openai search text-embeddings transformers vector vector-search

client-vector-search's Introduction

client-vector-search

A client side vector search library that can embed, search, and cache. Works on the browser and server side.

It outperforms OpenAI's text-embedding-ada-002 and is way faster than Pinecone and other VectorDBs.

I'm the founder of searchbase.app and we needed this for our product and customers. We'll be using this library in production. You can be sure it'll be maintained and improved.

  • Embed documents using transformers by default: gte-small (~30mb).
  • Calculate cosine similarity between embeddings.
  • Create an index and search on the client side
  • Cache vectors with browser caching support.

Lots of improvements are coming!

Roadmap

Our goal is to build a super simple, fast vector search that works with couple hundred to thousands vectors. ~1k vectors per user covers 99% of the use cases.

We'll initially keep things super simple and sub 100ms

TODOs

  • add HNSW index that works on node and browser env, don't rely on hnsw binder libs
  • add a proper testing suite and ci/cd for the lib
    • simple health tests
      • mock the @xenova/transformers for jest, it's not happy with it
    • performance tests, recall, memory usage, cpu usage etc.

Installation

npm i client-vector-search

Quickstart

This library provides a plug-and-play solution for embedding and vector search. It's designed to be easy to use, efficient, and versatile. Here's a quick start guide:

  import { getEmbedding, EmbeddingIndex } from 'client-vector-search';

  // getEmbedding is an async function, so you need to use 'await' or '.then()' to get the result
  const embedding = await getEmbedding("Apple"); // Returns embedding as number[]

  // Each object should have an 'embedding' property of type number[]
  const initialObjects = [
  { id: 1, name: "Apple", embedding: embedding },
  { id: 2, name: "Banana", embedding: await getEmbedding("Banana") },
  { id: 3, name: "Cheddar", embedding: await getEmbedding("Cheddar")},
  { id: 4, name: "Space", embedding: await getEmbedding("Space")},
  { id: 5, name: "database", embedding: await getEmbedding("database")},
  ];
  const index = new EmbeddingIndex(initialObjects); // Creates an index

  // The query should be an embedding of type number[]
  const queryEmbedding = await getEmbedding('Fruit'); // Query embedding
  const results = await index.search(queryEmbedding, { topK: 5 }); // Returns top similar objects

  // specify the storage type
  await index.saveIndex('indexedDB');
  const results = await index.search([1, 2, 3], {
    topK: 5,
    useStorage: 'indexedDB',
    // storageOptions: { // use only if you overrode the defaults
    //   indexedDBName: 'clientVectorDB',
    //   indexedDBObjectStoreName: 'ClientEmbeddingStore',
    // },
  });

  console.log(results);

  await index.deleteIndexedDB(); // if you overrode default, specify db name

Trouble-shooting

NextJS

To use it inside NextJS projects you'll need to update the next.config.js file to include the following:

module.exports = {
  // Override the default webpack configuration
  webpack: (config) => {
    // See https://webpack.js.org/configuration/resolve/#resolvealias
    config.resolve.alias = {
      ...config.resolve.alias,
      sharp$: false,
      "onnxruntime-node$": false,
    };
    return config;
  },
};

Model load after page is loaded

You can initialize the model before using it to generate embeddings. This will ensure that the model is loaded before you use it and provide a better UX.

import { initializeModel } from "client-vector-search"
...
  useEffect(() => {
    try {
      initializeModel();
    } catch (e) {
      console.log(e);
    }
  }, []);

Usage Guide

This guide provides a step-by-step walkthrough of the library's main features. It covers everything from generating embeddings for a string to performing operations on the index such as adding, updating, and removing objects. It also includes instructions on how to save the index to a database and perform search operations within it.

Until we have a reference documentation, you can find all the methods and their usage in this guide. Each step is accompanied by a code snippet to illustrate the usage of the method in question. Make sure to follow along and try out the examples in your own environment to get a better understanding of how everything works.

Let's get started!

Step 1: Generate Embeddings for String

Generate embeddings for a given string using the getEmbedding method.

const embedding = await getEmbedding("Apple"); // Returns embedding as number[]

Note: getEmbedding is asynchronous; make sure to use await.


Step 2: Calculate Cosine Similarity

Calculate the cosine similarity between two embeddings.

const similarity = cosineSimilarity(embedding1, embedding2, 6);

Note: Both embeddings should be of the same length.


Step 3: Create an Index

Create an index with an initial array of objects. Each object must have an 'embedding' property.

const initialObjects = [...];
const index = new EmbeddingIndex(initialObjects);

Step 4: Add to Index

Add an object to the index.

const objectToAdd = { id: 6, name: 'Cat', embedding: await getEmbedding('Cat') };
index.add(objectToAdd);

Step 5: Update Index

Update an existing object in the index.

const vectorToUpdate = { id: 6, name: 'Dog', embedding: await getEmbedding('Dog') };
index.update({ id: 6 }, vectorToUpdate);

Step 6: Remove from Index

Remove an object from the index.

index.remove({ id: 6 });

Step 7: Retrieve from Index

Retrieve an object from the index.

const vector = index.get({ id: 1 });

Step 8: Search the Index

Search the index with a query embedding.

const queryEmbedding = await getEmbedding('Fruit');
const results = await index.search(queryEmbedding, { topK: 5 });

Step 9: Print the Index

Print the entire index to the console.

index.printIndex();

Step 10: Save Index to IndexedDB (for browser)

Save the index to a persistent IndexedDB database. Note

await index.saveIndex("indexedDB", { DBName: "clientVectorDB", objectStoreName:"ClientEmbeddingStore"})

Important: Search in indexedDB

Perform a search operation in the IndexedDB.

const results = await index.search(queryEmbedding, {
  topK: 5,
  useStorage: "indexedDB",
  storageOptions: { // only if you want to override the default options, defaults are below
    indexedDBName: 'clientVectorDB',
    indexedDBObjectStoreName: 'ClientEmbeddingStore'
  }
});

---

### Delete Database
To delete an entire database.

```ts
await IndexedDbManager.deleteIndexedDB("clientVectorDB");

Delete Object Store

To delete an object store from a database.

await IndexedDbManager.deleteIndexedDBObjectStore("clientVectorDB", "ClientEmbeddingStore");

Retrieve All Objects

To retrieve all objects from a specific object store.

const allObjects = await IndexedDbManager.getAllObjectsFromIndexedDB("clientVectorDB", "ClientEmbeddingStore");

client-vector-search's People

Contributors

lurrobert avatar shunnnet avatar yusufhilmi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

client-vector-search's Issues

Use modern JavaScript

while typescript is popular for legacy reasons (it came out when js had no classes/modules and people were using babel transpile anyways for browsers), the reach and longevity of this codebase would be better served by not having dependency on the whole typescript build system. Given this is for a 'browser native' capability, the code would be better developed as browser native.
The value of having the code that runs be the same code that is developed should not be discarded. Built using native browser JS tech should be a badge of honor and is certainly 'feasible' with a library of this size.

It may be great if combine `client-vector-search` with `browser-ai`

Hello, I am Net Chen. A frontend developer from Taiwan.

I am working on the package called browser-ai recently.

The goal of this package is to run applications like Langchain in the browser, but aiming for simplicity. Its main features include the ability to directly convert routes or DOM into prompts, interact with LLM for Q&A, and even perform web navigation. It can also work in conjunction with transformer.js.

When dealing with many pages and DOM elements, the need for a vector index arises. As I began searching for a browser-side solution, I came across client-vector-search, which turned out to be the ideal package I was looking for.

I want to express my gratitude for creating this package.

Though I haven't started the integration yet, I've written a small example demonstrating how they can be combined.

If you are willing, you can visit the browser-ai repository's example/qa/pages/PageIndex.vue directory to see how they are integrated.

To run the example, follow these steps:

  1. Run pnpm install at root directory
  2. Run pnpm build at root directory
  3. cd to example/qa
  4. Create .env file at example/qa and set env variable VITE_OPENAI_API_KEY=<your-openai-key>
  5. and run pnpm dev
  6. Open localhost:5173
  7. Open the console
  8. Type some question like How to setup agent in input at top of page then click then button.
  9. You will see the answer and the page should be scrolled to the related element.

Allow the `.update` method to update only attributes other than embedding.

I hope to implement a functionality similar to soft delete. The approach would involve directly updating certain attributes of the object, such as setting deleted to true. However, the current .update(filter, vector) method seems challenging to achieve this. The vector parameter requires the embedding attribute; otherwise, an error will be thrown. This necessitates storing the same vector externally to achieve the desired result.

Perhaps I could submit a Pull Request to allow updating only attributes other than embedding?

Too much memory usage

5k+ takes too much space in memory, just create batches between 2k-5k.

I have 30k vectors and I cannot use indexDb. Keeping the index in memory does not make sense.

Screenshot 2023-11-13 at 8 54 18 PM

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.