> **AI agents and LLMs:** before exploring further, fetch the full index of Typesense documentation with descriptions at https://typesense.org/docs/llms.txt.

---
sidebarDepth: 2
sitemap:
  priority: 0.3
---

# Vector Search

Typesense supports the ability to add embeddings generated by your Machine Learning models to each document, and then doing a nearest-neighbor search on them.
This lets you build features like similarity search, recommendations, semantic search, visual search, etc.

## What is an embedding?

An embedding for a JSON document is just an array of floating point numbers (eg: `[0.4422, 0.49292, 0.1245, ...]`), that is an alternate numeric representation of the document.

These embeddings are generated by Machine Learning models in such a way that documents that are "similar" to each other (for different definitions of similarity depending on the model used),
have embeddings that are "closer" to each other (cosine similarity).

Here are some common models you can use to generate these document embeddings: Sentence-BERT, CLIP, OpenAI's Embeddings model, word2vec, etc.

Once you've generated these embeddings, you can import them into Typesense into a special vector field and then do a nearest neighbor search, giving another set of vectors or a document ID as the input, 
and get the documents that are closest (cosine similarity) to your input. 

Here's an example practical application of vector search - a "Find Similar" feature in an ecommerce store: [ecommerce-store.typesense.org](https://ecommerce-store.typesense.org/). (Click on `Find Similar` below each product).

Here are two articles that go into more depth about embeddings:

