diff --git a/meilisearch-core/src/bucket_sort.rs b/meilisearch-core/src/bucket_sort.rs index f0fc71bd0..57e50b87f 100644 --- a/meilisearch-core/src/bucket_sort.rs +++ b/meilisearch-core/src/bucket_sort.rs @@ -212,6 +212,7 @@ where FD: Fn(DocumentId) -> Option, { let mut result = SortResult::default(); + let mut filtered_count = 0; let words_set = index.main.words_fst(reader)?; let stop_words = index.main.stop_words_fst(reader)?; @@ -322,19 +323,36 @@ where let filter_accepted = match &filter { Some(filter) => { let entry = filter_map.entry(document.id); - *entry.or_insert_with(|| (filter)(document.id)) + *entry.or_insert_with(|| { + let accepted = (filter)(document.id); + // we only want to count it out the first time we see it + if !accepted { + filtered_count += 1; + } + accepted + }) } None => true, }; if filter_accepted { let entry = key_cache.entry(document.id); - let key = entry.or_insert_with(|| (distinct)(document.id).map(Rc::new)); + let mut seen = true; + let key = entry.or_insert_with(|| { + seen = false; + (distinct)(document.id).map(Rc::new) + }); - match key.clone() { + let distinct = match key.clone() { Some(key) => buf_distinct.register(key), None => buf_distinct.register_without_key(), }; + + // we only want to count the document if it is the first time we see it and + // if it wasn't accepted by distinct + if !seen && !distinct { + filtered_count += 1; + } } // the requested range end is reached: stop computing distinct @@ -396,7 +414,7 @@ where } } result.documents = documents; - result.nb_hits = docids.len(); + result.nb_hits = docids.len() - filtered_count; Ok(result) } diff --git a/meilisearch-http/tests/search.rs b/meilisearch-http/tests/search.rs index 170d9ffaf..06cca487d 100644 --- a/meilisearch-http/tests/search.rs +++ b/meilisearch-http/tests/search.rs @@ -1829,3 +1829,51 @@ async fn update_documents_with_facet_distribution() { let (response2, _) = server.search_post(search).await; assert_json_eq!(expected_facet_distribution, response2["facetsDistribution"].clone()); } + +#[actix_rt::test] +async fn test_filter_nb_hits_search_normal() { + let mut server = common::Server::with_uid("test"); + + let body = json!({ + "uid": "test", + "primaryKey": "id", + }); + + server.create_index(body).await; + let documents = json!([ + { + "id": 1, + "content": "a", + "color": "green", + "size": 1, + }, + { + "id": 2, + "content": "a", + "color": "green", + "size": 2, + }, + { + "id": 3, + "content": "a", + "color": "blue", + "size": 3, + }, + ]); + + server.add_or_update_multiple_documents(documents).await; + let (response, _) = server.search_post(json!({"q": "a"})).await; + assert_eq!(response["nbHits"], 3); + + let (response, _) = server.search_post(json!({"q": "a", "filters": "size = 1"})).await; + assert_eq!(response["nbHits"], 1); + + server.update_distinct_attribute(json!("color")).await; + + let (response, _) = server.search_post(json!({"q": "a"})).await; + assert_eq!(response["nbHits"], 2); + + let (response, _) = server.search_post(json!({"q": "a", "filters": "size < 3"})).await; + println!("result: {}", response); + assert_eq!(response["nbHits"], 1); +}