# Vector Search

Typesense has the ability to index [embeddings](#what-is-an-embedding) generated by any machine learning model, and then do a nearest-neighbor (KNN) search on this data.

[[toc]]

## Use-cases

Here are some example use-cases you can build, using vector search as the foundation:

1. [Semantic search](../../guide/semantic-search.md)
2. [Recommendations](../../guide/recommendations.md)
3. [Hybrid search](#hybrid-search) (Keyword Search + Semantic Search + Filtering)
4. Visual image search
5. [Integrate with LLMs](https://python.langchain.com/docs/integrations/vectorstores/typesense), to get them to respond to queries using your own dataset (RAG)

You can also combine any of the above with features like filtering, faceting, sorting, grouping, etc to build a user-friendly search experience.

## 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
- E-5
- CLIP
- OpenAI's Text Embeddings model
- Google's PaLM API
- Google's Vertex API

You can import embeddings generated by these models 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.

You can also have Typesense generate these embeddings for you, using OpenAI, PaLM API or one of the built-in ML models listed [here](https://huggingface.co/typesense/models/tree/main).

#### Live Demo

Here is one (of many possible) practical applications 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).

#### Read More

Here are two articles that talk about embeddings in more detail:

- [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.

## Index Embeddings

### Option A: Importing externally-generated embeddings into Typesense

If you have already generated embeddings using your own models outside Typesense, you can import them into Typesense.

:::tip
[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 outside Typesense.
:::

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 `embedding` that contains just 4 dimensions.

:::tip
We're creating a vector with 4 dimensions in the examples 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.
:::

<Tabs :tabs="['JavaScript','PHP','Python','Ruby', 'Dart','Java','Go','Shell']">
  <template v-slot:JavaScript>

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

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

  </template>

<template v-slot:PHP>

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

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

  </template>

<template v-slot:Python>

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

client.collections.create(schema)
```

  </template>

<template v-slot:Ruby>

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

client.collections.create(schema)
```

  </template>
  <template v-slot:Dart>

```dart
final schema = Schema(
  'docs',
  {
    Field('title', type: Type.string),
    Field('points', type: Type.int32),
    Field('embedding', type: Type.float, isMultivalued: true, dimensions: 4),
  },
  defaultSortingField: Field('points', type: Type.int32),
);

await client.collections.create(schema);

```

  </template>
<template v-slot:Java>

```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("embedding").type("float[]").num_dim(4))
                .defaultSortingField("points");

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

  </template>
<template v-slot:Go>

```go
schema := &api.CollectionSchema{
  Name: "docs",
  Fields: []api.Field{
    {
      Name: "title",
      Type: "string",
    },
    {
      Name: "points",
      Type: "int32",
    },
    {
      Name:   "embedding",
      Type:   "float[]",
      NumDim: pointer.Int(4),
    },
  },
  DefaultSortingField: pointer.String("points"),
}

client.Collections().Create(context.Background(), schema)
```

  </template>
  <template v-slot:Shell>

```bash
curl "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": "embedding", "type": "float[]", "num_dim": 4}
            ],
            "default_sorting_field": "points"
          }'
```

  </template>
</Tabs>

Let's now index a document with a vector.

<Tabs :tabs="['JavaScript','PHP','Python','Ruby', 'Dart','Java','Go','Shell']">
  <template v-slot:JavaScript>

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

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

  </template>

<template v-slot:PHP>

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

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

  </template>

<template v-slot:Python>

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

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

  </template>

<template v-slot:Ruby>

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

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

  </template>
  <template v-slot:Dart>

```dart
final document = {
  'title': 'Louvre Museuem',
  'points': 1,
  'embedding': [0.04, 0.234, 0.113, 0.001]
};

await client.collection('docs').documents.create(document);

```

  </template>

  <template v-slot:Java>

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

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

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

  </template>

  <template v-slot:Go>

```go
document := struct {
  Title     string    `json:"title"`
  Points    int32     `json:"points"`
  Embedding []float64 `json:"embedding"`
}{
  Title:     "Louvre Museuem",
  Points:    1,
  Embedding: []float64{0.04, 0.234, 0.113, 0.001},
}

client.Collection("docs").Documents().Create(context.Background(), document)
```

  </template>

  <template v-slot:Shell>

```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", "embedding": [0.04, 0.234, 0.113, 0.001]}'
```

  </template>
</Tabs>

### Option B: Auto-embedding generation within Typesense

To simplify the process of embedding generation, Typesense can automatically use your JSON data and either OpenAI API, PaLM API or any of the built-in embedding models listed [here](https://huggingface.co/typesense/models/tree/main) to generate & store embeddings.

When you do a search query on this automatically-generated vector field, your search query will be vectorized using the same model used for the field, which then allows you to do semantic search or combine keyword and semantic search to do hybrid search.

:::tip Embedding Updates
Embeddings are only regenerated when one or more fields specified in the `embed.from` configuration are updated. This helps avoid unnecessary embedding recreation and API calls when other fields in the document are modified.
:::

### Creating an auto-embedding field

To create a field that automatically embeds other string or string array fields, you need to set the `embed` property of the field.

Here's an example:

<Tabs :tabs="['JavaScript','PHP','Python', 'Ruby', 'Java','Go','Shell']">

  <template v-slot:JavaScript>

```js
let schema = {
  "name": "products",
  "fields": [
    {
      "name": "product_name",
      "type": "string"
    },
    {
      "name": "categories",
      "type": "string[]"
    },
    {
      "name": "embedding",
      "type": "float[]",
      "embed": {
        "from": [
          "product_name",
          "categories"
        ],
        "model_config": {
          "model_name": "ts/e5-small"
        }
      }
    }
  ]
};

client.collections('products').create(schema);

```
  </template>

  <template v-slot:PHP>

```php
$schema = [
  "name" => "products",
  "fields" => [
    [
      "name" => "product_name",
      "type" => "string"
    ],
    [
      "name" => "categories",
      "type" => "string[]"
    ],
    [
      "name" => "embedding",
      "type" => "float[]",
      "embed" => [
        "from" => [
          "product_name",
          "categories"
        ],
        "model_config" => [
          "model_name" => "ts/e5-small"
        ]
      ]
    ]
  ]
];

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

```

  </template>
  <template v-slot:Python>

```py
schema = {
  "name": "products",
  "fields": [
    {
      "name" : "product_name",
      "type" : "string"
    },
    {
      "name" : "categories",
      "type" : "string[]"
    },
    {
      "name" : "embedding",
      "type" : "float[]",
      "embed": {
        "from": [
          "product_name",
          "categories"
        ],
        "model_config": {
          "model_name": "ts/e5-small"
        }
      }
    }
  ]
}

client.collections.create(schema)
```

  </template>

  <template v-slot:Ruby>

```rb

schema = {
  "name" => "products",
  "fields" => [
    {
      "name" => "product_name",
      "type" => "string"
    },
    {
      "name" => "categories",
      "type" => "string[]"
    },
    {
      "name" => "embedding",
      "type" => "float[]",
      "embed" => {
        "from" => [
          "product_name",
          "categories"
        ],
        "model_config" => {
          "model_name" => "ts/e5-small"
        }
      }
    }
  ]
}

client.collections.create(schema)
```
  </template>

  <template v-slot:Java>

```java
CollectionSchema collectionSchema = new CollectionSchema();
ArrayList<String> embedFrom = new ArrayList<>();
embedFrom.add("product_name");
embedFrom.add("categories");

collectionschema.name("products")
                .addFieldsItem(new Field().name("product_name").type(FieldTypes.STRING))
                .addFieldsItem(new Field().name("categories").type(FieldTypes.STRING_ARRAY))
                .addFieldsItem(new Field().name("embedding").type(FieldTypes.FLOAT_ARRAY).embed(
                  new FieldEmbed().from(embedFrom).modelConfig(new FieldEmbedModelConfig().modelName("ts/e5-small"))
                ));

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

  </template>

  <template v-slot:Go>

```go
schema := &api.CollectionSchema{
  Name: "products",
  Fields: []api.Field{
    {
      Name: "product_name",
      Type: "string",
    },
    {
      Name: "categories",
      Type: "string[]",
    },
    {
      Name: "embedding",
      Type: "float[]",
      Embed: &struct {
        From        []string "json:\"from\""
        ModelConfig struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        } "json:\"model_config\""
      }{
        From: []string{"product_name", "categories"},
        ModelConfig: struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        }{
          ModelName: "ts/e5-small",
        },
      },
    },
  },
}

client.Collections().Create(context.Background(), schema)
```

  </template>

  <template v-slot:Shell>

```bash
curl 'http://localhost:8108/collections' \
  -X POST \
  -H 'Content-Type: application/json' \
  -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
  -d '{
        "name": "products",
        "fields": [
          {
            "name": "product_name",
            "type": "string"
          },
          {
            "name": "categories",
            "type": "string[]"
          },
          {
            "name": "embedding",
            "type": "float[]",
            "embed": {
              "from": [
                "product_name",
                "categories"
              ],
              "model_config": {
                "model_name": "ts/e5-small"
              }
            }
          }
        ]
      }'

```
   </template>
</Tabs>

In this example the `embedding` vector field will be generated automatically while indexing a document, using the concatenated values of the `product_name` and `categories` fields (separated by spaces).

### Using Built-in Models

These models are officially supported by Typesense and stored in the Typesense Hugging Face repository [here](https://huggingface.co/typesense/models/tree/main).

You can specify them by adding the ```ts``` namespace before the model name. Typesense will automatically download these models and make them available for use when you index documents after creating the collection.

<Tabs :tabs="['JavaScript','PHP','Python', 'Ruby', 'Java','Go','Shell']">

  <template v-slot:JavaScript>

```js
let schema = {
  "name": "products",
  "fields": [
    {
      "name": "brand",
      "type": "string"
    },
    {
      "name": "categories",
      "type": "string[]"
    },
    {
      "name": "embedding",
      "type": "float[]",
      "embed": {
        "from": [
          "brand",
          "categories"
        ],
        "model_config": {
          "model_name": "ts/all-MiniLM-L12-v2"
        }
      }
    }
  ]
};

client.collections('products').create(schema);

```
  </template>

  <template v-slot:PHP>

```php
$schema = [
  "name" => "products",
  "fields" => [
    [
      "name" => "brand",
      "type" => "string"
    ],
    [
      "name" => "categories",
      "type" => "string[]"
    ],
    [
      "name" => "embedding",
      "type" => "float[]",
      "embed" => [
        "from" => [
          "brand",
          "categories"
        ],
        "model_config" => [
          "model_name" => "ts/all-MiniLM-L12-v2"
        ]
      ]
    ]
  ]
];

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

```

  </template>

  <template v-slot:Python>

```py
schema = {
  "name": "products",
  "fields": [
    {
      "name" : "brand",
      "type" : "string"
    },
    {
      "name" : "categories",
      "type" : "string[]"
    },
    {
      "name" : "embedding",
      "type" : "float[]",
      "embed": {
        "from": [
          "brand",
          "categories"
        ],
        "model_config": {
          "model_name": "ts/all-MiniLM-L12-v2"
        }
      }
    }
  ]
}

client.collections.create(schema)
```

  </template>

  <template v-slot:Ruby>

```rb
schema = {
  "name" => "products",
  "fields" => [
    {
      "name" => "brand",
      "type" => "string"
    },
    {
      "name" => "categories",
      "type" => "string[]"
    },
    {
      "name" => "embedding",
      "type" => "float[]",
      "embed" => {
        "from" => [
          "brand",
          "categories"
        ],
        "model_config" => {
          "model_name" => "ts/all-MiniLM-L12-v2"
        }
      }
    }
  ]
}

client.collections.create(schema)
```
  </template>

  <template v-slot:Java>

```java
CollectionSchema collectionSchema = new CollectionSchema();
ArrayList<String> embedFrom = new ArrayList<>();
embedFrom.add("product_name");
embedFrom.add("categories");

collectionschema.name("products")
                .addFieldsItem(new Field().name("product_name").type(FieldTypes.STRING))
                .addFieldsItem(new Field().name("categories").type(FieldTypes.STRING_ARRAY))
                .addFieldsItem(new Field().name("embedding").type(FieldTypes.FLOAT_ARRAY).embed(
                  new FieldEmbed().from(embedFrom).modelConfig(new FieldEmbedModelConfig().modelName("ts/all-MiniLM-L12-v2"))
                ));

CollectionResponse collectionResponse = client.collections().create(collectionSchema);
```
  </template>

  <template v-slot:Go>

```go
schema := &api.CollectionSchema{
  Name: "products",
  Fields: []api.Field{
    {
      Name: "brand",
      Type: "string",
    },
    {
      Name: "categories",
      Type: "string[]",
    },
    {
      Name: "embedding",
      Type: "float[]",
      Embed: &struct {
        From        []string "json:\"from\""
        ModelConfig struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        } "json:\"model_config\""
      }{
        From: []string{"brand", "categories"},
        ModelConfig: struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        }{
          ModelName: "ts/all-MiniLM-L12-v2",
        },
      },
    },
  },
}

client.Collections().Create(context.Background(), schema)
```
  </template>

  <template v-slot:Shell>

```bash
curl 'http://localhost:8108/collections' \
  -X POST \
  -H 'Content-Type: application/json' \
  -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
  -d '{
        "name": "products",
        "fields": [
          {
            "name": "brand",
            "type": "string"
          },
          {
            "name": "categories",
            "type": "string[]"
          },
          {
            "name": "embedding",
            "type": "float[]",
            "embed": {
              "from": [
                "brand",
                "categories"
              ],
              "model_config": {
                "model_name": "ts/all-MiniLM-L12-v2"
              }
            }
          }
        ]
      }'

```
   </template>
</Tabs>

When you create a collection with the schema above, the `all-MiniLM-L12-v2` model will be downloaded and your documents will be automatically embedded by this model and will be stored in the `embedding` field.

See our [Hugging Face repo](https://huggingface.co/typesense/models/tree/main) for all officially supported models.
If you need support for additional publicly-available models, feel free to convert the model to ONNX format and send a PR to our [Hugging Face models repo](https://huggingface.co/typesense/models/tree/main).

### Using a GPU (optional)

Embedding models are computationally intensive to run.
So when using one of the [built-in models](#using-built-in-models), you might want to consider running Typesense on a server with a GPU to improve the performance of embedding generation, especially for large datasets.

:::tip
The GPU is only used for _generating_ embeddings - when indexing documents and when generating embeddings for the search term. The actual nearest-neighbor vector search operation does not use the GPU. 
:::

#### On Typesense Cloud:

For [select RAM / CPU configurations](https://typesense-cloud.helpscoutdocs.com/article/4-gpu-acceleration), you'll find the option to turn on "GPU Acceleration" when provisioning a new cluster or under Cluster Configuration > Modify for Typesense versions `0.25.0` and above.

#### When Self Hosting:

Follow the [installation guide](../../guide/install-typesense.md#using-a-gpu-optional).

### Using OpenAI API

You can also have Typesense send specific fields in your JSON data to OpenAI's API to generate text embeddings.

You can use any of OpenAI models listed [here](https://platform.openai.com/docs/guides/embeddings/embedding-models).

<Tabs :tabs="['JavaScript','PHP','Python','Ruby','Java','Go','Shell']">

  <template v-slot:JavaScript>

```js
let schema = {
  "name": "products",
  "fields": [
    {
      "name": "product_name",
      "type": "string"
    },
    {
      "name": "embedding",
      "type": "float[]",
      "embed": {
        "from": [
          "product_name"
        ],
        "model_config": {
          "model_name": "openai/text-embedding-ada-002",
          "api_key": "your_openai_api_key"
        }
      }
    }
  ]
};

client.collections('products').create(schema);

```
  </template>

  <template v-slot:PHP>

```php
$schema = [
  "name" => "products",
  "fields" => [
    [
      "name" => "product_name",
      "type" => "string"
    ],
    [
      "name" => "embedding",
      "type" => "float[]",
      "embed" => [
        "from" => [
          "product_name"
        ],
        "model_config" => [
          "model_name" => "openai/text-embedding-ada-002",
          "api_key" => "your_openai_api_key"
        ]
      ]
    ]
  ]
];

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

```

  </template>

  <template v-slot:Python>

```py
schema = {
  "name": "products",
  "fields": [
    {
      "name" : "product_name",
      "type" : "string"
    },
    {
      "name" : "embedding",
      "type" : "float[]",
      "embed": {
        "from": [
          "product_name"
        ],
        "model_config": {
          "model_name": "openai/text-embedding-ada-002",
          "api_key": "your_openai_api_key"
        }
      }
    }
  ]
}

client.collections.create(schema)
```

  </template>

  <template v-slot:Ruby>

```rb
schema = {
  "name" => "products",
  "fields" => [
    {
      "name" => "product_name",
      "type" => "string"
    },
    {
      "name" => "embedding",
      "type" => "float[]",
      "embed" => {
        "from" => [
          "product_name"
        ],
        "model_config" => {
          "model_name" => "openai/text-embedding-ada-002",
          "api_key" => "your_openai_api_key"
        }
      }
    }
  ]
}

client.collections.create(schema)

```

  </template>

  <template v-slot:Java>

```java
CollectionSchema collectionSchema = new CollectionSchema();
ArrayList<String> embedFrom = new ArrayList<>();
embedFrom.add("product_name");
embedFrom.add("categories");

collectionschema.name("products")
                .addFieldsItem(new Field().name("product_name").type(FieldTypes.STRING))
                .addFieldsItem(new Field().name("categories").type(FieldTypes.STRING_ARRAY))
                .addFieldsItem(new Field().name("embedding").type(FieldTypes.FLOAT_ARRAY).embed(
                  new FieldEmbed().from(embedFrom).modelConfig(new FieldEmbedModelConfig().modelName("openai/text-embedding-ada-002").apiKey("your_openai_api_key")
                ));

CollectionResponse collectionResponse = client.collections().create(collectionSchema);
```
  </template>

  <template v-slot:Go>

```go
schema := &api.CollectionSchema{
  Name: "products",
  Fields: []api.Field{
    {
      Name: "product_name",
      Type: "string",
    },
    {
      Name: "embedding",
      Type: "float[]",
      Embed: &struct {
        From        []string "json:\"from\""
        ModelConfig struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        } "json:\"model_config\""
      }{
        From: []string{"product_name"},
        ModelConfig: struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        }{
          ModelName: "openai/text-embedding-ada-002",
          ApiKey:    pointer.String("your_openai_api_key"),
        },
      },
    },
  },
}

client.Collections().Create(context.Background(), schema)
```
  </template>

  <template v-slot:Shell>

```bash
curl 'http://localhost:8108/collections' \
  -X POST \
  -H 'Content-Type: application/json' \
  -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
  -d '{
        "name": "products",
        "fields": [
          {
            "name": "product_name",
            "type": "string"
          },
          {
            "name": "embedding",
            "type": "float[]",
            "embed": {
              "from": [
                "product_name"
              ],
              "model_config": {
                "model_name": "openai/text-embedding-ada-002",
                "api_key": "your_openai_api_key"
              }
            }
          }
        ]
      }'

```
   </template>
</Tabs>

When you create the collection above, we will call the OpenAI API to create embeddings from the `product_name` field and store them in the `embedding` field every time you index a document.

You have to provide a valid OpenAI API key in `model_config` to use this feature.
###  Using Azure OpenAI API
You can use an [Azure](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/embeddings?tabs=console) OpenAI model to generate embedings:

```js
let schema = {
  "name": "products",
  "fields": [
    {
      "name": "product_name",
      "type": "string"
    },
    {
      "name": "embedding",
      "type": "float[]",
      "embed": {
        "from": [
          "product_name"
        ],
        "model_config": {
          "model_name": "azure/text-embedding-ada-002",
          "api_key": "your_api_key_as_required_by_the_custom_provider",
          "url": "https://example.openai.azure.com/openai/deployments/text-embedding-3-large/embeddings?api-version=2023-05-15"
        }
      }
    }
  ]
};

client.collections('products').create(schema);
```

### Using OpenAI-compatible APIs

You can also use other OpenAI-API-compatible API providers, by customizing the base URL in the `model_config`:

<Tabs :tabs="['JavaScript','PHP','Python','Ruby','Java','Go','Shell']">

  <template v-slot:JavaScript>

```js
let schema = {
  "name": "products",
  "fields": [
    {
      "name": "product_name",
      "type": "string"
    },
    {
      "name": "embedding",
      "type": "float[]",
      "embed": {
        "from": [
          "product_name"
        ],
        "model_config": {
          "model_name": "azure/text-embedding-ada-002",
          "api_key": "your_api_key_as_required_by_the_custom_provider",
          "url": "https://example.openai.azure.com/openai/deployments/text-embedding-3-large/embeddings?api-version=2023-05-15"
        }
      }
    }
  ]
};

client.collections('products').create(schema);

```
  </template>

  <template v-slot:PHP>

```php
$schema = [
  "name" => "products",
  "fields" => [
    [
      "name" => "product_name",
      "type" => "string"
    ],
    [
      "name" => "embedding",
      "type" => "float[]",
      "embed" => [
        "from" => [
          "product_name"
        ],
        "model_config" => [
          "model_name" => "openai/text-embedding-ada-002",
          "api_key" => "your_api_key_as_required_by_the_custom_provider",
          "url" => "https://your-custom-openai-compatible-api.domain.com"
        ]
      ]
    ]
  ]
];

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

```

  </template>

  <template v-slot:Python>

```py
schema = {
  "name": "products",
  "fields": [
    {
      "name" : "product_name",
      "type" : "string"
    },
    {
      "name" : "embedding",
      "type" : "float[]",
      "embed": {
        "from": [
          "product_name"
        ],
        "model_config": {
          "model_name": "openai/text-embedding-ada-002",
          "api_key": "your_api_key_as_required_by_the_custom_provider",
          "url": "https://your-custom-openai-compatible-api.domain.com"
        }
      }
    }
  ]
}

client.collections.create(schema)
```

  </template>

  <template v-slot:Ruby>

```rb
schema = {
  "name" => "products",
  "fields" => [
    {
      "name" => "product_name",
      "type" => "string"
    },
    {
      "name" => "embedding",
      "type" => "float[]",
      "embed" => {
        "from" => [
          "product_name"
        ],
        "model_config" => {
          "model_name" => "openai/text-embedding-ada-002",
          "api_key" => "your_api_key_as_required_by_the_custom_provider",
          "url" => "https://your-custom-openai-compatible-api.domain.com"
        }
      }
    }
  ]
}

client.collections.create(schema)

```

  </template>

  <template v-slot:Java>

```java
CollectionSchema collectionSchema = new CollectionSchema();
ArrayList<String> embedFrom = new ArrayList<>();
embedFrom.add("product_name");
embedFrom.add("categories");

collectionschema.name("products")
                .addFieldsItem(new Field().name("product_name").type(FieldTypes.STRING))
                .addFieldsItem(new Field().name("categories").type(FieldTypes.STRING_ARRAY))
                .addFieldsItem(new Field().name("embedding").type(FieldTypes.FLOAT_ARRAY).embed(
                  new FieldEmbed().from(embedFrom).modelConfig(new FieldEmbedModelConfig().modelName("openai/text-embedding-ada-002").apiKey("your_api_key_as_required_by_the_custom_provider").url("https://your-custom-openai-compatible-api.domain.com")
                ));

CollectionResponse collectionResponse = client.collections().create(collectionSchema);
```
  </template>

  <template v-slot:Go>

```go
schema := &api.CollectionSchema{
  Name: "products",
  Fields: []api.Field{
    {
      Name: "product_name",
      Type: "string",
    },
    {
      Name: "embedding",
      Type: "float[]",
      Embed: &struct {
        From        []string "json:\"from\""
        ModelConfig struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        } "json:\"model_config\""
      }{
        From: []string{"product_name"},
        ModelConfig: struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        }{
          ModelName: "openai/text-embedding-ada-002",
          ApiKey:    pointer.Any("your_api_key_as_required_by_the_custom_provider"),
          Url:       pointer.Any("https://your-custom-openai-compatible-api.domain.com"),
        },
      },
    },
  },
}

client.Collections().Create(context.Background(), schema)
```
  </template>

  <template v-slot:Shell>

```bash
curl 'http://localhost:8108/collections' \
  -X POST \
  -H 'Content-Type: application/json' \
  -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
  -d '{
        "name": "products",
        "fields": [
          {
            "name": "product_name",
            "type": "string"
          },
          {
            "name": "embedding",
            "type": "float[]",
            "embed": {
              "from": [
                "product_name"
              ],
              "model_config": {
                "model_name": "openai/text-embedding-ada-002",
                "api_key": "your_api_key_as_required_by_the_custom_provider",
                "url": "https://your-custom-openai-compatible-api.domain.com"
              }
            }
          }
        ]
      }'

```
   </template>
</Tabs>

When you create the collection above, Typesense will call the OpenAI-API compatible API server running behind `https://your-custom-openai-compatible-api.domain.com` to create embeddings from the `product_name` field and store them in the `embedding` field every time you index a document.

The `model_name` within `model_config` *must* begin with `openai`.

The custom API server behind the specified URL should provide the following endpoint:

**Endpoint**:

`POST /v1/embeddings`

**Request Body:**

| Parameter  | Type               | Description                  |
|------------|--------------------|------------------------------|
| model      | string             | Model name                   |
| input      | string or string[] | Input string or string array |

**Response Body:**

```json
{
    "data": [
        {
            "embedding": [
                       ....
            ]
        }
    ]
}
```

Response body might have additional data, but the embeddings MUST be returned in the format above.

**Error Response Body:**

```json
{
  "error": {
    "message": "Error message",
    "type": "error_type",
    "param": null,
    "code": "error_code"
  }
}
```

### Using Google PaLM API

This API provided by [Google MakerSuite](https://developers.generativeai.google/products/makersuite) to generate embeddings.

<Tabs :tabs="['JavaScript','PHP','Python', 'Ruby', 'Java','Go','Shell']">

  <template v-slot:JavaScript>

```js
let schema = {
  "name": "products",
  "fields": [
    {
      "name": "product_name",
      "type": "string"
    },
    {
      "name": "embedding",
      "type": "float[]",
      "embed": {
        "from": [
          "product_name"
        ],
        "model_config": {
          "model_name": "google/embedding-gecko-001",
          "api_key": "your_google_api_key"
        }
      }
    }
  ]
};

client.collections('products').create(schema);

```
  </template>

  <template v-slot:PHP>

```php
$schema = [
  "name" => "products",
  "fields" => [
    [
      "name" => "product_name",
      "type" => "string"
    ],
    [
      "name" => "embedding",
      "type" => "float[]",
      "embed" => [
        "from" => [
          "product_name"
        ],
        "model_config" => [
          "model_name" => "google/embedding-gecko-001",
          "api_key" => "your_google_api_key"
        ]
      ]
    ]
  ]
];

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

```

  </template>
  <template v-slot:Python>

```py
schema = {
  "name": "products",
  "fields": [
    {
      "name" : "product_name",
      "type" : "string"
    },
    {
      "name" : "embedding",
      "type" : "float[]",
      "embed": {
        "from": [
          "product_name"
        ],
        "model_config": {
          "model_name": "google/embedding-gecko-001",
          "api_key": "your_google_api_key"
        }
      }
    }
  ]
}

client.collections.create(schema)
```

  </template>
  <template v-slot:Ruby>

```rb
schema = {
  "name" => "products",
  "fields" => [
    {
      "name" => "product_name",
      "type" => "string"
    },
    {
      "name" => "embedding",
      "type" => "float[]",
      "embed" => {
        "from" => [
          "product_name"
        ],
        "model_config" => {
          "model_name" => "google/embedding-gecko-001",
          "api_key" => "your_google_api_key"
        }
      }
    }
  ]
}

client.collections.create(schema)

```
  </template>
  <template v-slot:Java>

```java
CollectionSchema collectionSchema = new CollectionSchema();
ArrayList<String> embedFrom = new ArrayList<>();
embedFrom.add("product_name");
embedFrom.add("categories");

collectionschema.name("products")
                .addFieldsItem(new Field().name("product_name").type(FieldTypes.STRING))
                .addFieldsItem(new Field().name("categories").type(FieldTypes.STRING_ARRAY))
                .addFieldsItem(new Field().name("embedding").type(FieldTypes.FLOAT_ARRAY).embed(
                  new FieldEmbed().from(embedFrom).modelConfig(new FieldEmbedModelConfig().modelName("google/embedding-gecko-001").apiKey("your_google_api_key")
                ));

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

  </template>

  <template v-slot:Go>

```go
schema := &api.CollectionSchema{
  Name: "products",
  Fields: []api.Field{
    {
      Name: "product_name",
      Type: "string",
    },
    {
      Name: "embedding",
      Type: "float[]",
      Embed: &struct {
        From        []string "json:\"from\""
        ModelConfig struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        } "json:\"model_config\""
      }{
        From: []string{"product_name"},
        ModelConfig: struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        }{
          ModelName: "google/embedding-gecko-001",
          ApiKey:    pointer.String("your_google_api_key"),
        },
      },
    },
  },
}

client.Collections().Create(context.Background(), schema)
```

  </template>
  <template v-slot:Shell>

```bash
curl 'http://localhost:8108/collections' \
  -X POST \
  -H 'Content-Type: application/json' \
  -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
  -d '{
        "name": "products",
        "fields": [
          {
            "name": "product_name",
            "type": "string"
          },
          {
            "name": "embedding",
            "type": "float[]",
            "embed": {
              "from": [
                "product_name"
              ],
              "model_config": {
                "model_name": "google/embedding-gecko-001",
                "api_key": "your_google_api_key"
              }
            }
          }
        ]
      }'

```
   </template>

</Tabs>

**Note:** The only supported model is `embedding-gecko-001` for now.

### Updating Remote Model API Key

You can update the API key used for remote embedding models (like OpenAI) without recreating the collection:

<Tabs :tabs="['Shell']">
  <template v-slot:Shell>

```bash
curl "http://localhost:8108/collections/products" \
     -X PATCH \
     -H "Content-Type: application/json" \
     -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
     -d '{
       "fields": [
         {
           "name": "embedding",
           "embed": {
             "from": ["product_name"],
             "model_config": {
               "model_name": "openai/text-embedding-ada-002",
               "api_key": "new_api_key"
             }
           }
         }
       ]
     }'
```

  </template>
</Tabs>

:::warning
Note: All fields parameters (`name`, `embed.from`, and `model_config` parameters) must be included in the update request.
:::

### Using GCP Vertex AI API

This API also provided by Google under the Google Cloud Platform (GCP) umbrella.

You would need the following authentication information to use this method:

- GCP access token (must be valid while creating the field)
- GCP refresh token
- GCP application client ID
- GCP application client secret
- GCP project ID

Please refer to the Vertex AI docs for more information on how to fetch these values.

<Tabs :tabs="['JavaScript','PHP','Python', 'Ruby', 'Java', 'Go', 'Shell']">

  <template v-slot:JavaScript>

```js
schema = {
  "name": "products",
  "fields": [
    {
      "name": "product_name",
      "type": "string"
    },
    {
      "name": "embedding",
      "type": "float[]",
      "embed": {
        "from": [
          "product_name"
        ],
        "model_config": {
          "model_name": "gcp/embedding-gecko-001",
          "access_token": "your_gcp_access_token",
          "refresh_token": "your_gcp_refresh_token",
          "client_id": "your_gcp_app_client_id",
          "client_secret": "your_gcp_client_secret",
          "project_id": "your_gcp_project_id",
          "document_task": "DOCUMENT",
          "query_task": "QUERY",
          "region": "us-central1"
        }
      }
    }
  ]
};

client.collections('products').create(schema);

```
  </template>

  <template v-slot:PHP>

```php
$schema = [
  "name" => "products",
  "fields" => [
    [
      "name" => "product_name",
      "type" => "string"
    ],
    [
      "name" => "embedding",
      "type" => "float[]",
      "embed" => [
        "from" => [
          "product_name"
        ],
        "model_config" => [
          "model_name" => "gcp/embedding-gecko-001",
          "access_token" => "your_gcp_access_token",
          "refresh_token" => "your_gcp_refresh_token",
          "client_id" => "your_gcp_app_client_id",
          "client_secret" => "your_gcp_client_secret",
          "project_id" => "your_gcp_project_id",
          "document_task" => "DOCUMENT",
          "query_task" => "QUERY",
          "region": "us-central1"
        ]
      }
    ]
  ]
];

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

```

  </template>
  <template v-slot:Python>

```py
schema = {
  "name": "products",
  "fields": [
    {
      "name" : "product_name",
      "type" : "string"
    },
    {
      "name" : "embedding",
      "type" : "float[]",
      "embed": {
        "from": [
          "product_name"
        ],
        "model_config": {
          "model_name": "gcp/embedding-gecko-001",
          "access_token": "your_gcp_access_token",
          "refresh_token": "your_gcp_refresh_token",
          "client_id": "your_gcp_app_client_id",
          "client_secret": "your_gcp_client_secret",
          "project_id": "your_gcp_project_id",
          "document_task": "DOCUMENT",
          "query_task": "QUERY",
          "region": "us-central1"
        }
      }
    }
  ]
}

client.collections.create(schema)
```

  </template>
  <template v-slot:Ruby>

```rb
schema = {
  "name" => "products",
  "fields" => [
    {
      "name" => "product_name",
      "type" => "string"
    },
    {
      "name" => "embedding",
      "type" => "float[]",
      "embed" => {
        "from" => [
          "product_name"
        ],
        "model_config" => {
          "model_name" => "gcp/embedding-gecko-001",
          "access_token" => "your_gcp_access_token",
          "refresh_token" => "your_gcp_refresh_token",
          "client_id" => "your_gcp_app_client_id",
          "client_secret" => "your_gcp_client_secret",
          "project_id" => "your_gcp_project_id",
          "document_task" => "DOCUMENT",
          "query_task" => "QUERY",
          "region": "us-central1"
        }
      }
    }
  ]
}

client.collections.create(schema)
```

  </template>
  <template v-slot:Java>

```java
CollectionSchema collectionSchema = new CollectionSchema();
ArrayList<String> embedFrom = new ArrayList<>();
embedFrom.add("product_name");
embedFrom.add("categories");

collectionschema.name("products")
                .addFieldsItem(new Field().name("product_name").type(FieldTypes.STRING))
                .addFieldsItem(new Field().name("categories").type(FieldTypes.STRING_ARRAY))
                .addFieldsItem(new Field().name("embedding").type(FieldTypes.FLOAT_ARRAY).embed(
                  new FieldEmbed().from(embedFrom).modelConfig(new FieldEmbedModelConfig().modelName("gcp/embedding-gecko-001")
                      .accessToken("your_gcp_access_token")
                      .refreshToken("your_gcp_refresh_token")
                      .clientId("your_gcp_app_client_id")
                      .clientSecret("your_gcp_client_secret").projectId("your_gcp_project_id")
                      .documentTask("DOCUMENT")
                      .queryTask("QUERY")
                      .region("us-central1"))
                ));
CollectionResponse collectionResponse = client.collections().create(collectionSchema);
```

  </template>

  <template v-slot:Go>

```go
schema := &api.CollectionSchema{
  Name: "products",
  Fields: []api.Field{
    {Name: "product_name", Type: "string"},
    {Name: "embedding", Type: "float[]",
      Embed: &struct {
        From        []string "json:\"from\""
        ModelConfig struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        } "json:\"model_config\""
      }{
        From: []string{"product_name"},
        ModelConfig: struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        }{
          ModelName:    "gcp/embedding-gecko-001",
          AccessToken:  pointer.Any("your_gcp_access_token"),
          RefreshToken: pointer.Any("your_gcp_refresh_token"),
          ClientId:     pointer.Any("your_gcp_app_client_id"),
          ClientSecret: pointer.Any("your_gcp_client_secret"),
          ProjectId:    pointer.Any("your_gcp_project_id"),
          DocumentTask: pointer.Any("DOCUMENT"),
          QueryTask:    pointer.Any("QUERY"),
          Region:       pointer.Any("us-central1"),
        },
      }},
  },
}
client.Collections().Create(context.Background(), schema)
```

  </template>
  <template v-slot:Shell>

```bash
curl 'http://localhost:8108/collections' \
  -X POST \
  -H 'Content-Type: application/json' \
  -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
  -d '{
        "name": "products",
        "fields": [
          {
            "name": "product_name",
            "type": "string"
          },
          {
            "name": "embedding",
            "type": "float[]",
            "embed": {
              "from": [
                "product_name"
              ],
              "model_config": {
                "model_name": "gcp/embedding-gecko-001",
                "access_token": "your_gcp_access_token",
                "refresh_token": "your_gcp_refresh_token",
                "client_id": "your_gcp_app_client_id",
                "client_secret": "your_gcp_client_secret",
                "project_id": "your_gcp_project_id",
                "document_task": "DOCUMENT",
                "query_task": "QUERY",
                "region": "us-central1"
              }
            }
          }
        ]
      }'
```
   </template>

</Tabs>

### Remote Embedding API parameters

You can use any of the following parameters to fine-tune how API calls are made to remote embedding services:

#### During Search

| Parameter                     | Description                                                                                               |  Default  |
|-------------------------------|-----------------------------------------------------------------------------------------------------------|-----------|
| `remote_embedding_timeout_ms` | How long to wait until an API call to a remote embedding service is considered a timeout, during a search |    30s    |
| `remote_embedding_num_tries`  | The number of times to retry an API call to a remote embedding service on failure, during a search        |     2     |

<Tabs :tabs="['JavaScript','PHP','Python', 'Ruby', 'Java','Go','Shell']">

  <template v-slot:JavaScript>

```js
let search_parameters = {
  'q'                          : 'chair',
  'query_by'                   : 'embedding',
  'prefix'                     : false,
  'remote_embedding_timeout_ms': 5000,
  'remote_embedding_num_tries'   : 3
}

client.collections('products').documents().search(search_parameters)
```

  </template>

<template v-slot:PHP>

```php
$search_parameters = [
  'q'                          => 'chair',
  'query_by'                   => 'embedding',
  'prefix'                     => false,
  'remote_embedding_timeout_ms'=> 5000,
  'remote_embedding_num_try'   => 3
];

$client->collections['products']->documents->search($search_parameters);
```

  </template>

<template v-slot:Python>

  ```py
search_parameters = {
  'q'                          : 'chair',
  'query_by'                   : 'embedding',
  'prefix'                     : false,
  'remote_embedding_timeout_ms': 5000,
  'remote_embedding_num_try'   : 3
}

client.collections['products'].documents.search(search_parameters)
```

  </template>
  <template v-slot:Ruby>

```rb
search_parameters = {
  'q'                          => 'chair',
  'query_by'                   => 'embedding',
  'prefix'                     => false,
  'remote_embedding_timeout_ms'=> 5000,
  'remote_embedding_num_try'   => 3
}

client.collections['products'].documents.search(search_parameters)
```

  </template>
  <template v-slot:Java>

```java
SearchParameters searchParameters = new SearchParameters();

searchParameters.q("chair")
                .queryBy("embedding")
                .prefix(false)
                .remoteEmbeddingTimeoutMs(5000)
                .remoteEmbeddingNumTries(3);

SearchResult searchResult = client.collections("products").documents().search(searchParameters);
```

  </template>
  <template v-slot:Go>

```go
searchParameters := &api.SearchCollectionParams{
  Q:                        pointer.String("chair"),
  QueryBy:                  pointer.String("embedding"),
  Prefix:                   pointer.String("false"),
  RemoteEmbeddingTimeoutMs: pointer.Int(5000),
  RemoteEmbeddingNumTries:  pointer.Int(3),
}

client.Collection("products").Documents().Search(context.Background(), searchParameters)
```

  </template>
  <template v-slot:Shell>

  ```bash
curl 'http://localhost:8108/multi_search' \
      -X POST \
      -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
      -d '{
            "searches": [
              {
                "collection": "products",
                "q": "chair",
                "query_by": "embedding",
                "prefix": false,
                "remote_embedding_timeout_ms": 5000,
                "remote_embedding_num_try": 3
              }
            ]
          }'
```

  </template>

</Tabs>


#### During Indexing

| Parameter                     | Description                                                                                                                                                                           | Default |
|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
| `remote_embedding_batch_size` | Max size of each batch that will be sent to remote APIs while importing multiple documents at once. Using lower amount will lower timeout risk, but increase number of requests made. | 200     |
| `remote_embedding_timeout_ms` | How long to wait until an API call to a remote embedding service is considered a timeout during indexing.                                                                             | 60000     |
| `remote_embedding_num_tries` | The number of times to retry an API call to a remote embedding service on failure during indexing.                                                                                    | 2       |

<Tabs :tabs="['JavaScript','PHP','Python', 'Ruby', 'Java','Go','Shell']">

  <template v-slot:JavaScript>

```js
let import_parameters = {
  'remote_embedding_batch_size': 200
}

client.collections('products').documents().import(documents, import_parameters)
```

  </template>

<template v-slot:PHP>

```php
$import_parameters = [
  'remote_embedding_batch_size' => 200
];

$client->collections['products']->documents->import($documents, $import_parameters);
```

  </template>

<template v-slot:Python>

  ```py
import_parameters = {
  'remote_embedding_batch_size': 200
}

client.collections['products'].documents.import(documents, import_parameters)
```

  </template>

<template v-slot:Ruby>

  ```rb
import_parameters = {
  'remote_embedding_batch_size' => 200
}

client.collections['products'].documents.import(documents, import_parameters)
```

</template>
<template v-slot:Java>

```java
ImportDocumentParameters importDocumentParameters = new ImportDocumentParameters();
importDocumentParameters.remoteEmbeddingBatchSize(200);

client.collections("products").documents().import(documents, importDocumentParameters);
```

</template>
<template v-slot:Go>

```go
importParameters := &api.ImportDocumentsParams{
  RemoteEmbeddingBatchSize: pointer.Int(200),
}

client.Collection("products").Documents().Import(context.Background(), documents, importParameters)
```

</template>
<template v-slot:Shell>

```bash
curl 'http://localhost:8108/collections/products/documents/import?remote_embedding_batch_size=200' \
  -X POST \
  -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
  -d '{"product_name": "chair"}
      {"product_name": "table"}'
```

  </template>

</Tabs>

### Using your own models

You can also use your own models to generate embeddings from within Typesense. They must be in the ONNX file format.

Create a directory under `<data_dir>/models` and store your ONNX model file, vocab file, and a JSON for model config there.

***Note:*** Your model file MUST be named as `model.onnx` and the config file MUST be named as `config.json`.

#### Model config file

This file will contain information about the type of model you want to use.

The JSON file must contain `model_type` (type of the model; we support `bert` and `xlm_roberta` at the moment) and `vocab_file_name` keys.

**Directory Structure:**

```
<data_dir>/models/test_model/model.onnx
<data_dir>/models/test_model/vocab.txt
<data_dir>/models/test_model/config.json
```

**Contents of `config.json`:**
```
{
    "model_type": "bert",
    "vocab_file_name": "vocab.txt"
}
```

Create an embedding field using the directory name as `model_name` in `model_config`.

<Tabs :tabs="['JavaScript','PHP','Python', 'Ruby', 'Java','Go','Shell']">

  <template v-slot:JavaScript>

```js
let schema = {
  "name": "products",
  "fields": [
    {
      "name": "product_name",
      "type": "string"
    },
    {
      "name": "embedding",
      "type": "float[]",
      "embed": {
        "from": ["product_name"],
        "model_config": {
          "model_name": "test_model"
        }
      }
    }
  ]
};

client.collections('products').create(schema);

```
  </template>

  <template v-slot:PHP>

```php
$schema = [
  "name" => "products",
  "fields" => [
    [
      "name" => "product_name",
      "type" => "string"
    ],
    [
      "name" => "embedding",
      "type" => "float[]",
      "embed" => [
        "from" => ["product_name"],
        "model_config" => [
          "model_name" => "test_model"
        ]
      ]
    ]
  ]
];

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

```

  </template>
  <template v-slot:Python>

```py
schema = {
  "name": "products",
  "fields": [
    {
      "name" : "product_name",
      "type" : "string"
    },
    {
      "name" : "embedding",
      "type" : "float[]",
      "embed": {
        "from": ["product_name"],
        "model_config": {
          "model_name": "test_model"
        }
      }
    }
  ]
}

client.collections.create(schema)
```

  </template>
  <template v-slot:Ruby>

```rb
schema = {
  "name" => "products",
  "fields" => [
    {
      "name" => "product_name",
      "type" => "string"
    },
    {
      "name" => "embedding",
      "type" => "float[]",
      "embed" => [
        "from" => ["product_name"],
        "model_config" => [
          "model_name" => "test_model"
        ]
      }
    }
  ]
}

client.collections.create(schema)

```
  </template>
  <template v-slot:Java>

```java
CollectionSchema collectionSchema = new CollectionSchema();
ArrayList<String> embedFrom = new ArrayList<>();
embedFrom.add("product_name");
embedFrom.add("categories");

collectionschema.name("products")
                .addFieldsItem(new Field().name("product_name").type(FieldTypes.STRING))
                .addFieldsItem(new Field().name("categories").type(FieldTypes.STRING_ARRAY))
                .addFieldsItem(new Field().name("embedding").type(FieldTypes.FLOAT_ARRAY).embed(
                  new FieldEmbed().from(embedFrom).modelConfig(new FieldEmbedModelConfig().modelName("test_model")
                ));

CollectionResponse collectionResponse = client.collections().create(collectionSchema);
```
  </template>
  <template v-slot:Go>

```go
schema := &api.CollectionSchema{
  Name: "products",
  Fields: []api.Field{
    {
      Name: "product_name",
      Type: "string",
    },
    {
      Name: "embedding",
      Type: "float[]",
      Embed: &struct {
        From        []string "json:\"from\""
        ModelConfig struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        } "json:\"model_config\""
      }{
        From: []string{"product_name"},
        ModelConfig: struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        }{
          ModelName: "test_model",
        },
      },
    },
  },
}

client.Collections().Create(context.Background(), schema)
```
  </template>
  <template v-slot:Shell>

```bash
curl 'http://localhost:8108/collections' \
  -X POST \
  -H 'Content-Type: application/json' \
  -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
  -d '{
        "name": "products",
        "fields": [
          {
            "name": "product_name",
            "type": "string"
          },
          {
            "name": "embedding",
            "type": "float[]",
            "embed": {
              "from": ["product_name"],
              "model_config": {
                "model_name": "test_model"
              }
            }
          }
        ]
      }'

