From e8fe43ec29aa0eacb9239a233f0377a4d20030d1 Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Thu, 24 Jul 2025 17:56:24 +0200 Subject: [PATCH] feat(analytics): add personalization tracking to segment analytics - Add total_personalized field to SearchAggregator to track personalization usage - Track when search requests include personalization parameters - Include personalization data in analytics JSON output - Maintain clean personalization service interface --- crates/meilisearch/src/personalization/mod.rs | 14 ++++++-------- .../src/routes/indexes/search_analytics.rs | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/crates/meilisearch/src/personalization/mod.rs b/crates/meilisearch/src/personalization/mod.rs index 490fb78aa..cff5cc12f 100644 --- a/crates/meilisearch/src/personalization/mod.rs +++ b/crates/meilisearch/src/personalization/mod.rs @@ -23,15 +23,14 @@ impl CohereService { query: Option<&str>, ) -> Result { // Extract user context from personalization - let Some(personalize) = personalize else { return Ok(search_result) }; - let user_context = personalize.user_context.as_deref(); + let Some(user_context) = personalize.and_then(|p| p.user_context.as_deref()) else { + return Ok(search_result); + }; // Build the prompt by merging query and user context - let prompt = match (query, user_context) { - (Some(q), Some(uc)) => format!("User Context: {}\nQuery: {}", uc, q), - (Some(q), None) => q.to_string(), - (None, Some(uc)) => format!("User Context: {}", uc), - (None, None) => return Ok(search_result), + let prompt = match query { + Some(q) => format!("User Context: {user_context}\nQuery: {q}"), + None => format!("User Context: {user_context}"), }; // Extract documents for reranking @@ -65,7 +64,6 @@ impl CohereService { // Create a mapping from original index to new rank let reranked_indices: Vec = rerank_response.iter().map(|result| result.index as usize).collect(); - debug!("Reranked indices: {:?}", reranked_indices); // Reorder the hits based on Cohere's reranking let mut reranked_hits = Vec::new(); diff --git a/crates/meilisearch/src/routes/indexes/search_analytics.rs b/crates/meilisearch/src/routes/indexes/search_analytics.rs index 0e6b96d2e..6c678b7ba 100644 --- a/crates/meilisearch/src/routes/indexes/search_analytics.rs +++ b/crates/meilisearch/src/routes/indexes/search_analytics.rs @@ -94,6 +94,9 @@ pub struct SearchAggregator { show_ranking_score_details: bool, ranking_score_threshold: bool, + // personalization + total_personalized: usize, + marker: std::marker::PhantomData, } @@ -128,7 +131,7 @@ impl SearchAggregator { hybrid, ranking_score_threshold, locales, - personalize: _, + personalize, } = query; let mut ret = Self::default(); @@ -203,6 +206,11 @@ impl SearchAggregator { ret.locales = locales.iter().copied().collect(); } + // personalization + if personalize.is_some() { + ret.total_personalized = 1; + } + ret.highlight_pre_tag = *highlight_pre_tag != DEFAULT_HIGHLIGHT_PRE_TAG(); ret.highlight_post_tag = *highlight_post_tag != DEFAULT_HIGHLIGHT_POST_TAG(); ret.crop_marker = *crop_marker != DEFAULT_CROP_MARKER(); @@ -291,6 +299,7 @@ impl Aggregate for SearchAggregator { total_used_negative_operator, ranking_score_threshold, mut locales, + total_personalized, marker: _, } = *new; @@ -375,6 +384,9 @@ impl Aggregate for SearchAggregator { // locales self.locales.append(&mut locales); + // personalization + self.total_personalized = self.total_personalized.saturating_add(total_personalized); + self } @@ -419,6 +431,7 @@ impl Aggregate for SearchAggregator { total_used_negative_operator, ranking_score_threshold, locales, + total_personalized, marker: _, } = *self; @@ -491,6 +504,9 @@ impl Aggregate for SearchAggregator { "show_ranking_score_details": show_ranking_score_details, "ranking_score_threshold": ranking_score_threshold, }, + "personalization": { + "total_personalized": total_personalized, + }, }) } }