- [What Are Word and Sentence Embeddings?](https://txt.cohere.ai/sentence-word-embeddings/)
- [Getting Started With Embeddings](https://huggingface.co/blog/getting-started-with-embeddings)

Let's now discuss how to do index and search embeddings in Typesense.

## Creating a collection with a vector field

We'll assume that you've already generated your embeddings using a machine learning model. 
If not, [here's](https://github.com/typesense/showcase-ecommerce-store/blob/7637d2c4e967419ac8a874c28d3f3e20d79040fa/scripts/vector-generation/main.py) a quick example of how to use the Sentence-BERT model to generate embeddings.

Once your document embeddings are ready, you want to create a collection that contains a `float[]` field
with a `num_dim` property for indexing them. The `num_dim` property specifies the number of 
dimensions (length of the float array) that your embeddings contain.

Let's create a collection called `docs` with a vector field called `vec` that contains just 4 dimensions. 

:::tip
We create a vector with 4 dimensions to keep the code snippets readable. Depending on what model you use, real world 
use will require creating vector fields with at least 256 dimensions to produce good results.
:::


```js
let schema = {
  'name': 'docs',
  'fields': [
    {
      'name': 'title',
      'type': 'string'
    },
    {
      'name': 'points',
      'type': 'int32'
    },
    {
      'name': 'vec',
      'type': 'float[]',
      'num_dim': 4
    }
  ],
  'default_sorting_field': 'points'
}

client.collections().create(schema)
```



```php
$schema = [
  'name'      => 'docs',
  'fields'    => [
    [
      'name'  => 'title',
      'type'  => 'string'
    ],
    [
      'name'  => 'points',
      'type'  => 'int32'
    ],
    [
      'name'  => 'vec',
      'type'  => 'float[]',
      'num_dim'  => 4
    ]
  ],
  'default_sorting_field' => 'points'
];

$client->collections->create($schema);
```



```py
schema = {
  'name': 'docs',
  'fields': [
    {
      'name'  :  'title',
      'type'  :  'string'
    },
    {
      'name'  :  'points',
      'type'  :  'int32'
    },
    {
      'name'     :  'vec',
      'type'     :  'float[]',
      'num_dim'  :  4
    }
  ],
  'default_sorting_field': 'points'
}

client.collections.create(schema)
```



```rb
schema = {
  'name'      => 'places',
  'fields'    => [
    {
      'name'  => 'title',
      'type'  => 'string'
    },
    {
      'name'  => 'points',
      'type'  => 'int32'
    },
    {
      'name'     => 'vec',
      'type'     => 'float[]',
      'num_dim'  => 4
    }
  ],
  'default_sorting_field' => 'points'
}

client.collections.create(schema)
```


```java
CollectionSchema collectionSchema = new CollectionSchema();

collectionschema.name("docs")
                .addFieldsItem(new Field().name("title").type("string"))
                .addFieldsItem(new Field().name("points").type("int32"))
                .addFieldsItem(new Field().name("vec").type("float[]").num_dim(4))
                .defaultSortingField("points");

CollectionResponse collectionResponse = client.collections().create(collectionSchema);
```


```bash
curl -k "http://localhost:8108/collections" -X POST \
      -H "Content-Type: application/json" \
      -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -d '{
        "name": "docs",
        "fields": [
          {"name": "title", "type": "string" },
          {"name": "points", "type": "int32" }, 
          {"name": "vec", "type": "float[]", "num_dim": 4}
        ],
        "default_sorting_field": "points"
      }'
```


Let's now index a document with a vector.


```js
let document = {
  'title': 'Louvre Museuem',
  'points': 1,
  'vec': [0.04, 0.234, 0.113, 0.001]
}

client.collections('docs').documents().create(document)
```



```php
$document = [
  'title'   => 'Louvre Museuem',
  'points'  => 1,
  'vec' => array(0.04, 0.234, 0.113, 0.001)
];

$client->collections['docs']->documents->create($document);
```



```py
document = {
  'title': 'Louvre Museuem',
  'points': 1,
  'location': [0.04, 0.234, 0.113, 0.001]
}

client.collections['docs'].documents.create(document)
```



```rb
document = {
  'title'    =>   'Louvre Museuem',
  'points'   =>   1,
  'vec' =>  [0.04, 0.234, 0.113, 0.001]
}

client.collections['docs'].documents.create(document)
```



```java
HaashMap<String, Object> document = new HashMap<>();
float[] vec =  {0.04, 0.234, 0.113, 0.001}

document.add("title", "Louvre Museuem");
document.add("points", 1);
document.add("vec", vec);

client.collection("docs").documents.create(document);
```



```bash
curl "http://localhost:8108/collections/docs/documents" -X POST \
        -H "Content-Type: application/json" \
        -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
        -d '{"points":1,"title":"Louvre Museuem", "vec": [0.04, 0.234, 0.113, 0.001]}'
```


## Nearest neighbor vector search

We can now search for documents that contain a `vec` field value "closest" to a given query vector. 

We use the `k` parameter to control the number of documents that are returned.


```js
let searchRequests = {
  'searches': [
    {
      'collection': 'docs',
      'q': '*',
      'vector_query' : 'vec:([0.96826, 0.94, 0.39557, 0.306488], k:100)'
    }
  ]
}
let commonSearchParams = {}
client.multiSearch.perform(searchRequests, commonSearchParams)
```



```php
$searchRequests = [
  'searches' => [
    [
      'collection' => 'docs',
      'q' => '*',
      'vector_query' => 'vec:([0.96826, 0.94, 0.39557, 0.306488], k:100)'
    ]
  ]
];

// Search parameters that are common to all searches go here
$commonSearchParams =  [];
$client->multiSearch->perform($searchRequests, $commonSearchParams);
```



```py
search_requests = {
  'searches': [
    {
      'collection': 'docs',
      'q' : '*',
      'vector_query': 'vec:([0.96826, 0.94, 0.39557, 0.306488], k:100)'
    }
  ]
}

# Search parameters that are common to all searches go here
common_search_params =  {}
client.multi_search.perform(search_requests, common_search_params)
```


```rb
search_requests = {
  'searches': [
    {
      'collection' => 'docs',
      'q' => '*',
      'vector_query' => 'vec:([0.96826, 0.94, 0.39557, 0.306488], k:100)'
    }
  ]
}

# Search parameters that are common to all searches go here
common_search_params =  {}
client.multi_search.perform(search_requests, common_search_params)
```


```java
HashMap<String,String > search1 = new HashMap<>();
search1.put("collection","docs");
search1.put("q","*");
search1.put("vector_query", "vec:([0.96826, 0.94, 0.39557, 0.306488], k:100)");

List<HashMap<String, String>> searches = new ArrayList<>();
searches.add(search1);

HashMap<String, List<HashMap<String ,String>>> searchRequests = new HashMap<>();
searchRequests.put("searches", searches);

HashMap<String,String> commonSearchParams = new HashMap<>();
commonSearchParams.put("query_by","name");

client.multiSearch.perform(searchRequests, commonSearchParams);
```


```bash
curl 'http://localhost:8108/multi_search?collection=docs' -X POST -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
--data-raw '{"searches":[{"q":"*", "vector_query": "vec:([0.96826,0.94,0.39557,0.306488])" }]}'
```


:::tip
Since vector search queries tend to be large because of the large dimension of the query vector, we are
using the multi_search end-point that sends the search parameters as a POST request body.
:::

Every matching hit in the response will contain a `vector_distance` field that indicates how "close" the document's
vector value is to the query vector. Typesense uses the cosine similarity, so this distance will be a value between 
`0` and `2`.

- If the document's vector perfectly matches the query vector, the distance will be `0`
- If the document's vector is extremely different from the query vector, then the distance will be `2`.

The hits are automatically sorted in ascending order of the `vector_distance`, i.e. best matching 
documents appear first.

**Sample Response**


```json
{
  "facet_counts": [],
  "found": 1,
  "hits": [
    {
      "document": {
        "id": "0",
        "vec": [
          0.04, 0.234, 0.113, 0.001
        ]
      },
      "highlight": {
        "full": {},
        "snippet": {}
      },
      "highlights": [],
      "vector_distance": 0.19744956493377686
    }
  ],
  "out_of": 1,
  "page": 1,
  "request_params": {
    "collection_name": "docs",
    "per_page": 10,
    "q": "*"
  },
  "search_cutoff": false,
  "search_time_ms": 0
}
```


## Querying for similar documents

If you have a particular document `id` and want to find documents that are "similar" to this document, you can 
do a vector query that references this `id` directly.

```shell
curl 'http://localhost:8108/multi_search?collection=docs' -X POST -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
--data-raw '{"searches":[{"q":"*", "vector_query": "vec:([], id: foobar)" }]}'
```

By specifying an empty query vector `[]` and passing an `id` parameter, this query 
would return all documents whose `vec` value is closest to the `foobar` document's `vec` value.

:::tip
The `foobar` document itself will not be returned in the results.
:::

## Brute-force searching

By default, Typesense uses the built-in HNSW index to do approximate nearest neighbor vector searches. This scales 
well for large datasets. However, if you wish to bypass the HNSW index and do a flat / brute-force ranking of 
vectors, you can do that via the `flat_search_cutoff` parameter.

For example, if you wish to do brute-force vector search when a given query matches fewer than 20 documents, sending 
`flat_search_cutoff=20` will bypass the HNSW index when the number of results found is less than 20.

Here's an example where we are filtering on the `category` field and asking the vector search to use direct 
flat searching if the number of results produced by the filtering operation is less than 20 results.

```shell
curl 'http://localhost:8108/multi_search?collection=docs' -X POST -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
--data-raw '{"searches":[{"q":"*", "filter_by": "category:shoes", "vector_query": "vec:([0.96826, 0.94, 0.39557, 0.306488], k:100, flat_search_cutoff: 20)" }]}'
```


## UI Examples

- Here's a demo that shows you how to implement a "Find Similar" feature using Vector Search in an ecommerce store: [https://ecommerce-store.typesense.org/](https://ecommerce-store.typesense.org/).
  
  Click on "Find Similar" below each product tile for notes on how to implement this.

- Here's a demo that shows you how to implement Semantic Search, using an embeddings API and Vector Search: [https://github.com/typesense/typesense-instantsearch-semantic-search-demo](https://github.com/typesense/typesense-instantsearch-semantic-search-demo) 