```
   </template>

</Tabs>

#### Optional Model Parameters

These are optional model parameters, which may be required to use with your custom models.

##### Indexing prefix and query prefix

Some models may require a prefix to know if texts are queries or they are actual texts to query on (you can check `intfloat/e5-small`, for example).

If you set this property in `model_config`, the given indexing prefix will be added to the text that will be used to create embeddings when you index a document and `query_prefix` to the actual query before creating embeddings of it.Example:

<Tabs :tabs="['JavaScript','PHP','Python', 'Ruby', 'Java','Go','Shell']">

  <template v-slot:JavaScript>

```js
let schema = {
  "name": "products",
  "fields": [
    {
      "name": "product_name",
      "type": "string"
    },
    {
      "name": "embedding",
      "type": "float[]",
      "embed": {
        "from": ["product_name"],
        "model_config": {
          "model_name": "e5-base",
          "indexing_prefix": "passage:",
          "query_prefix": "query:"
        }
      }
    }
  ]
};

client.collections('products').create(schema);

```
  </template>

  <template v-slot:PHP>

```php
$schema = [
  "name" => "products",
  "fields" => [
    [
      "name" => "product_name",
      "type" => "string"
    ],
    [
      "name" => "embedding",
      "type" => "float[]",
      "embed" => [
        "from" => ["product_name"],
        "model_config" => [
          "model_name" => "e5-base",
          "indexing_prefix" => "passage:",
          "query_prefix" => "query:"
        ]
      ]
    ]
  ]
];

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

