Skip to content

v1.16: Multimodal search #3312

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jul 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1533,3 +1533,19 @@ update_network_1: |-
}
}
}'
search_parameter_reference_media_1: |-
curl \
-X POST 'MEILISEARCH_URL/indexes/INDEX_NAME/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"hybrid": {
"embedder": "EMBEDDER_NAME"
},
"media": {
"FIELD_A": "VALUE_A",
"FIELD_B" : {
"FIELD_C": "VALUE_B"
"FIELD_D": "VALUE_C"
}
}
}'
4 changes: 3 additions & 1 deletion learn/resources/experimental_features_overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,6 @@ Activating or deactivating experimental features this way does not require you t
| [Search query embedding cache](/learn/self_hosted/configure_meilisearch_at_launch#search-query-embedding-cache) | Enable a cache for search query embeddings | CLI flag or environment variable |
| [Uncompressed snapshots](/learn/self_hosted/configure_meilisearch_at_launch#uncompressed-snapshots) | Disable snapshot compaction | CLI flag or environment variable |
| [Maximum batch payload size](/learn/self_hosted/configure_meilisearch_at_launch#maximum-batch-payload-size) | Limit batch payload size | CLI flag or environment variable |
| [Disable new indexer](/learn/self_hosted/configure_meilisearch_at_launch) | Use previous settings indexer | CLI flag or environment variable |
| [Multimodal search](/reference/api/settings) | Enable multimodal search | API route |
| [Disable new indexer](/learn/self_hosted/configure_meilisearch_at_launch) | Use previous settings indexer | CLI flag or environment variable |

10 changes: 7 additions & 3 deletions reference/api/experimental_features.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ The experimental API route is not compatible with all experimental features. Con
"containsFilter": false,
"editDocumentsByFunction": false,
"network": false,
"chatCompletions": false
"chatCompletions": false,
"multimodal": false
}
```

Expand All @@ -38,6 +39,7 @@ The experimental API route is not compatible with all experimental features. Con
| **`editDocumentsByFunction`** | Boolean | `true` if feature is active, `false` otherwise |
| **`network`** | Boolean | `true` if feature is active, `false` otherwise |
| **`chatCompletions`** | Boolean | `true` if feature is active, `false` otherwise |
| **`multimodal`** | Boolean | `true` if feature is active, `false` otherwise |

## Get all experimental features

Expand All @@ -58,7 +60,8 @@ Get a list of all experimental features that can be activated via the `/experime
"containsFilter": false,
"editDocumentsByFunction": false,
"network": false,
"chatCompletions": false
"chatCompletions": false,
"multimodal": false
}
```

Expand Down Expand Up @@ -87,6 +90,7 @@ Setting a field to `null` leaves its value unchanged.
"containsFilter": false,
"editDocumentsByFunction": false,
"network": false,
"chatCompletions": false
"chatCompletions": false,
"multimodal": false
}
```
44 changes: 44 additions & 0 deletions reference/api/search.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ By default, [this endpoint returns a maximum of 1000 results](/learn/resources/k
| **[`vector`](#vector)** | Array of numbers | `null` | Search using a custom query vector |
| **[`retrieveVectors`](#display-_vectors-in-response)** | Boolean | `false` | Return document vector data |
| **[`locales`](#query-locales)** | Array of strings | `null` | Explicitly specify languages used in a query |
| **[`media`](#media)** | Object | `null` | Perform AI-powered search queries with multimodal content |

### Response

Expand Down Expand Up @@ -1283,3 +1284,46 @@ For full control over the way Meilisearch detects languages during indexing and
}
```

### Media <NoticeTag type="experimental" label="experimental" />

**Parameter**: `media`<br />
**Expected value**: Object<br />
**Default value**: `null`

<Note>
This is an experimental feature. Use the Meilisearch Cloud UI or the experimental features endpoint to activate it:

```sh
curl \
-X PATCH 'MEILISEARCH_URL/experimental-features/' \
-H 'Content-Type: application/json' \
--data-binary '{
"multimodal": true
}'
```
</Note>

Specifies data to populate search fragments when performing multimodal searches.

`media` must be an object whose fields must correspond to the data required by one [search fragment](/reference/api/settings#searchfragments). `media` must match a single search fragment. If `media` matches more than one fragment or no search fragments at all, Meilisearch will return an error.

It is mandatory to specify an embedder when using `media`. `media` is incompatible with `vector`.

#### Example

<CodeSamplesSearchParameterReferenceMedia1 />

```json
{
"hits": [
{
"id": 0,
"title": "DOCUMENT NAME",
}
],
}
```
116 changes: 115 additions & 1 deletion reference/api/settings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2512,7 +2512,9 @@ These embedder objects may contain the following fields:
| **`binaryQuantized`** | Boolean | Empty | Once set to `true`, irreversibly converts all vector dimensions to 1-bit values |
| **`indexingEmbedder`** | Object | Empty | Configures embedder to vectorize documents during indexing |
| **`searchEmbedder`** | Object | Empty | Configures embedder to vectorize search queries |
| **`pooling`** | String | `"useModel"` | Pooling method for Hugging Face embedders |
| **`pooling`** | String | `"useModel"` | Pooling method for Hugging Face embedders |
| **`indexingFragments`** | Object | Empty | Configures multimodal embedding generation at indexing time |
| **`searchFragments`** | Object | Empty | Configures data handling during multimodal search |

### Get embedder settings

Expand Down Expand Up @@ -2875,6 +2877,118 @@ Both fields must be an object and accept the same fields as a regular embedder,

`indexingEmbedder` and `searchEmbedder` are incompatible with all other embedder sources.

##### `indexingFragments` <NoticeTag type="experimental" label="experimental" />

<Note>
This is an experimental feature. Use the Meilisearch Cloud UI or the experimental features endpoint to activate it:

```sh
curl \
-X PATCH 'MEILISEARCH_URL/experimental-features/' \
-H 'Content-Type: application/json' \
--data-binary '{
"multimodal": true
}'
```
</Note>

`indexingFragments` specifies which fields in your documents should be used to generate multimodal embeddings. It must be an object with the following structure:

```json
"FRAGMENT_NAME": {
"value": {
}
}
```

`FRAGMENT_NAME` can be any valid string. It must contain a single field, `value`. `value` must then follow your chosen model's specifications.

For example, for [VoyageAI's multimodal embedding route](https://docs.voyageai.com/reference/multimodal-embeddings-api), `value` must be an object containing a `content` field. `content` itself must contain an array of objects with a `type` field. Depending on `type`'s value, you must include either `text`, `image_url`, or `image_base64`:

```json
{
"VOYAGE_FRAGMENT_NAME_A": {
"value": {
"content": [
{
"type": "text",
"text": "A document called {{doc.title}} that can be described as {{doc.description}}"
}
]
}
},
"VOYAGE_FRAGMENT_NAME_B": {
"value": {
"content": [
{
"type": "image_url",
"image_url": "{{doc.image_url}}"
}
]
}
},
}
```

Use Liquid templates to interpolate document data into the fragment fields, where `doc` gives you access to all fields within a document.

`indexingFragments` is optional when using the `rest` source.

`indexingFragments` is incompatible with all other embedder sources.

Specifying a `documentTemplate` in an embedder using `indexingFragments` will result in an error.

You must specify at least one valid fragment in `searchFragments` when using `indexingFragments`.

##### `searchFragments` <NoticeTag type="experimental" label="experimental" />

<Note>
This is an experimental feature. Use the Meilisearch Cloud UI or the experimental features endpoint to activate it:

```sh
curl \
-X PATCH 'MEILISEARCH_URL/experimental-features/' \
-H 'Content-Type: application/json' \
--data-binary '{
"multimodal": true
}'
```
</Note>

`searchFragments` instructs Meilisearch how to parse fields present in a query's [`media` search parameter](/reference/api/search#media). It must be an object following the same structure as the [`indexingFragments`](/reference/api/settings#indexingfragments) object:

```json
"FRAGMENT_NAME": {
"value": {
}
}
```

As with `indexingFragments`, the content of `value` should follow your model's specification.

Use Liquid templates to interpolate search query data into the fragment fields, where `media` gives you access to all multimodal data received with a query:

```json
"SEARCH_FRAGMENT_A": {
"value": {
"content": [
{
"type": "image_base64",
"image_base64": "data:{{media.image.mime}};base64,{{media.image.data}}"
}
]
}
},
```

`searchFragments` is optional when using the `rest` source.

`searchFragments` is incompatible with all other embedder sources.

You must specify at least one valid fragment in `indexingFragments` when using `searchFragments`.

#### Example

<CodeSamplesUpdateEmbedders1 />
Expand Down
8 changes: 8 additions & 0 deletions reference/errors/error_codes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ The given [`uid`](/reference/api/keys#uid) is invalid. The `uid` must follow the

The value passed to [`attributesToSearchOn`](/reference/api/search#customize-attributes-to-search-on-at-search-time) is invalid. `attributesToSearchOn` accepts an array of strings indicating document attributes. Attributes given to `attributesToSearchOn` must be present in the [`searchableAttributes` list](/learn/relevancy/displayed_searchable_attributes#the-searchableattributes-list).

## `invalid_search_media`

The value passed to [`media`](/reference/api/search#media) is not a valid JSON object.

## `invalid_search_media_and_vector`

The search query contains non-`null` values for both [`media`](/reference/api/search#media) and [`vector`](/reference/api/search#media). These two parameters are mutually exclusive, since `media` generates vector embeddings via the embedder configured in `hybrid`.

## `invalid_content_type`

The [Content-Type header](/reference/api/overview#content-type) is not supported by Meilisearch. Currently, Meilisearch only supports JSON, CSV, and NDJSON.
Expand Down
Loading