mirror of
https://github.com/meilisearch/meilisearch.git
synced 2025-10-10 13:46:28 +00:00
feat: add metadata field with queryUid to search responses
- Add SearchMetadata struct with queryUid field (UUID v7) - Add metadata field to SearchResult for /search route - Add metadata field to FederatedSearchResult for /multi-search route - Update perform_search to generate queryUid and set metadata - Update federated search to generate queryUid for each query - Update multi-search non-federated path to include metadata - Fix pattern matching in analytics and other code The metadata field contains: - For /search: single object with queryUid - For /multi-search: array of objects, one per query - For federated search: array of objects, one per query All queryUid values are generated using Uuid::now_v7() for time-ordered uniqueness.
This commit is contained in:
@@ -235,6 +235,7 @@ impl<Method: AggregateMethod> SearchAggregator<Method> {
|
|||||||
degraded,
|
degraded,
|
||||||
used_negative_operator,
|
used_negative_operator,
|
||||||
request_uid: _,
|
request_uid: _,
|
||||||
|
metadata: _,
|
||||||
} = result;
|
} = result;
|
||||||
|
|
||||||
self.total_succeeded = self.total_succeeded.saturating_add(1);
|
self.total_succeeded = self.total_succeeded.saturating_add(1);
|
||||||
|
@@ -20,6 +20,7 @@ use tokio::task::JoinHandle;
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use super::super::ranking_rules::{self, RankingRules};
|
use super::super::ranking_rules::{self, RankingRules};
|
||||||
|
use super::super::SearchMetadata;
|
||||||
use super::super::{
|
use super::super::{
|
||||||
compute_facet_distribution_stats, prepare_search, AttributesFormat, ComputedFacets, HitMaker,
|
compute_facet_distribution_stats, prepare_search, AttributesFormat, ComputedFacets, HitMaker,
|
||||||
HitsInfo, RetrieveVectors, SearchHit, SearchKind, SearchQuery, SearchQueryWithIndex,
|
HitsInfo, RetrieveVectors, SearchHit, SearchKind, SearchQuery, SearchQueryWithIndex,
|
||||||
@@ -59,7 +60,10 @@ pub async fn perform_federated_search(
|
|||||||
|
|
||||||
// 1. partition queries by host and index
|
// 1. partition queries by host and index
|
||||||
let mut partitioned_queries = PartitionedQueries::new();
|
let mut partitioned_queries = PartitionedQueries::new();
|
||||||
|
let mut query_metadata = Vec::new();
|
||||||
for (query_index, federated_query) in queries.into_iter().enumerate() {
|
for (query_index, federated_query) in queries.into_iter().enumerate() {
|
||||||
|
let query_uid = Uuid::now_v7();
|
||||||
|
query_metadata.push(SearchMetadata { query_uid });
|
||||||
partitioned_queries.partition(federated_query, query_index, &network, features)?
|
partitioned_queries.partition(federated_query, query_index, &network, features)?
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,6 +177,7 @@ pub async fn perform_federated_search(
|
|||||||
facets_by_index,
|
facets_by_index,
|
||||||
remote_errors: partitioned_queries.has_remote.then_some(remote_errors),
|
remote_errors: partitioned_queries.has_remote.then_some(remote_errors),
|
||||||
request_uid: Some(request_uid),
|
request_uid: Some(request_uid),
|
||||||
|
metadata: Some(query_metadata),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,6 +447,7 @@ fn merge_metadata(
|
|||||||
degraded: degraded_for_host,
|
degraded: degraded_for_host,
|
||||||
used_negative_operator: host_used_negative_operator,
|
used_negative_operator: host_used_negative_operator,
|
||||||
remote_errors: _,
|
remote_errors: _,
|
||||||
|
metadata: _,
|
||||||
request_uid: _,
|
request_uid: _,
|
||||||
} in remote_results
|
} in remote_results
|
||||||
{
|
{
|
||||||
|
@@ -18,6 +18,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::search::SearchMetadata;
|
||||||
|
|
||||||
use super::super::{ComputedFacets, FacetStats, HitsInfo, SearchHit, SearchQueryWithIndex};
|
use super::super::{ComputedFacets, FacetStats, HitsInfo, SearchHit, SearchQueryWithIndex};
|
||||||
use crate::milli::vector::Embedding;
|
use crate::milli::vector::Embedding;
|
||||||
|
|
||||||
@@ -134,6 +136,8 @@ pub struct FederatedSearchResult {
|
|||||||
pub facets_by_index: FederatedFacets,
|
pub facets_by_index: FederatedFacets,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub request_uid: Option<Uuid>,
|
pub request_uid: Option<Uuid>,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub metadata: Option<Vec<SearchMetadata>>,
|
||||||
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub remote_errors: Option<BTreeMap<String, ResponseError>>,
|
pub remote_errors: Option<BTreeMap<String, ResponseError>>,
|
||||||
@@ -160,6 +164,7 @@ impl fmt::Debug for FederatedSearchResult {
|
|||||||
facets_by_index,
|
facets_by_index,
|
||||||
remote_errors,
|
remote_errors,
|
||||||
request_uid,
|
request_uid,
|
||||||
|
metadata,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let mut debug = f.debug_struct("SearchResult");
|
let mut debug = f.debug_struct("SearchResult");
|
||||||
@@ -195,6 +200,9 @@ impl fmt::Debug for FederatedSearchResult {
|
|||||||
if let Some(request_uid) = request_uid {
|
if let Some(request_uid) = request_uid {
|
||||||
debug.field("request_uid", &request_uid);
|
debug.field("request_uid", &request_uid);
|
||||||
}
|
}
|
||||||
|
if let Some(metadata) = metadata {
|
||||||
|
debug.field("metadata", &metadata);
|
||||||
|
}
|
||||||
|
|
||||||
debug.finish()
|
debug.finish()
|
||||||
}
|
}
|
||||||
|
@@ -836,6 +836,13 @@ pub struct SearchHit {
|
|||||||
pub ranking_score_details: Option<serde_json::Map<String, serde_json::Value>>,
|
pub ranking_score_details: Option<serde_json::Map<String, serde_json::Value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, ToSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[schema(rename_all = "camelCase")]
|
||||||
|
pub struct SearchMetadata {
|
||||||
|
pub query_uid: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Clone, PartialEq, ToSchema)]
|
#[derive(Serialize, Clone, PartialEq, ToSchema)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
#[schema(rename_all = "camelCase")]
|
#[schema(rename_all = "camelCase")]
|
||||||
@@ -854,6 +861,8 @@ pub struct SearchResult {
|
|||||||
pub facet_stats: Option<BTreeMap<String, FacetStats>>,
|
pub facet_stats: Option<BTreeMap<String, FacetStats>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub request_uid: Option<Uuid>,
|
pub request_uid: Option<Uuid>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub metadata: Option<SearchMetadata>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub semantic_hit_count: Option<u32>,
|
pub semantic_hit_count: Option<u32>,
|
||||||
@@ -876,6 +885,7 @@ impl fmt::Debug for SearchResult {
|
|||||||
facet_distribution,
|
facet_distribution,
|
||||||
facet_stats,
|
facet_stats,
|
||||||
request_uid,
|
request_uid,
|
||||||
|
metadata,
|
||||||
semantic_hit_count,
|
semantic_hit_count,
|
||||||
degraded,
|
degraded,
|
||||||
used_negative_operator,
|
used_negative_operator,
|
||||||
@@ -908,6 +918,9 @@ impl fmt::Debug for SearchResult {
|
|||||||
if let Some(request_uid) = request_uid {
|
if let Some(request_uid) = request_uid {
|
||||||
debug.field("request_uid", &request_uid);
|
debug.field("request_uid", &request_uid);
|
||||||
}
|
}
|
||||||
|
if let Some(metadata) = metadata {
|
||||||
|
debug.field("metadata", &metadata);
|
||||||
|
}
|
||||||
|
|
||||||
debug.finish()
|
debug.finish()
|
||||||
}
|
}
|
||||||
@@ -1234,6 +1247,7 @@ pub fn perform_search(
|
|||||||
.map(|ComputedFacets { distribution, stats }| (distribution, stats))
|
.map(|ComputedFacets { distribution, stats }| (distribution, stats))
|
||||||
.unzip();
|
.unzip();
|
||||||
|
|
||||||
|
let query_uid = Uuid::now_v7();
|
||||||
let result = SearchResult {
|
let result = SearchResult {
|
||||||
hits: documents,
|
hits: documents,
|
||||||
hits_info,
|
hits_info,
|
||||||
@@ -1246,6 +1260,7 @@ pub fn perform_search(
|
|||||||
used_negative_operator,
|
used_negative_operator,
|
||||||
semantic_hit_count,
|
semantic_hit_count,
|
||||||
request_uid: Some(request_uid),
|
request_uid: Some(request_uid),
|
||||||
|
metadata: Some(SearchMetadata { query_uid }),
|
||||||
};
|
};
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user