```

  </template>
  <template v-slot:Python>

```py
schema = {
  "name": "products",
  "fields": [
    {
      "name" : "product_name",
      "type" : "string"
    },
    {
      "name" : "embedding",
      "type" : "float[]",
      "embed": {
        "from": ["product_name"],
        "model_config": {
          "model_name": "e5-base",
          "indexing_prefix": "passage:",
          "query_prefix": "query:"
        }
      }
    }
  ]
}

client.collections.create(schema)
```

  </template>
  <template v-slot:Ruby>

```rb
schema = {
  "name" => "products",
  "fields" => [
    {
      "name" => "product_name",
      "type" => "string"
    },
    {
      "name" => "embedding",
      "type" => "float[]",
      "embed" => [
        "from" => ["product_name"],
        "model_config" => [
          "model_name" => "e5-base",
          "indexing_prefix" => "passage:",
          "query_prefix" => "query:"
        ]
    }
  ]
}

client.collections.create(schema)
```

  </template>
  <template v-slot:Java>

```java
CollectionSchema collectionSchema = new CollectionSchema();
ArrayList<String> embedFrom = new ArrayList<>();
embedFrom.add("product_name");
embedFrom.add("categories");

collectionschema.name("products")
                .addFieldsItem(new Field().name("product_name").type(FieldTypes.STRING))
                .addFieldsItem(new Field().name("categories").type(FieldTypes.STRING_ARRAY))
                .addFieldsItem(new Field().name("embedding").type(FieldTypes.FLOAT_ARRAY).embed(
                  new FieldEmbed().from(embedFrom).modelConfig(new FieldEmbedModelConfig().modelName("e5-base").indexingPrefix("passage:").queryPrefix("query:")
                ));

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

```

  </template>
  <template v-slot:Go>

```go
schema := &api.CollectionSchema{
  Name: "products",
  Fields: []api.Field{
    {Name: "product_name", Type: "string"},
    {Name: "embedding", Type: "float[]",
      Embed: &struct {
        From        []string "json:\"from\""
        ModelConfig struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        } "json:\"model_config\""
      }{
        From: []string{"product_name"},
        ModelConfig: struct {
          AccessToken    *string "json:\"access_token,omitempty\""
          ApiKey         *string "json:\"api_key,omitempty\""
          ClientId       *string "json:\"client_id,omitempty\""
          ClientSecret   *string "json:\"client_secret,omitempty\""
          DocumentTask   *string "json:\"document_task,omitempty\""
          IndexingPrefix *string "json:\"indexing_prefix,omitempty\""
          ModelName      string  "json:\"model_name\""
          ProjectId      *string "json:\"project_id,omitempty\""
          QueryPrefix    *string "json:\"query_prefix,omitempty\""
          QueryTask      *string "json:\"query_task,omitempty\""
          RefreshToken   *string "json:\"refresh_token,omitempty\""
          Url            *string "json:\"url,omitempty\""
        }{
          ModelName:      "e5-base",
          IndexingPrefix: pointer.Any("passage:"),
          QueryPrefix:    pointer.Any("query:"),
        },
      }},
  },
}
client.Collections().Create(context.Background(), schema)
```

  </template>
  <template v-slot:Shell>

```bash
curl 'http://localhost:8108/collections' \
  -X POST \
  -H 'Content-Type: application/json' \
  -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
  -d '{
        "name": "products",
        "fields": [
          {
            "name": "product_name",
            "type": "string"
          },
          {
            "name": "embedding",
            "type": "float[]",
            "embed": {
              "from": ["product_name"],
              "model_config": {
                "model_name": "e5-base",
                "indexing_prefix": "passage:",
                "query_prefix": "query:"
              }
            }
          }
        ]
      }'

