Skip to content

Commit 96d2d02

Browse files
authored
Merge pull request #18 from meilisearch/more-tenant
More tenant token, v1.48 edition
2 parents de87d65 + fea60ee commit 96d2d02

3 files changed

Lines changed: 108 additions & 23 deletions

File tree

crates/meilisearch/src/routes/chats/chat_completions.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use index_scheduler::filter::{
2424
filter_into_index_filter, filters_into_index_filters_unchecked, parse_filter,
2525
};
2626
use index_scheduler::IndexScheduler;
27-
use meilisearch_auth::AuthController;
27+
use meilisearch_auth::{AuthController, IndexSearchRules};
2828
use meilisearch_types::error::{Code, ResponseError};
2929
use meilisearch_types::features::{
3030
ChatCompletionPrompts as DbChatCompletionPrompts,
@@ -35,7 +35,7 @@ use meilisearch_types::keys::actions;
3535
use meilisearch_types::milli::index::ChatConfig;
3636
use meilisearch_types::milli::progress::Progress;
3737
use meilisearch_types::milli::{
38-
all_obkv_to_json, obkv_to_json, OrderBy, PatternMatch, TotalProcessingTimeStep,
38+
all_obkv_to_json, obkv_to_json, Filter, OrderBy, PatternMatch, TotalProcessingTimeStep,
3939
};
4040
use meilisearch_types::{Document, Index};
4141
use serde::Deserialize;
@@ -239,18 +239,29 @@ fn setup_search_tool(
239239
let mut index_uids = Vec::new();
240240
let mut function_description = prompts.search_description.clone();
241241
let mut filter_description = prompts.search_filter_param.clone();
242+
let progress = &Default::default();
242243
index_scheduler.try_for_each_index::<_, ()>(|name, index| {
243244
// Make sure to skip unauthorized indexes
244245
if !filters.is_index_authorized(name) {
245246
return Ok(());
246247
}
248+
let search_rules = filters.get_index_search_rules(name);
247249

248250
let rtxn = index.read_txn()?;
249251
let chat_config = index.chat_config(&rtxn)?;
250252
let index_description = chat_config.description;
251253
let _ = writeln!(&mut function_description, "\n\n - {name}: {index_description}\n");
252254
index_uids.push(name.to_string());
253-
let facet_distributions = format_facet_distributions(index, &rtxn, 10).unwrap(); // TODO do not unwrap
255+
let facet_distributions = format_facet_distributions(
256+
index_scheduler,
257+
index,
258+
&rtxn,
259+
10,
260+
search_rules,
261+
name,
262+
progress,
263+
)
264+
.unwrap(); // TODO do not unwrap
254265
let _ = writeln!(&mut filter_description, "\n## Facet distributions of the {name} index");
255266
let _ = writeln!(&mut filter_description, "{facet_distributions}");
256267

@@ -956,11 +967,27 @@ struct SearchInIndexParameters {
956967
}
957968

958969
fn format_facet_distributions(
970+
index_scheduler: &IndexScheduler,
959971
index: &Index,
960972
rtxn: &RoTxn,
961973
max_values_per_facet: usize,
962-
) -> meilisearch_types::milli::Result<String> {
963-
let universe = index.documents_ids(rtxn)?;
974+
search_rules: Option<IndexSearchRules>,
975+
index_uid: &str,
976+
progress: &Progress,
977+
) -> index_scheduler::Result<String> {
978+
let from_milli = |err| index_scheduler::Error::from_milli(err, Some(index_uid.to_string()));
979+
let universe = 'filter: {
980+
let Some(search_rules) = search_rules else { break 'filter index.documents_ids(rtxn)? };
981+
let Some(filter) = search_rules.filter else {
982+
break 'filter index.documents_ids(rtxn)?;
983+
};
984+
let Some(filter) = Filter::from_json(&filter).map_err(from_milli)? else {
985+
break 'filter index.documents_ids(rtxn)?;
986+
};
987+
let filter =
988+
filter_into_index_filter(filter, index, rtxn, index_scheduler, progress, index_uid)?;
989+
filter.evaluate(rtxn, index).map_err(from_milli)?
990+
};
964991
let rules = index.filterable_attributes_rules(rtxn)?;
965992
let fields_ids_map = index.fields_ids_map(rtxn)?;
966993
let filterable_attributes = fields_ids_map
@@ -972,7 +999,8 @@ fn format_facet_distributions(
972999
.max_values_per_facet(max_values_per_facet)
9731000
.candidates(universe)
9741001
.facets(filterable_attributes)
975-
.execute()?;
1002+
.execute()
1003+
.map_err(from_milli)?;
9761004

9771005
let mut output = String::new();
9781006
for (facet_name, entries) in facets_distribution {

crates/meilisearch/src/routes/indexes/similar.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,16 +207,19 @@ async fn similar(
207207
mut query: SimilarQuery,
208208
) -> Result<SimilarResult, ResponseError> {
209209
let progress = Progress::default();
210+
211+
let search_rules = index_scheduler.filters().get_index_search_rules(&index_uid);
212+
210213
// Tenant token search_rules.
211-
if let Some(search_rules) = index_scheduler.filters().get_index_search_rules(&index_uid) {
214+
if let Some(search_rules) = search_rules.clone() {
212215
add_search_rules(&mut query.filter, search_rules);
213216
}
214217

215218
let progress_clone = progress.clone();
216219
let result = tokio::task::spawn_blocking(move || {
217220
let _step = progress_clone.update_progress_scoped(TotalProcessingTimeStep::Search);
218221

219-
perform_similar(&index_scheduler, index_uid, query, &progress_clone)
222+
perform_similar(&index_scheduler, index_uid, query, &progress_clone, search_rules)
220223
})
221224
.await;
222225

crates/meilisearch/src/search/mod.rs

Lines changed: 69 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ use core::fmt;
22
use std::cmp::min;
33
use std::collections::{BTreeMap, BTreeSet, HashSet};
44
use std::ops::Not as _;
5+
use std::rc::Rc;
56
use std::str::FromStr;
67
use std::sync::Arc;
78
use std::time::Instant;
89

910
use deserr::Deserr;
10-
use index_scheduler::filter::{filter_into_index_filter, parse_filter};
11+
use index_scheduler::filter::{
12+
filter_into_index_filter, filters_into_index_filters, parse_filter,
13+
retrieve_foreign_keys_settings, SourceIndexUid,
14+
};
1115
use index_scheduler::{IndexScheduler, RoFeatures};
1216
use indexmap::IndexMap;
1317
use meilisearch_auth::IndexSearchRules;
@@ -23,8 +27,8 @@ use meilisearch_types::milli::score_details::{ScoreDetails, ScoringStrategy};
2327
use meilisearch_types::milli::vector::parsed_vectors::ExplicitVectors;
2428
use meilisearch_types::milli::vector::Embedder;
2529
use meilisearch_types::milli::{
26-
AttributeState, Deadline, FacetValueHit, IndexFilter, InternalError, OrderBy, PatternMatch,
27-
SearchForFacetValues, SearchStep,
30+
filtered_universe, AttributeState, Deadline, FacetValueHit, Filter, IndexFilter, InternalError,
31+
OrderBy, PatternMatch, SearchForFacetValues, SearchStep,
2832
};
2933
use meilisearch_types::network::Network;
3034
use meilisearch_types::settings::DEFAULT_PAGINATION_MAX_TOTAL_HITS;
@@ -2481,6 +2485,7 @@ pub fn perform_similar(
24812485
index_uid: IndexUid,
24822486
query: SimilarQuery,
24832487
progress: &Progress,
2488+
search_rules: Option<IndexSearchRules>,
24842489
) -> Result<SimilarResult, ResponseError> {
24852490
let before_search = Instant::now();
24862491
let features = index_scheduler.features();
@@ -2512,6 +2517,30 @@ pub fn perform_similar(
25122517
Route::Similar,
25132518
)?;
25142519

2520+
let docid_filter = search_rules.and_then(|search_rules| search_rules.filter);
2521+
let docid_filter = docid_filter
2522+
.as_ref()
2523+
.map(|docid_filter| {
2524+
parse_filter(
2525+
docid_filter,
2526+
Code::InvalidSimilarFilter,
2527+
features,
2528+
Some(index_uid.as_str()),
2529+
)
2530+
})
2531+
.transpose()?
2532+
.flatten();
2533+
2534+
let candidates_filter = filter
2535+
.as_ref()
2536+
.and_then(|filter| {
2537+
parse_filter(filter, Code::InvalidSimilarFilter, features, None).transpose()
2538+
})
2539+
.transpose()?;
2540+
2541+
let (docid_filter, candidates_filter) =
2542+
extract_filters(index_scheduler, index_uid, progress, docid_filter, candidates_filter)?;
2543+
25152544
let id: ExternalDocumentId = id.try_into().map_err(|error| {
25162545
let msg = format!("Invalid value at `.id`: {error}");
25172546
ResponseError::from_msg(msg, Code::InvalidSimilarId)
@@ -2526,6 +2555,14 @@ pub fn perform_similar(
25262555
));
25272556
};
25282557

2558+
let docid_universe = filtered_universe(&index, &rtxn, &docid_filter, progress)?;
2559+
if docid_universe.contains(internal_id).not() {
2560+
return Err(ResponseError::from_msg(
2561+
MeilisearchHttpError::DocumentNotFound(id.into_inner()).to_string(),
2562+
Code::NotFoundSimilarId,
2563+
));
2564+
}
2565+
25292566
let mut similar = milli::Similar::new(
25302567
internal_id,
25312568
offset,
@@ -2538,18 +2575,8 @@ pub fn perform_similar(
25382575
progress,
25392576
);
25402577

2541-
if let Some(ref filter) = filter {
2542-
if let Some(filter) = parse_filter(filter, Code::InvalidSimilarFilter, features, None)? {
2543-
let filter = filter_into_index_filter(
2544-
filter,
2545-
&index,
2546-
&rtxn,
2547-
index_scheduler,
2548-
progress,
2549-
&index_uid,
2550-
)?;
2551-
similar.filter(filter);
2552-
}
2578+
if let Some(filter) = candidates_filter {
2579+
similar.filter(filter);
25532580
}
25542581

25552582
if let Some(ranking_score_threshold) = ranking_score_threshold {
@@ -2618,6 +2645,33 @@ pub fn perform_similar(
26182645
Ok(result)
26192646
}
26202647

2648+
fn extract_filters<'a>(
2649+
index_scheduler: &IndexScheduler,
2650+
index_uid: IndexUid,
2651+
progress: &Progress,
2652+
docid_filter: Option<Filter<'a>>,
2653+
candidates_filter: Option<Filter<'a>>,
2654+
) -> Result<(Option<IndexFilter<'a>>, Option<IndexFilter<'a>>), ResponseError> {
2655+
let source_index_uid = SourceIndexUid(Rc::from(&*index_uid));
2656+
let foreign_keys_settings =
2657+
retrieve_foreign_keys_settings(index_scheduler, std::iter::once(&source_index_uid))?;
2658+
let (docid_filter, candidates_filter) = match filters_into_index_filters(
2659+
vec![
2660+
(source_index_uid.clone(), docid_filter),
2661+
(source_index_uid.clone(), candidates_filter),
2662+
],
2663+
&foreign_keys_settings,
2664+
index_scheduler,
2665+
progress,
2666+
)?
2667+
.as_mut_slice()
2668+
{
2669+
[docid_filter, candidates_filter] => (docid_filter.take(), candidates_filter.take()),
2670+
_ => unreachable!(),
2671+
};
2672+
Ok((docid_filter, candidates_filter))
2673+
}
2674+
26212675
pub fn insert_geo_distance(sorts: &[String], document: &mut Document) {
26222676
lazy_static::lazy_static! {
26232677
static ref GEO_REGEX: Regex =

0 commit comments

Comments
 (0)