mirror of
https://github.com/meilisearch/MeiliSearch
synced 2025-03-12 19:11:42 +01:00
958 lines
29 KiB
Rust
958 lines
29 KiB
Rust
use meili_snap::{json_string, snapshot};
|
|
|
|
use crate::common::{GetAllDocumentsOptions, Server};
|
|
use crate::json;
|
|
use crate::vector::generate_default_user_provided_documents;
|
|
|
|
#[actix_rt::test]
|
|
async fn field_unavailable_for_source() {
|
|
let server = Server::new().await;
|
|
let index = server.index("doggo");
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": { "manual": {"source": "userProvided", "dimensions": 128, "documentTemplate": "{{doc.documentTemplate}}"}},
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"400 Bad Request");
|
|
snapshot!(response, @r###"
|
|
{
|
|
"message": "`.embedders.manual`: Field `documentTemplate` unavailable for source `userProvided`.\n - note: `documentTemplate` is available for sources: `openAi`, `huggingFace`, `ollama`, `rest`\n - note: available fields for source `userProvided`: `source`, `dimensions`, `distribution`, `binaryQuantized`",
|
|
"code": "invalid_settings_embedders",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_settings_embedders"
|
|
}
|
|
"###);
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": { "default": {"source": "openAi", "revision": "42"}},
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"400 Bad Request");
|
|
snapshot!(response, @r###"
|
|
{
|
|
"message": "`.embedders.default`: Field `revision` unavailable for source `openAi`.\n - note: `revision` is available for sources: `huggingFace`\n - note: available fields for source `openAi`: `source`, `model`, `apiKey`, `dimensions`, `documentTemplate`, `documentTemplateMaxBytes`, `url`, `distribution`, `binaryQuantized`",
|
|
"code": "invalid_settings_embedders",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_settings_embedders"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn update_embedder() {
|
|
let server = Server::new().await;
|
|
let index = server.index("doggo");
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": { "manual": {}},
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"202 Accepted");
|
|
server.wait_task(response.uid()).await.succeeded();
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"manual": {
|
|
"source": "userProvided",
|
|
"dimensions": 2,
|
|
}
|
|
},
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"202 Accepted");
|
|
|
|
let ret = server.wait_task(response.uid()).await;
|
|
snapshot!(ret, @r###"
|
|
{
|
|
"uid": "[uid]",
|
|
"batchUid": "[batch_uid]",
|
|
"indexUid": "doggo",
|
|
"status": "succeeded",
|
|
"type": "settingsUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"embedders": {
|
|
"manual": {
|
|
"source": "userProvided",
|
|
"dimensions": 2
|
|
}
|
|
}
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn reset_embedder_documents() {
|
|
let server = Server::new().await;
|
|
let index = generate_default_user_provided_documents(&server).await;
|
|
|
|
let (response, code) = index.delete_settings().await;
|
|
snapshot!(code, @"202 Accepted");
|
|
server.wait_task(response.uid()).await;
|
|
|
|
// Make sure the documents are still present
|
|
let (documents, _code) = index
|
|
.get_all_documents(GetAllDocumentsOptions {
|
|
limit: None,
|
|
offset: None,
|
|
retrieve_vectors: false,
|
|
fields: None,
|
|
})
|
|
.await;
|
|
snapshot!(json_string!(documents), @r###"
|
|
{
|
|
"results": [
|
|
{
|
|
"id": 0,
|
|
"name": "kefir"
|
|
},
|
|
{
|
|
"id": 1,
|
|
"name": "echo"
|
|
},
|
|
{
|
|
"id": 2,
|
|
"name": "billou"
|
|
},
|
|
{
|
|
"id": 3,
|
|
"name": "intel"
|
|
},
|
|
{
|
|
"id": 4,
|
|
"name": "max"
|
|
}
|
|
],
|
|
"offset": 0,
|
|
"limit": 20,
|
|
"total": 5
|
|
}
|
|
"###);
|
|
|
|
// Make sure we are still able to retrieve their vectors
|
|
let (documents, _code) = index
|
|
.get_all_documents(GetAllDocumentsOptions { retrieve_vectors: true, ..Default::default() })
|
|
.await;
|
|
snapshot!(json_string!(documents), @r###"
|
|
{
|
|
"results": [
|
|
{
|
|
"id": 0,
|
|
"name": "kefir",
|
|
"_vectors": {
|
|
"manual": {
|
|
"embeddings": [
|
|
[
|
|
0.0,
|
|
0.0,
|
|
0.0
|
|
]
|
|
],
|
|
"regenerate": false
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"id": 1,
|
|
"name": "echo",
|
|
"_vectors": {
|
|
"manual": {
|
|
"embeddings": [
|
|
[
|
|
1.0,
|
|
1.0,
|
|
1.0
|
|
]
|
|
],
|
|
"regenerate": false
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"id": 2,
|
|
"name": "billou",
|
|
"_vectors": {
|
|
"manual": {
|
|
"embeddings": [
|
|
[
|
|
2.0,
|
|
2.0,
|
|
2.0
|
|
],
|
|
[
|
|
2.0,
|
|
2.0,
|
|
3.0
|
|
]
|
|
],
|
|
"regenerate": false
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"id": 3,
|
|
"name": "intel",
|
|
"_vectors": {
|
|
"manual": {
|
|
"embeddings": [
|
|
[
|
|
3.0,
|
|
3.0,
|
|
3.0
|
|
]
|
|
],
|
|
"regenerate": false
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"id": 4,
|
|
"name": "max",
|
|
"_vectors": {
|
|
"manual": {
|
|
"embeddings": [
|
|
[
|
|
4.0,
|
|
4.0,
|
|
4.0
|
|
],
|
|
[
|
|
4.0,
|
|
4.0,
|
|
5.0
|
|
]
|
|
],
|
|
"regenerate": false
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"offset": 0,
|
|
"limit": 20,
|
|
"total": 5
|
|
}
|
|
"###);
|
|
|
|
// Make sure the arroy DB has been cleared
|
|
let (documents, _code) =
|
|
index.search_post(json!({ "vector": [1, 1, 1], "hybrid": {"embedder": "default"} })).await;
|
|
snapshot!(json_string!(documents), @r###"
|
|
{
|
|
"message": "Cannot find embedder with name `default`.",
|
|
"code": "invalid_search_embedder",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_search_embedder"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn ollama_url_checks() {
|
|
let server = super::get_server_vector().await;
|
|
let index = server.index("doggo");
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": { "ollama": {"source": "ollama", "model": "toto", "dimensions": 1, "url": "http://localhost:11434/api/embeddings"}},
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"202 Accepted");
|
|
let response = server.wait_task(response.uid()).await;
|
|
|
|
snapshot!(response, @r###"
|
|
{
|
|
"uid": "[uid]",
|
|
"batchUid": "[batch_uid]",
|
|
"indexUid": "doggo",
|
|
"status": "succeeded",
|
|
"type": "settingsUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"embedders": {
|
|
"ollama": {
|
|
"source": "ollama",
|
|
"model": "toto",
|
|
"dimensions": 1,
|
|
"url": "[url]"
|
|
}
|
|
}
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": { "ollama": {"source": "ollama", "model": "toto", "dimensions": 1, "url": "http://localhost:11434/api/embed"}},
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"202 Accepted");
|
|
let response = server.wait_task(response.uid()).await;
|
|
|
|
snapshot!(response, @r###"
|
|
{
|
|
"uid": "[uid]",
|
|
"batchUid": "[batch_uid]",
|
|
"indexUid": "doggo",
|
|
"status": "succeeded",
|
|
"type": "settingsUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"embedders": {
|
|
"ollama": {
|
|
"source": "ollama",
|
|
"model": "toto",
|
|
"dimensions": 1,
|
|
"url": "[url]"
|
|
}
|
|
}
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": { "ollama": {"source": "ollama", "model": "toto", "dimensions": 1, "url": "http://localhost:11434/api/embedd"}},
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"202 Accepted");
|
|
let response = server.wait_task(response.uid()).await;
|
|
|
|
snapshot!(response, @r###"
|
|
{
|
|
"uid": "[uid]",
|
|
"batchUid": "[batch_uid]",
|
|
"indexUid": "doggo",
|
|
"status": "failed",
|
|
"type": "settingsUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"embedders": {
|
|
"ollama": {
|
|
"source": "ollama",
|
|
"model": "toto",
|
|
"dimensions": 1,
|
|
"url": "[url]"
|
|
}
|
|
}
|
|
},
|
|
"error": {
|
|
"message": "Index `doggo`: Error while generating embeddings: user error: unsupported Ollama URL.\n - For `ollama` sources, the URL must end with `/api/embed` or `/api/embeddings`\n - Got `http://localhost:11434/api/embedd`",
|
|
"code": "vector_embedding_error",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#vector_embedding_error"
|
|
},
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": { "ollama": {"source": "ollama", "model": "toto", "dimensions": 1, "url": "http://localhost:11434/v1/embeddings"}},
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"202 Accepted");
|
|
let response = server.wait_task(response.uid()).await;
|
|
|
|
snapshot!(response, @r###"
|
|
{
|
|
"uid": "[uid]",
|
|
"batchUid": "[batch_uid]",
|
|
"indexUid": "doggo",
|
|
"status": "failed",
|
|
"type": "settingsUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"embedders": {
|
|
"ollama": {
|
|
"source": "ollama",
|
|
"model": "toto",
|
|
"dimensions": 1,
|
|
"url": "[url]"
|
|
}
|
|
}
|
|
},
|
|
"error": {
|
|
"message": "Index `doggo`: Error while generating embeddings: user error: unsupported Ollama URL.\n - For `ollama` sources, the URL must end with `/api/embed` or `/api/embeddings`\n - Got `http://localhost:11434/v1/embeddings`",
|
|
"code": "vector_embedding_error",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#vector_embedding_error"
|
|
},
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn composite_checks() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
// inner distribution
|
|
let (response, _code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": null
|
|
}
|
|
}))
|
|
.await;
|
|
server.wait_task(response.uid()).await;
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
"distribution": {
|
|
"mean": 0.5,
|
|
"sigma": 0.2,
|
|
}
|
|
},
|
|
"indexingEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
},
|
|
}
|
|
}
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"400 Bad Request");
|
|
snapshot!(response, @r###"
|
|
{
|
|
"message": "`.embedders.test.searchEmbedder`: Field `distribution` unavailable for source `huggingFace` for the search embedder.\n - note: available fields for source `huggingFace` for the search embedder: `source`, `model`, `revision`, `pooling`\n - note: `distribution` is available when source `huggingFace` is not for the search embedder",
|
|
"code": "invalid_settings_embedders",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_settings_embedders"
|
|
}
|
|
"###);
|
|
// manual source
|
|
let (response, _code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": null
|
|
}
|
|
}))
|
|
.await;
|
|
server.wait_task(response.uid()).await;
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "userProvided",
|
|
"dimensions": 42,
|
|
},
|
|
"indexingEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
},
|
|
}
|
|
}
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"400 Bad Request");
|
|
snapshot!(response, @r###"
|
|
{
|
|
"message": "`.embedders.test.searchEmbedder.source`: Source `userProvided` is not available in a nested embedder",
|
|
"code": "invalid_settings_embedders",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_settings_embedders"
|
|
}
|
|
"###);
|
|
// composite source
|
|
let (response, _code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": null
|
|
}
|
|
}))
|
|
.await;
|
|
server.wait_task(response.uid()).await;
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
},
|
|
"indexingEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
}
|
|
},
|
|
"indexingEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
},
|
|
}
|
|
}
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"400 Bad Request");
|
|
snapshot!(response, @r###"
|
|
{
|
|
"message": "`.embedders.test.searchEmbedder.source`: Source `composite` is not available in a nested embedder",
|
|
"code": "invalid_settings_embedders",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_settings_embedders"
|
|
}
|
|
"###);
|
|
// no source in indexing
|
|
let (response, _code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": null
|
|
}
|
|
}))
|
|
.await;
|
|
server.wait_task(response.uid()).await;
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
},
|
|
"indexingEmbedder": {},
|
|
}
|
|
}
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"400 Bad Request");
|
|
snapshot!(response, @r###"
|
|
{
|
|
"message": "`.embedders.test.indexingEmbedder`: Missing field `source`.\n - note: this field is mandatory for nested embedders",
|
|
"code": "invalid_settings_embedders",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_settings_embedders"
|
|
}
|
|
"###);
|
|
// no source in search
|
|
let (response, _code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": null
|
|
}
|
|
}))
|
|
.await;
|
|
server.wait_task(response.uid()).await;
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {},
|
|
"indexingEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
},
|
|
}
|
|
}
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"400 Bad Request");
|
|
snapshot!(response, @r###"
|
|
{
|
|
"message": "`.embedders.test.searchEmbedder`: Missing field `source`.\n - note: this field is mandatory for nested embedders",
|
|
"code": "invalid_settings_embedders",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_settings_embedders"
|
|
}
|
|
"###);
|
|
// no indexing
|
|
let (response, _code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": null
|
|
}
|
|
}))
|
|
.await;
|
|
server.wait_task(response.uid()).await;
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
},
|
|
}
|
|
}
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"400 Bad Request");
|
|
snapshot!(response, @r###"
|
|
{
|
|
"message": "`.embedders.test`: Missing field `indexingEmbedder` (note: this field is mandatory for source `composite`)",
|
|
"code": "invalid_settings_embedders",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_settings_embedders"
|
|
}
|
|
"###);
|
|
// no search
|
|
let (response, _code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": null
|
|
}
|
|
}))
|
|
.await;
|
|
server.wait_task(response.uid()).await;
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"indexingEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
},
|
|
}
|
|
}
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"400 Bad Request");
|
|
snapshot!(response, @r###"
|
|
{
|
|
"message": "`.embedders.test`: Missing field `searchEmbedder` (note: this field is mandatory for source `composite`)",
|
|
"code": "invalid_settings_embedders",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_settings_embedders"
|
|
}
|
|
"###);
|
|
// inner quantized
|
|
let (response, _code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": null
|
|
}
|
|
}))
|
|
.await;
|
|
server.wait_task(response.uid()).await;
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
"binaryQuantized": true,
|
|
},
|
|
"indexingEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
"binaryQuantized": false,
|
|
},
|
|
}
|
|
}
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"400 Bad Request");
|
|
snapshot!(response, @r###"
|
|
{
|
|
"message": "`.embedders.test.searchEmbedder`: Field `binaryQuantized` unavailable for source `huggingFace` for the search embedder.\n - note: available fields for source `huggingFace` for the search embedder: `source`, `model`, `revision`, `pooling`\n - note: `binaryQuantized` is available when source `huggingFace` is not for the search embedder",
|
|
"code": "invalid_settings_embedders",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_settings_embedders"
|
|
}
|
|
"###);
|
|
// prompt in search
|
|
let (response, _code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": null
|
|
}
|
|
}))
|
|
.await;
|
|
server.wait_task(response.uid()).await;
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
"documentTemplate": "toto",
|
|
},
|
|
"indexingEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
},
|
|
}
|
|
}
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"400 Bad Request");
|
|
snapshot!(response, @r###"
|
|
{
|
|
"message": "`.embedders.test.searchEmbedder`: Field `documentTemplate` unavailable for source `huggingFace` for the search embedder.\n - note: available fields for source `huggingFace` for the search embedder: `source`, `model`, `revision`, `pooling`\n - note: `documentTemplate` is available when source `huggingFace` is not for the search embedder",
|
|
"code": "invalid_settings_embedders",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_settings_embedders"
|
|
}
|
|
"###);
|
|
// dimensions don't match
|
|
let (response, _code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": null
|
|
}
|
|
}))
|
|
.await;
|
|
server.wait_task(response.uid()).await;
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "ollama",
|
|
"dimensions": 0x42,
|
|
"model": "does-not-exist",
|
|
},
|
|
"indexingEmbedder": {
|
|
"source": "ollama",
|
|
"dimensions": 42,
|
|
"model": "does-not-exist",
|
|
},
|
|
}
|
|
}
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"202 Accepted");
|
|
let response = server.wait_task(response.uid()).await;
|
|
snapshot!(response, @r###"
|
|
{
|
|
"uid": "[uid]",
|
|
"batchUid": "[batch_uid]",
|
|
"indexUid": "test",
|
|
"status": "failed",
|
|
"type": "settingsUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "ollama",
|
|
"model": "does-not-exist",
|
|
"dimensions": 66
|
|
},
|
|
"indexingEmbedder": {
|
|
"source": "ollama",
|
|
"model": "does-not-exist",
|
|
"dimensions": 42
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"error": {
|
|
"message": "Index `test`: Error while generating embeddings: user error: error while generating test embeddings.\n - the dimensions of embeddings produced at search time and at indexing time don't match.\n - Search time dimensions: 66\n - Indexing time dimensions: 42\n - Note: Dimensions of embeddings produced by both embedders are required to match.",
|
|
"code": "vector_embedding_error",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#vector_embedding_error"
|
|
},
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
// pooling don't match
|
|
let (response, _code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": null
|
|
}
|
|
}))
|
|
.await;
|
|
server.wait_task(response.uid()).await;
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
"pooling": "forceMean"
|
|
},
|
|
"indexingEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
"pooling": "forceCls"
|
|
},
|
|
}
|
|
}
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"202 Accepted");
|
|
let response = server.wait_task(response.uid()).await;
|
|
snapshot!(response, @r###"
|
|
{
|
|
"uid": "[uid]",
|
|
"batchUid": "[batch_uid]",
|
|
"indexUid": "test",
|
|
"status": "failed",
|
|
"type": "settingsUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
"pooling": "forceMean"
|
|
},
|
|
"indexingEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
"pooling": "forceCls"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"error": {
|
|
"message": "Index `test`: Error while generating embeddings: user error: error while generating test embeddings.\n - the embeddings produced at search time and indexing time are not similar enough.\n - angular distance 0.25\n - Meilisearch requires a maximum distance of 0.01.\n - Note: check that both embedders produce similar embeddings.\n - Make sure the `model`, `revision` and `pooling` of both embedders match.",
|
|
"code": "vector_embedding_error",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#vector_embedding_error"
|
|
},
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
// ok
|
|
let (response, _code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": null
|
|
}
|
|
}))
|
|
.await;
|
|
server.wait_task(response.uid()).await;
|
|
|
|
let (response, code) = index
|
|
.update_settings(json!({
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
},
|
|
"indexingEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e",
|
|
},
|
|
}
|
|
}
|
|
}))
|
|
.await;
|
|
snapshot!(code, @"202 Accepted");
|
|
let response = server.wait_task(response.uid()).await;
|
|
snapshot!(response, @r###"
|
|
{
|
|
"uid": "[uid]",
|
|
"batchUid": "[batch_uid]",
|
|
"indexUid": "test",
|
|
"status": "succeeded",
|
|
"type": "settingsUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"embedders": {
|
|
"test": {
|
|
"source": "composite",
|
|
"searchEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e"
|
|
},
|
|
"indexingEmbedder": {
|
|
"source": "huggingFace",
|
|
"model": "sentence-transformers/all-MiniLM-L6-v2",
|
|
"revision": "e4ce9877abf3edfe10b0d82785e83bdcb973e22e"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|