```
   </template>

</Tabs>

For this example, when you index a document:
```
{
   "product_name": "ABCD"
}

```
The text used to generate embeddings for the `embedding` field will be `passage: ABCD` instead of `ABCD`. And when you query, if your query is `EFGH`, it will be embedded as `query: EFGH` instead of `EFGH`.

## Nearest-neighbor vector search

Once you've indexed your embeddings in a vector field, you can now search for documents that are "closest" to a given query vector.

To control the number of documents that are returned, you can either use the `per_page` pagination parameter or the `k` parameter within the vector query.

<Tabs :tabs="['JavaScript','PHP','Python','Ruby', 'Dart','Java','Go','Shell']">
<template v-slot:JavaScript>

```js
let searchRequests = {
  'searches': [
    {
      'collection': 'docs',
      'q': '*',
      'vector_query' : 'embedding:([0.96826, 0.94, 0.39557, 0.306488], k:100)', // <=== Be sure to replace `embedding` with the name of the field that stores your embeddings.
      'exclude_fields': 'embedding', // <=== Don't return the raw floating point numbers in the vector field in the search API response, to save on network bandwidth.
    }
  ]
}
let commonSearchParams = {}
client.multiSearch.perform(searchRequests, commonSearchParams)
```

</template>

<template v-slot:PHP>

```php
$searchRequests = [
  'searches' => [
    [
      'collection' => 'docs',
      'q' => '*',
      'vector_query' => 'embedding:([0.96826, 0.94, 0.39557, 0.306488], k:100)', //  <=== Be sure to replace `embedding` with the name of the field that stores your embeddings.
      'exclude_fields' => 'embedding' // <=== Don't return the raw floating point numbers in the vector field in the search API response, to save on network bandwidth.
    ]
  ]
];

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

</template>

<template v-slot:Python>

```py
search_requests = {
  'searches': [
    {
      'collection': 'docs',
      'q' : '*',
      'vector_query': 'embedding:([0.96826, 0.94, 0.39557, 0.306488], k:100)', # <=== Be sure to replace `embedding` with the name of the field that stores your embeddings.
      'exclude_fields': 'embedding' # <=== Don't return the raw floating point numbers in the vector field in the search API response, to save on network bandwidth.
    }
  ]
}

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

<template v-slot:Ruby>

```rb
search_requests = {
  'searches': [
    {
      'collection' => 'docs',
      'q' => '*',
      'vector_query' => 'embedding:([0.96826, 0.94, 0.39557, 0.306488], k:100)', # <=== Be sure to replace `embedding` with the name of the field that stores your embeddings.
      'exclude_fields' => 'embedding' # <=== Don't return the raw floating point numbers in the vector field in the search API response, to save on network bandwidth.
    }
  ]
}

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

  </template>
  <template v-slot:Dart>

```dart
final searchRequests = {
  'searches': [
    {
      'collection': 'docs',
      'q': '*',
      'vector_query': 'embedding:([0.96826, 0.94, 0.39557, 0.306488], k:100)', //  <=== Be sure to replace `embedding` with the name of the field that stores your embeddings.
      'exclude_fields': 'embedding' // <=== Don't return the raw floating point numbers in the vector field in the search API response, to save on network bandwidth.
    }
  ]
};

// Search parameters that are common to all searches go here
final commonSearchParams =  {};

await client.multiSearch.perform(searchRequests, queryParams: commonSearchParams);

```

</template>
<template v-slot:Java>

```java
HashMap<String,String > search1 = new HashMap<>();
search1.put("collection","docs");
search1.put("q","*");
search1.put("vector_query", "embedding:([0.96826, 0.94, 0.39557, 0.306488], k:100)"); //  <=== Be sure to replace `embedding` with the name of the field that stores your embeddings.
search1.put("exclude_fields", "embedding"); // <=== Don't return the raw floating point numbers in the vector field in the search API response, to save on network bandwidth.

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);
```

</template>
<template v-slot:Go>

```go
searchRequests := api.MultiSearchSearchesParameter{
  Searches: []api.MultiSearchCollectionParameters{
    {
      Collection:    pointer.Any("docs"),
      Q:             pointer.Any("*"),
      VectorQuery:   pointer.Any("embedding:([0.96826, 0.94, 0.39557, 0.306488], k:100)"), // <=== Be sure to replace `embedding` with the name of the field that stores your embeddings.
      ExcludeFields: pointer.Any("embedding"),                                             // <=== Don't return the raw floating point numbers in the vector field in the search API response, to save on network bandwidth.
    },
  },
}

commonSearchParams := &api.MultiSearchParams{}
client.MultiSearch.Perform(context.Background(), commonSearchParams, searchRequests)
```

</template>
<template v-slot:Shell>

```bash
curl 'http://localhost:8108/multi_search' \
      -X POST \
      -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
      -d '{
            "searches": [
              {
                "collection": "docs",
                "q": "*",
                "vector_query": "embedding:([0.96826,0.94,0.39557,0.306488], k:100)",
                "exclude_fields": "embedding"
              }
            ]
          }'

# Be sure to replace `embedding` with the name of the field that stores your embeddings.
# We use `exclude_fields` so Typesense doesn't return the raw floating point numbers in the vector field in the search API response, to save on network bandwidth.
```

  </template>
</Tabs>

NOTE: If both `per_page` and `k` parameters are provided, the larger value is used.

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.

:::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.
:::

:::warning Network Bandwidth Optimization
By default Typesense returns all fields in the document as part of the search API response.

So if your documents contain a vector field, this could lead to a lot of floating point vector data returned by Typesense for each search query, unnecessarily, eating into your network bandwidth and could lead to a lot of wasted CPU cycles.

To prevent this, you want to add `exclude_fields: "your_embedding_field_name"` as a search parameter.
:::

**Sample Response**

<Tabs :tabs="['JSON']">
  <template v-slot:JSON>

```json
{
  "facet_counts": [],
  "found": 1,
  "hits": [
    {
      "document": {
        "id": "0",
        "embedding": [
          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
}
```

  </template>
</Tabs>

### Pagination

To paginate through the vector search (or semantic or hybrid search) results, use the `k` parameter in `vector_search` to limit results (e.g., `embedding:([], k: 200)`), set `per_page` for the number of results per page, and use the `page` parameter to navigate through paginated results:

```shell{11,12,13}
curl 'http://localhost:8108/multi_search' \
  -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
  -X POST \
  -d '{
    "searches": [
      {
        "q": "device to type things on",
        "query_by": "embedding",
        "collection": "products",
        "exclude_fields": "embedding",
        "vector_query": "embedding:([], k: 200)",
        "per_page": 10,
        "page": 1
      }
    ]
  }'
```

This will ground the vector search to fetch the closest 200 items, and then paginate within that result-set, fetching 10 results per page. You'd then increment `page` to fetch additional pages of results.

We do this because, with vector search, every item in the dataset is technically a "match" to some level of closeness. So we have to limit the upper limit of closeness either using a quantity value using the `k` parameter as described above, and/or using the [`distance_threshold`](#distance-threshold) parameter of `vector_query`.

## 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' \
  -X POST \
  -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
  -d '{
        "searches": [
          {
            "collection": "docs",
            "q": "*",
            "vector_query": "embedding:([], id: foobar)"
          }
        ]
      }'

# Be sure to replace `embedding` with the name of the field that stores your embeddings.
```

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

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

## Using Auto-generated vs Manual Embeddings

When querying vector fields, you can choose between auto-generated embeddings (where Typesense converts your text query to vectors) or manual embeddings (where you provide pre-computed vectors).

### Auto-generated Embeddings

For auto-embedding fields, use an empty array `[]` in `vector_query` to let Typesense automatically generate embeddings from your `q` parameter:

```json
{
  "q": "comfortable office chair",
  "query_by": "embedding",
  "vector_query": "embedding:([], k:100, distance_threshold:0.30)"
}
```

This approach automatically:

- Converts your text query to an embedding using the same model used for indexing
- Applies vector search parameters like `k`, `distance_threshold`, etc.

### Manual Embeddings

For manual control, provide your own pre-computed embedding vector:

```json
{
  "q": "*",
  "vector_query": "embedding:([0.2, 0.4, 0.1, ...], k:100, distance_threshold:0.30)"
}
```

This gives you full control over the query vector while still applying all vector search parameters.

## Semantic Search

When using [auto-embedding](#option-b-auto-embedding-generation-within-typesense), you can directly set `query_by` to the auto-embedding field to do a semantic search on this field.

Typesense will use the same embedding model that was used to generate the auto-embedding field to generate vectors for the `q` parameter and then do a nearest neighbor search internally.

<Tabs :tabs="['JavaScript','PHP','Python', 'Ruby', 'Java','Go','Shell']">

  <template v-slot:JavaScript>

```js
let search_parameters = {
  'q'                          : 'chair',
  'query_by'                   : 'embedding',
}

client.collections('products').documents().search(search_parameters)
```

  </template>

<template v-slot:PHP>

```php
$search_parameters = [
  'q'                          => 'chair',
  'query_by'                   => 'embedding',
];

$client->collections['products']->documents->search($search_parameters);
```

  </template>

<template v-slot:Python>

  ```py
search_parameters = {
  'q'                          : 'chair',
  'query_by'                   : 'embedding',
}

client.collections['products'].documents.search(search_parameters)
```

  </template>

<template v-slot:Ruby>

  ```rb
search_parameters = {
  'q'                          => 'chair',
  'query_by'                   => 'embedding',
}

client.collections['products'].documents.search(search_parameters)
```

  </template>

<template v-slot:Java>

  ```java

SearchParameters searchParameters = new SearchParameters();

searchParameters.q("chair")
                .queryBy("embedding");

SearchResult searchResult = client.collections("products").documents().search(searchParameters);
```

  </template>
<template v-slot:Go>

  ```go
searchParameters := &api.SearchCollectionParams{
    Q:       pointer.Any("chair"),
    QueryBy: pointer.Any("embedding"),
}

client.Collection("products").Documents().Search(context.Background(), searchParameters)
```

  </template>
<template v-slot:Shell>

  ```bash
curl 'http://localhost:8108/multi_search' \
      -X POST \
      -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
      -d '{
            "searches": [
              {
                "collection": "products",
                "q": "chair",
                "query_by": "embedding"
              }
            ]
          }'
```

  </template>

</Tabs>

This will automatically embed the `chair` query with the same model used for the `embedding` field and will perform a nearest neighbor vector search.

## Hybrid Search

When using [auto-embedding](#option-b-auto-embedding-generation-within-typesense), you can set `query_by` to a list of both regular fields and auto-embedding fields, to do a hybrid search on multiple fields.

Typesense will do a keyword search on all the regular fields, and a semantic search on the auto-embedding field and
combine the results using Rank Fusion to arrive at a **fusion score** that is used to rank the hits.

```
K = rank of document in keyword search
S = rank of document in semantic search

rank_fusion_score = 0.7 * K + 0.3 * S
```

The `0.7` and `0.3` values can be changed using the [`alpha` parameter](#weightage-for-semantic-vs-keyword-matches).

<Tabs :tabs="['JavaScript','PHP','Python', 'Ruby', 'Java','Go','Shell']">

  <template v-slot:JavaScript>

```js
let search_parameters = {
  'q'                          : 'chair',
  'query_by'                   : 'product_name,embedding',
  'sort_by'                   :  '_text_match:desc',
}

client.collections('products').documents().search(search_parameters)
```

  </template>

<template v-slot:PHP>

  ```php
$search_parameters = [
  'q'                          => 'chair',
  'query_by'                   => 'product_name,embedding',
  'sort_by'                   => '_text_match:desc',
];

$client->collections['products']->documents->search($search_parameters);
```

  </template>

<template v-slot:Python>

  ```py
search_parameters = {
  'q'                          : 'chair',
  'query_by'                   : 'product_name,embedding',
  'sort_by'                   :  '_text_match:desc',
}

client.collections['products'].documents.search(search_parameters)
```

  </template>

<template v-slot:Ruby>

  ```rb
search_parameters = {
  'q'                          => 'chair',
  'query_by'                   => 'product_name,embedding',
  'sort_by'                    => '_text_match:desc',
}

client.collections['products'].documents.search(search_parameters)
```

  </template>

<template v-slot:Java>

  ```java
SearchParameters searchParameters = new SearchParameters();

searchParameters.q("chair")
                .queryBy("product_name,embedding,")
                .sortBy("_text_match:desc");

SearchResult searchResult = client.collections("products").documents().search(searchParameters);
```
  </template>
<template v-slot:Go>

  ```go
searchParameters := &api.SearchCollectionParams{
    Q:       pointer.String("chair"),
    QueryBy: pointer.String("product_name,embedding"),
    SortBy:  pointer.String("_text_match:desc"),
}

client.Collection("products").Documents().Search(context.Background(), searchParameters)
```
  </template>

<template v-slot:Shell>

```bash
curl 'http://localhost:8108/multi_search' \
    -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
    -X POST \
    -d '{
          "searches": [
            {
              "q": "chair",
              "query_by": "product_name,embedding",
              "sort_by": "_text_match:desc",
              "exclude_fields": "embedding"
            }
          ]
        }'
```

  </template>

</Tabs>

:::tip
During hybrid search, the `_text_match` clause in `sort_by` will refer to the combined fusion score.
:::

If you are populating the embedding field externally, without using auto-embedding, you can still do a hybrid
search by passing the embedding of the query string manually via the `vector_query` parameter and omitting the 
embedding field from `query_by`.

```shell
curl 'http://localhost:8108/multi_search' \
    -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
    -X POST \
    -d '{
          "searches": [
            {
              "q": "chair",
              "query_by": "product_name",
              "vector_query": "embedding:([0.2, 0.4, 0.1])",
              "sort_by": "_text_match:desc"
            }
          ]
        }'
```

Typesense will do a keyword search using the `q` parameter, and a nearest neighbor search
using the `vector_query` field and combine the results into a ranked set of results using rank fusion as described earlier.

:::warning Performance Tip
If you expect users to use several-words-long queries in the `q` parameter when doing hybrid search (which is common during [conversational search](./conversational-search-rag.md) for eg),
you want to set `drop_tokens_threshold: 0` as an additional search parameter to avoid redundant internal keyword searches and excessive CPU usage. Read more about what this parameter does under [this table](./search.md#typo-tolerance-parameters).
:::

### Weightage for Semantic vs Keyword matches

By default, Typesense assigns a weight of `0.3` for vector search rank and a weight of `0.7` for keyword search rank.
You can adjust the weight assigned to vector search ranking via the `alpha` option of the `vector_query` parameter.

For example, to set a weight of `0.8` to vector search ranking, set `alpha` to `0.8`:

```bash
curl 'http://localhost:8108/multi_search' \
    -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
    -X POST \
    -d '{
          "searches": [
            {
              "collection": "products",
              "query_by": "embedding,product_name",
              "q": "chair",
              "vector_query": "embedding:([], alpha: 0.8)",
              "exclude_fields": "embedding"
            }
          ]
        }'
```

:::tip
When querying on both an embedding field and regular search fields, some parameters like `query_by_weights`
won't have an impact on an embedding field mentioned in `query_by`. However, since length of `query_by_weights`
must match the length of `query_by`, you can use a placeholder value like `0`.
:::

### Re-ranking Hybrid Matches

By default, during hybrid search:
- Documents found through keyword search but not through vector search will only have a text match score
- Documents found through vector search but not through keyword search will only have a vector distance score

You can optionally compute both scores for all matches by setting `rerank_hybrid_matches: true` in your search parameters. When enabled:
- Documents found only through keyword search will also get a vector distance score
- Documents found only through vector search will also get a text match score

This allows for more comprehensive ranking of results, at the cost of additional computation time.

Example:

<Tabs :tabs="['Shell']">
  <template v-slot:Shell>

```bash
curl 'http://localhost:8108/multi_search' \
    -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
    -X POST \
    -d '{
          "searches": [
            {
              "collection": "products",
              "query_by": "embedding,product_name",
              "q": "chair",
              "rerank_hybrid_matches": true,
              "vector_query": "embedding:([], alpha: 0.8)",
              "exclude_fields": "embedding"
            }
          ]
        }'
```

  </template>
</Tabs>

Each hit in the response will contain a `text_match_info` and a `vector_distance` score, regardless of whether it was initially found through keyword or vector search.

### Distance Threshold

You can also set a maximum vector distance threshold for results of semantic search and hybrid search. You should set `distance_threshold` in `vector_query` parameter for this.

<Tabs :tabs="['JavaScript','PHP','Python', 'Ruby','Go','Shell']">

  <template v-slot:JavaScript>

```js
let search_parameters = {
  'q'                          : 'chair',
  'query_by'                   : 'embedding,product_name',
  'vector_query'               : 'embedding:([], distance_threshold:0.30)'
}

client.collections('products').documents().search(search_parameters)
```

  </template>

<template v-slot:PHP>

  ```php
$search_parameters = [
  'q'                          => 'chair',
  'query_by'                   => 'embedding,product_name',
  'vector_query'               => 'embedding:([], distance_threshold:0.30)'
];

$client->collections['products']->documents->search($search_parameters);
```

  </template>

<template v-slot:Python>

  ```py
search_parameters = {
  'q'                          : 'chair',
  'query_by'                   : 'embedding,product_name',
  'vector_query'               : 'embedding:([], distance_threshold:0.30)'
}

client.collections['products'].documents.search(search_parameters)
```

  </template>

<template v-slot:Ruby>

  ```rb
search_parameters = {
  'q'                          => 'chair',
  'query_by'                   => 'embedding,product_name',
  'vector_query'               => 'embedding:([], distance_threshold:0.30)'
}

client.collections['products'].documents.search(search_parameters)
```

  </template>
<template v-slot:Go>

  ```go
searchParameters := &api.SearchCollectionParams{
    Q:           pointer.String("chair"),
    QueryBy:     pointer.String("product_name,embedding"),
    VectorQuery: pointer.String("embedding:([], distance_threshold:0.30)"),
}

client.Collection("products").Documents().Search(context.Background(), searchParameters)
```

  </template>

<template v-slot:Shell>

```bash
curl 'http://localhost:8108/multi_search' \
      -X POST \
      -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
      -d '{
            "searches": [
              {
                "collection": "products",
                "q": "chair",
                "query_by": "embedding,product_name",
                "vector_query": "embedding:([], distance_threshold:0.30)"
              }
            ]
          }'
```

  </template>

</Tabs>

### Sorting hybrid matches on vector distance

If you want to fetch both keyword and vector search matches but sort the results only on the vector distance,
you can use the special sort keyword `_vector_distance`  in `sort_by`.

Here's an example:

```json
{
  "q": "chair",
  "query_by": "title,embedding",
  "sort_by": "popularity_score:desc,_vector_distance:asc"
}
```

We are searching on both the title text field and the `embedding` vector field, but the final results are sorted
first on `popularity_score` and then on vector distance.

## Searching with historical queries

You can send a list of search queries via the `queries` parameter to make vector search compute a weighted query embedding
from the queries. You can use this for personalizing search results based on historical search queries.

In the following example, vector search is made from the embedding calculated from the embeddings of the queries
`smart phone` and `apple ipad`.

We can also use the optional `query_weights` parameter to assign appropriate weights to the queries. If the
`query_weights` parameter is not passed, all queries will have equal weightage.

```json
{
  "vector_query": "embedding:([], queries:[smart phone, apple ipad], query_weights:[0.9, 0.1])"
}
```

## Rank keyword search via vector search

Instead of combining the scores from both keyword and vector search, you can also use vector search distances as a
sorting clause for reordering keyword search hits.

In the example below, we are using the vector distance as a secondary sorting condition to text match score.

```json
{
  "q": "shoes",
  "query_by": "title",
  "sort_by": "_text_match:desc,_vector_query(embedding:([])):asc"
}
```

## 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' \
      -X POST \
      -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
      -d '{
            "searches": [
              {
                "collection": "docs",
                "q": "*",
                "filter_by": "category:shoes",
                "vector_query": "embedding:([0.96826, 0.94, 0.39557, 0.306488], k:100, flat_search_cutoff: 20)"
              }
            ]
          }'

# Be sure to replace `embedding` with the name of the field that stores your embeddings.
```

## Configuring HNSW parameters

#### Indexing parameters

You can set `ef_construction` (default: `200`) and `M` (default: `16`) for vector and embedding fields while creating
the collection.

```json
{
  "name": "docs",
  "fields": [
    {
      "name": "vec",
      "type": "float[]",
      "num_dim": 768,
      "hnsw_params": {
        "ef_construction": 100,
        "M": 8
      }
    }
  ]
}
```
#### Search Parameters

You can set a custom `ef` via the `vector_query` parameter (default value is `10`).

```json
{
  "vector_query" : "vec:([], ef:100)"
}
```

## Distance Metrics

By default, Typesense uses cosine similarity as the distance metric for vector search. When you use a `distance_threshold` parameter, documents with cosine distances larger than the threshold will:

- In standalone vector search: be excluded from results
- When used in sorting (`sort_by`): get the maximum possible distance score but remain in results

You can use this with both cosine similarity and inner product distance metrics. For example:

```json
{
  "vector_query": "embedding:([], distance_threshold: 0.30)"
}
```

This helps filter out less relevant results while still allowing other sort conditions to take effect.

## Vector Distance Bucketing

Similar to [Text Match Score Bucketing](./search.md#text-match-score-bucketing), you can also use the same bucketing concept explained in the previous link to bucket on the vector distance like this:

```json
{
  "sort_by": "_vector_distance(bucket_size: 10), popularity:desc"
}
```

This will cause the ranked result set to be divided into buckets with 10 results each, then a tie is forced inside each bucket and the popularity score is used to break that tie. 

This effectively mixes your custom score (`popularity` in the example above) with vector similarity.

## Vector Search Parameters

Here are all the possible parameters you can use inside the `vector_query` search parameter, that we've covered in the various sections above:

| Parameter            | Description                                                             |  Example                                                                                                                  |
|----------------------|-------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|
| `k`                  | Number of nearest neighbors to return                                   |  `k:100`                                                                                                                  |
| `id`                 | ID of a document to find similar documents to                           |  `id:foobar`                                                                                                              |
| `alpha`              | Weight assigned to vector search ranking in hybrid search               |  `alpha:0.8`                                                                                                              |
| `distance_threshold` | Maximum vector distance threshold for results                           |  `distance_threshold:0.30`                                                                                                |
| `queries`            | List of historical search queries to compute a weighted query embedding |  `queries:[smart phone, apple ipad]`                                                                                      |
| `query_weights`      | Weights corresponding to the queries                                    |  `query_weights:[0.9, 0.1]`                                                                                               |
| `flat_search_cutoff` | Threshold for bypassing HNSW index for brute-force search []            |  `flat_search_cutoff:20`                                                                                                  |
| `ef`                 | Custom HNSW search parameter                                            |  `ef:100`                                                                                                                 |

You can use each of the above parameters inside `vector_query` like this example:

```json
{
  "vector_query": "vector_field_name:([], k: 100, alpha: 0.8, distance_threshold:0.30)"
}
```

## UI Examples

- [Here's](https://hn-comments-search.typesense.org) a demo that shows you how to implement Hybrid Search (Semantic Search + Keyword Search + Filtering + Faceting) using Typesense's built-in embedding generation mechanism.

- [Here's](https://ecommerce-store.typesense.org/) a demo that shows you how to implement a "Find Similar" feature using Vector Search in an ecommerce store.

  Click on "Find Similar" below each product tile for notes on how to implement this.

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