Compare commits

...

8 Commits

17 changed files with 993 additions and 89 deletions

View File

@ -224,6 +224,7 @@ InvalidIndexLimit , InvalidRequest , BAD_REQUEST ;
InvalidIndexOffset , InvalidRequest , BAD_REQUEST ;
InvalidIndexPrimaryKey , InvalidRequest , BAD_REQUEST ;
InvalidIndexUid , InvalidRequest , BAD_REQUEST ;
InvalidRestrictSearchableAttributes , InvalidRequest , BAD_REQUEST ;
InvalidSearchAttributesToCrop , InvalidRequest , BAD_REQUEST ;
InvalidSearchAttributesToHighlight , InvalidRequest , BAD_REQUEST ;
InvalidSearchAttributesToRetrieve , InvalidRequest , BAD_REQUEST ;

View File

@ -66,6 +66,8 @@ pub struct SearchQueryGet {
crop_marker: String,
#[deserr(default, error = DeserrQueryParamError<InvalidSearchMatchingStrategy>)]
matching_strategy: MatchingStrategy,
#[deserr(default, error = DeserrQueryParamError<InvalidRestrictSearchableAttributes>)]
pub restrict_searchable_attributes: Option<CS<String>>,
}
impl From<SearchQueryGet> for SearchQuery {
@ -96,6 +98,9 @@ impl From<SearchQueryGet> for SearchQuery {
highlight_post_tag: other.highlight_post_tag,
crop_marker: other.crop_marker,
matching_strategy: other.matching_strategy,
restrict_searchable_attributes: other
.restrict_searchable_attributes
.map(|o| o.into_iter().collect()),
}
}
}

View File

@ -68,6 +68,8 @@ pub struct SearchQuery {
pub crop_marker: String,
#[deserr(default, error = DeserrJsonError<InvalidSearchMatchingStrategy>, default)]
pub matching_strategy: MatchingStrategy,
#[deserr(default, error = DeserrJsonError<InvalidRestrictSearchableAttributes>, default)]
pub restrict_searchable_attributes: Option<Vec<String>>,
}
impl SearchQuery {
@ -119,6 +121,8 @@ pub struct SearchQueryWithIndex {
pub crop_marker: String,
#[deserr(default, error = DeserrJsonError<InvalidSearchMatchingStrategy>, default)]
pub matching_strategy: MatchingStrategy,
#[deserr(default, error = DeserrJsonError<InvalidRestrictSearchableAttributes>, default)]
pub restrict_searchable_attributes: Option<Vec<String>>,
}
impl SearchQueryWithIndex {
@ -142,6 +146,7 @@ impl SearchQueryWithIndex {
highlight_post_tag,
crop_marker,
matching_strategy,
restrict_searchable_attributes,
} = self;
(
index_uid,
@ -163,6 +168,7 @@ impl SearchQueryWithIndex {
highlight_post_tag,
crop_marker,
matching_strategy,
restrict_searchable_attributes,
// do not use ..Default::default() here,
// rather add any missing field from `SearchQuery` to `SearchQueryWithIndex`
},
@ -274,6 +280,10 @@ pub fn perform_search(
search.query(query);
}
if let Some(ref searchable) = query.restrict_searchable_attributes {
search.searchable_attributes(searchable);
}
let is_finite_pagination = query.is_finite_pagination();
search.terms_matching_strategy(query.matching_strategy.into());

View File

@ -5,6 +5,7 @@ mod errors;
mod formatted;
mod multi;
mod pagination;
mod restrict_searchable;
use once_cell::sync::Lazy;
use serde_json::{json, Value};

View File

@ -0,0 +1,263 @@
use once_cell::sync::Lazy;
use serde_json::{json, Value};
use crate::common::index::Index;
use crate::common::Server;
async fn index_with_documents<'a>(server: &'a Server, documents: &Value) -> Index<'a> {
let index = server.index("test");
index.add_documents(documents.clone(), None).await;
index.wait_task(0).await;
index
}
static SIMPLE_SEARCH_DOCUMENTS: Lazy<Value> = Lazy::new(|| {
json!([
{
"title": "Shazam!",
"desc": "a Captain Marvel ersatz",
"id": "1",
},
{
"title": "Captain Planet",
"desc": "He's not part of the Marvel Cinematic Universe",
"id": "2",
},
{
"title": "Captain Marvel",
"desc": "a Shazam ersatz",
"id": "3",
}])
});
#[actix_rt::test]
async fn simple_search_on_title() {
let server = Server::new().await;
let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await;
// simple search should return 2 documents (ids: 2 and 3).
index
.search(
json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["title"]}),
|response, code| {
assert_eq!(code, 200, "{}", response);
assert_eq!(response["hits"].as_array().unwrap().len(), 2);
},
)
.await;
}
#[actix_rt::test]
async fn simple_prefix_search_on_title() {
let server = Server::new().await;
let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await;
// simple search should return 2 documents (ids: 2 and 3).
index
.search(
json!({"q": "Captain Mar", "restrictSearchableAttributes": ["title"]}),
|response, code| {
assert_eq!(code, 200, "{}", response);
assert_eq!(response["hits"].as_array().unwrap().len(), 2);
},
)
.await;
}
#[actix_rt::test]
async fn simple_search_on_title_matching_strategy_all() {
let server = Server::new().await;
let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await;
// simple search matching strategy all should only return 1 document (ids: 2).
index
.search(json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["title"], "matchingStrategy": "all"}), |response, code| {
assert_eq!(code, 200, "{}", response);
assert_eq!(response["hits"].as_array().unwrap().len(), 1);
})
.await;
}
#[actix_rt::test]
async fn simple_search_on_unknown_field() {
let server = Server::new().await;
let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await;
// simple search on unknown field shouldn't return any document.
index
.search(
json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["unknown"]}),
|response, code| {
assert_eq!(code, 200, "{}", response);
assert_eq!(response["hits"].as_array().unwrap().len(), 0);
},
)
.await;
}
#[actix_rt::test]
async fn simple_search_on_no_field() {
let server = Server::new().await;
let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await;
// simple search on no field shouldn't return any document.
index
.search(
json!({"q": "Captain Marvel", "restrictSearchableAttributes": []}),
|response, code| {
assert_eq!(code, 200, "{}", response);
assert_eq!(response["hits"].as_array().unwrap().len(), 0);
},
)
.await;
}
#[actix_rt::test]
async fn word_ranking_rule_order() {
let server = Server::new().await;
let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await;
// Document 3 should appear before document 2.
index
.search(
json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["title"], "attributesToRetrieve": ["id"]}),
|response, code| {
assert_eq!(code, 200, "{}", response);
assert_eq!(
response["hits"],
json!([
{"id": "3"},
{"id": "2"},
])
);
},
)
.await;
}
#[actix_rt::test]
async fn word_ranking_rule_order_exact_words() {
let server = Server::new().await;
let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await;
index.update_settings_typo_tolerance(json!({"disableOnWords": ["Captain", "Marvel"]})).await;
index.wait_task(1).await;
// simple search should return 2 documents (ids: 2 and 3).
index
.search(
json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["title"], "attributesToRetrieve": ["id"]}),
|response, code| {
assert_eq!(code, 200, "{}", response);
assert_eq!(
response["hits"],
json!([
{"id": "3"},
{"id": "2"},
])
);
},
)
.await;
}
#[actix_rt::test]
async fn typo_ranking_rule_order() {
let server = Server::new().await;
let index = index_with_documents(
&server,
&json!([
{
"title": "Capitain Marivel",
"desc": "Captain Marvel",
"id": "1",
},
{
"title": "Captain Marivel",
"desc": "a Shazam ersatz",
"id": "2",
}]),
)
.await;
// Document 2 should appear before document 1.
index
.search(json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["title"], "attributesToRetrieve": ["id"]}), |response, code| {
assert_eq!(code, 200, "{}", response);
assert_eq!(
response["hits"],
json!([
{"id": "2"},
{"id": "1"},
])
);
})
.await;
}
#[actix_rt::test]
async fn attributes_ranking_rule_order() {
let server = Server::new().await;
let index = index_with_documents(
&server,
&json!([
{
"title": "Captain Marvel",
"desc": "a Shazam ersatz",
"footer": "The story of Captain Marvel",
"id": "1",
},
{
"title": "The Avengers",
"desc": "Captain Marvel is far from the earth",
"footer": "A super hero team",
"id": "2",
}]),
)
.await;
// Document 2 should appear before document 1.
index
.search(json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["desc", "footer"], "attributesToRetrieve": ["id"]}), |response, code| {
assert_eq!(code, 200, "{}", response);
assert_eq!(
response["hits"],
json!([
{"id": "2"},
{"id": "1"},
])
);
})
.await;
}
#[actix_rt::test]
async fn exactness_ranking_rule_order() {
let server = Server::new().await;
let index = index_with_documents(
&server,
&json!([
{
"title": "Captain Marvel",
"desc": "Captain Marivel",
"id": "1",
},
{
"title": "Captain Marvel",
"desc": "CaptainMarvel",
"id": "2",
}]),
)
.await;
// Document 2 should appear before document 1.
index
.search(json!({"q": "Captain Marvel", "attributesToRetrieve": ["id"], "restrictSearchableAttributes": ["desc"]}), |response, code| {
assert_eq!(code, 200, "{}", response);
assert_eq!(
response["hits"],
json!([
{"id": "2"},
{"id": "1"},
])
);
})
.await;
}

View File

@ -23,3 +23,9 @@ pub use self::roaring_bitmap_length::{
pub use self::script_language_codec::ScriptLanguageCodec;
pub use self::str_beu32_codec::{StrBEU16Codec, StrBEU32Codec};
pub use self::str_str_u8_codec::{U8StrStrCodec, UncheckedU8StrStrCodec};
pub trait BytesDecodeOwned {
type DItem;
fn bytes_decode_owned(bytes: &[u8]) -> Option<Self::DItem>;
}

View File

@ -2,8 +2,11 @@ use std::borrow::Cow;
use std::convert::TryInto;
use std::mem::size_of;
use heed::BytesDecode;
use roaring::RoaringBitmap;
use crate::heed_codec::BytesDecodeOwned;
pub struct BoRoaringBitmapCodec;
impl BoRoaringBitmapCodec {
@ -13,7 +16,7 @@ impl BoRoaringBitmapCodec {
}
}
impl heed::BytesDecode<'_> for BoRoaringBitmapCodec {
impl BytesDecode<'_> for BoRoaringBitmapCodec {
type DItem = RoaringBitmap;
fn bytes_decode(bytes: &[u8]) -> Option<Self::DItem> {
@ -28,6 +31,14 @@ impl heed::BytesDecode<'_> for BoRoaringBitmapCodec {
}
}
impl BytesDecodeOwned for BoRoaringBitmapCodec {
type DItem = RoaringBitmap;
fn bytes_decode_owned(bytes: &[u8]) -> Option<Self::DItem> {
Self::bytes_decode(bytes)
}
}
impl heed::BytesEncode<'_> for BoRoaringBitmapCodec {
type EItem = RoaringBitmap;

View File

@ -5,6 +5,8 @@ use std::mem::size_of;
use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
use roaring::RoaringBitmap;
use crate::heed_codec::BytesDecodeOwned;
/// This is the limit where using a byteorder became less size efficient
/// than using a direct roaring encoding, it is also the point where we are able
/// to determine the encoding used only by using the array of bytes length.
@ -103,6 +105,14 @@ impl heed::BytesDecode<'_> for CboRoaringBitmapCodec {
}
}
impl BytesDecodeOwned for CboRoaringBitmapCodec {
type DItem = RoaringBitmap;
fn bytes_decode_owned(bytes: &[u8]) -> Option<Self::DItem> {
Self::deserialize_from(bytes).ok()
}
}
impl heed::BytesEncode<'_> for CboRoaringBitmapCodec {
type EItem = RoaringBitmap;

View File

@ -2,6 +2,8 @@ use std::borrow::Cow;
use roaring::RoaringBitmap;
use crate::heed_codec::BytesDecodeOwned;
pub struct RoaringBitmapCodec;
impl heed::BytesDecode<'_> for RoaringBitmapCodec {
@ -12,6 +14,14 @@ impl heed::BytesDecode<'_> for RoaringBitmapCodec {
}
}
impl BytesDecodeOwned for RoaringBitmapCodec {
type DItem = RoaringBitmap;
fn bytes_decode_owned(bytes: &[u8]) -> Option<Self::DItem> {
RoaringBitmap::deserialize_from(bytes).ok()
}
}
impl heed::BytesEncode<'_> for RoaringBitmapCodec {
type EItem = RoaringBitmap;

View File

@ -1,11 +1,23 @@
use std::mem;
use heed::BytesDecode;
use crate::heed_codec::BytesDecodeOwned;
pub struct BoRoaringBitmapLenCodec;
impl heed::BytesDecode<'_> for BoRoaringBitmapLenCodec {
impl BytesDecode<'_> for BoRoaringBitmapLenCodec {
type DItem = u64;
fn bytes_decode(bytes: &[u8]) -> Option<Self::DItem> {
Some((bytes.len() / mem::size_of::<u32>()) as u64)
}
}
impl BytesDecodeOwned for BoRoaringBitmapLenCodec {
type DItem = u64;
fn bytes_decode_owned(bytes: &[u8]) -> Option<Self::DItem> {
Self::bytes_decode(bytes)
}
}

View File

@ -1,11 +1,14 @@
use std::mem;
use heed::BytesDecode;
use super::{BoRoaringBitmapLenCodec, RoaringBitmapLenCodec};
use crate::heed_codec::roaring_bitmap::cbo_roaring_bitmap_codec::THRESHOLD;
use crate::heed_codec::BytesDecodeOwned;
pub struct CboRoaringBitmapLenCodec;
impl heed::BytesDecode<'_> for CboRoaringBitmapLenCodec {
impl BytesDecode<'_> for CboRoaringBitmapLenCodec {
type DItem = u64;
fn bytes_decode(bytes: &[u8]) -> Option<Self::DItem> {
@ -20,3 +23,11 @@ impl heed::BytesDecode<'_> for CboRoaringBitmapLenCodec {
}
}
}
impl BytesDecodeOwned for CboRoaringBitmapLenCodec {
type DItem = u64;
fn bytes_decode_owned(bytes: &[u8]) -> Option<Self::DItem> {
Self::bytes_decode(bytes)
}
}

View File

@ -3,6 +3,8 @@ use std::mem;
use byteorder::{LittleEndian, ReadBytesExt};
use crate::heed_codec::BytesDecodeOwned;
const SERIAL_COOKIE_NO_RUNCONTAINER: u32 = 12346;
const SERIAL_COOKIE: u16 = 12347;
@ -59,6 +61,14 @@ impl heed::BytesDecode<'_> for RoaringBitmapLenCodec {
}
}
impl BytesDecodeOwned for RoaringBitmapLenCodec {
type DItem = u64;
fn bytes_decode_owned(bytes: &[u8]) -> Option<Self::DItem> {
RoaringBitmapLenCodec::deserialize_from_slice(bytes).ok()
}
}
#[cfg(test)]
mod tests {
use heed::BytesEncode;

View File

@ -27,6 +27,7 @@ pub struct Search<'a> {
offset: usize,
limit: usize,
sort_criteria: Option<Vec<AscDesc>>,
searchable_attributes: Option<&'a [String]>,
geo_strategy: new::GeoSortStrategy,
terms_matching_strategy: TermsMatchingStrategy,
words_limit: usize,
@ -43,6 +44,7 @@ impl<'a> Search<'a> {
offset: 0,
limit: 20,
sort_criteria: None,
searchable_attributes: None,
geo_strategy: new::GeoSortStrategy::default(),
terms_matching_strategy: TermsMatchingStrategy::default(),
exhaustive_number_hits: false,
@ -72,6 +74,11 @@ impl<'a> Search<'a> {
self
}
pub fn searchable_attributes(&mut self, searchable: &'a [String]) -> &mut Search<'a> {
self.searchable_attributes = Some(searchable);
self
}
pub fn terms_matching_strategy(&mut self, value: TermsMatchingStrategy) -> &mut Search<'a> {
self.terms_matching_strategy = value;
self
@ -102,6 +109,11 @@ impl<'a> Search<'a> {
pub fn execute(&self) -> Result<SearchResult> {
let mut ctx = SearchContext::new(self.index, self.rtxn);
if let Some(searchable_attributes) = self.searchable_attributes {
ctx.searchable_attributes(searchable_attributes)?;
}
let PartialSearchResult { located_query_terms, candidates, documents_ids } =
execute_search(
&mut ctx,
@ -136,6 +148,7 @@ impl fmt::Debug for Search<'_> {
offset,
limit,
sort_criteria,
searchable_attributes,
geo_strategy: _,
terms_matching_strategy,
words_limit,
@ -149,6 +162,7 @@ impl fmt::Debug for Search<'_> {
.field("offset", offset)
.field("limit", limit)
.field("sort_criteria", sort_criteria)
.field("searchable_attributes", searchable_attributes)
.field("terms_matching_strategy", terms_matching_strategy)
.field("exhaustive_number_hits", exhaustive_number_hits)
.field("words_limit", words_limit)

View File

@ -4,12 +4,13 @@ use std::hash::Hash;
use fxhash::FxHashMap;
use heed::types::ByteSlice;
use heed::{BytesDecode, BytesEncode, Database, RoTxn};
use heed::{BytesEncode, Database, RoTxn};
use roaring::RoaringBitmap;
use super::interner::Interned;
use super::Word;
use crate::heed_codec::StrBEU16Codec;
use crate::heed_codec::{BytesDecodeOwned, StrBEU16Codec};
use crate::update::{merge_cbo_roaring_bitmaps, MergeFn};
use crate::{
CboRoaringBitmapCodec, CboRoaringBitmapLenCodec, Result, RoaringBitmapCodec, SearchContext,
};
@ -22,50 +23,110 @@ use crate::{
#[derive(Default)]
pub struct DatabaseCache<'ctx> {
pub word_pair_proximity_docids:
FxHashMap<(u8, Interned<String>, Interned<String>), Option<&'ctx [u8]>>,
FxHashMap<(u8, Interned<String>, Interned<String>), Option<Cow<'ctx, [u8]>>>,
pub word_prefix_pair_proximity_docids:
FxHashMap<(u8, Interned<String>, Interned<String>), Option<&'ctx [u8]>>,
FxHashMap<(u8, Interned<String>, Interned<String>), Option<Cow<'ctx, [u8]>>>,
pub prefix_word_pair_proximity_docids:
FxHashMap<(u8, Interned<String>, Interned<String>), Option<&'ctx [u8]>>,
pub word_docids: FxHashMap<Interned<String>, Option<&'ctx [u8]>>,
pub exact_word_docids: FxHashMap<Interned<String>, Option<&'ctx [u8]>>,
pub word_prefix_docids: FxHashMap<Interned<String>, Option<&'ctx [u8]>>,
pub exact_word_prefix_docids: FxHashMap<Interned<String>, Option<&'ctx [u8]>>,
FxHashMap<(u8, Interned<String>, Interned<String>), Option<Cow<'ctx, [u8]>>>,
pub word_docids: FxHashMap<Interned<String>, Option<Cow<'ctx, [u8]>>>,
pub exact_word_docids: FxHashMap<Interned<String>, Option<Cow<'ctx, [u8]>>>,
pub word_prefix_docids: FxHashMap<Interned<String>, Option<Cow<'ctx, [u8]>>>,
pub exact_word_prefix_docids: FxHashMap<Interned<String>, Option<Cow<'ctx, [u8]>>>,
pub words_fst: Option<fst::Set<Cow<'ctx, [u8]>>>,
pub word_position_docids: FxHashMap<(Interned<String>, u16), Option<&'ctx [u8]>>,
pub word_prefix_position_docids: FxHashMap<(Interned<String>, u16), Option<&'ctx [u8]>>,
pub word_position_docids: FxHashMap<(Interned<String>, u16), Option<Cow<'ctx, [u8]>>>,
pub word_prefix_position_docids: FxHashMap<(Interned<String>, u16), Option<Cow<'ctx, [u8]>>>,
pub word_positions: FxHashMap<Interned<String>, Vec<u16>>,
pub word_prefix_positions: FxHashMap<Interned<String>, Vec<u16>>,
pub word_fid_docids: FxHashMap<(Interned<String>, u16), Option<&'ctx [u8]>>,
pub word_prefix_fid_docids: FxHashMap<(Interned<String>, u16), Option<&'ctx [u8]>>,
pub word_fid_docids: FxHashMap<(Interned<String>, u16), Option<Cow<'ctx, [u8]>>>,
pub word_prefix_fid_docids: FxHashMap<(Interned<String>, u16), Option<Cow<'ctx, [u8]>>>,
pub word_fids: FxHashMap<Interned<String>, Vec<u16>>,
pub word_prefix_fids: FxHashMap<Interned<String>, Vec<u16>>,
}
impl<'ctx> DatabaseCache<'ctx> {
fn get_value<'v, K1, KC>(
fn get_value<'v, K1, KC, DC>(
txn: &'ctx RoTxn,
cache_key: K1,
db_key: &'v KC::EItem,
cache: &mut FxHashMap<K1, Option<&'ctx [u8]>>,
cache: &mut FxHashMap<K1, Option<Cow<'ctx, [u8]>>>,
db: Database<KC, ByteSlice>,
) -> Result<Option<&'ctx [u8]>>
) -> Result<Option<DC::DItem>>
where
K1: Copy + Eq + Hash,
KC: BytesEncode<'v>,
DC: BytesDecodeOwned,
{
let bitmap_ptr = match cache.entry(cache_key) {
Entry::Occupied(bitmap_ptr) => *bitmap_ptr.get(),
match cache.entry(cache_key) {
Entry::Occupied(_) => {}
Entry::Vacant(entry) => {
let bitmap_ptr = db.get(txn, db_key)?;
let bitmap_ptr = db.get(txn, db_key)?.map(Cow::Borrowed);
entry.insert(bitmap_ptr);
}
}
match cache.get(&cache_key).unwrap() {
Some(Cow::Borrowed(bytes)) => {
DC::bytes_decode_owned(bytes).ok_or(heed::Error::Decoding.into()).map(Some)
}
Some(Cow::Owned(bytes)) => {
DC::bytes_decode_owned(bytes).ok_or(heed::Error::Decoding.into()).map(Some)
}
None => Ok(None),
}
}
fn get_value_from_keys<'v, K1, KC, DC>(
txn: &'ctx RoTxn,
cache_key: K1,
db_keys: &'v [KC::EItem],
cache: &mut FxHashMap<K1, Option<Cow<'ctx, [u8]>>>,
db: Database<KC, ByteSlice>,
merger: MergeFn,
) -> Result<Option<DC::DItem>>
where
K1: Copy + Eq + Hash,
KC: BytesEncode<'v>,
DC: BytesDecodeOwned,
KC::EItem: Sized,
{
match cache.entry(cache_key) {
Entry::Occupied(_) => {}
Entry::Vacant(entry) => {
let bitmap_ptr: Option<Cow<'ctx, [u8]>> = match db_keys {
[] => None,
[key] => db.get(txn, key)?.map(Cow::Borrowed),
keys => {
let bitmaps = keys
.iter()
.filter_map(|key| db.get(txn, key).transpose())
.map(|v| v.map(Cow::Borrowed))
.collect::<std::result::Result<Vec<Cow<[u8]>>, _>>()?;
if bitmaps.is_empty() {
None
} else {
Some(merger(&[], &bitmaps[..])?)
}
}
};
entry.insert(bitmap_ptr);
bitmap_ptr
}
};
Ok(bitmap_ptr)
match cache.get(&cache_key).unwrap() {
Some(Cow::Borrowed(bytes)) => {
DC::bytes_decode_owned(bytes).ok_or(heed::Error::Decoding.into()).map(Some)
}
Some(Cow::Owned(bytes)) => {
DC::bytes_decode_owned(bytes).ok_or(heed::Error::Decoding.into()).map(Some)
}
None => Ok(None),
}
}
}
impl<'ctx> SearchContext<'ctx> {
pub fn get_words_fst(&mut self) -> Result<fst::Set<Cow<'ctx, [u8]>>> {
if let Some(fst) = self.db_cache.words_fst.clone() {
@ -99,30 +160,41 @@ impl<'ctx> SearchContext<'ctx> {
/// Retrieve or insert the given value in the `word_docids` database.
fn get_db_word_docids(&mut self, word: Interned<String>) -> Result<Option<RoaringBitmap>> {
DatabaseCache::get_value(
self.txn,
word,
self.word_interner.get(word).as_str(),
&mut self.db_cache.word_docids,
self.index.word_docids.remap_data_type::<ByteSlice>(),
)?
.map(|bytes| RoaringBitmapCodec::bytes_decode(bytes).ok_or(heed::Error::Decoding.into()))
.transpose()
match &self.restricted_fids {
Some(restricted_fids) => {
let interned = self.word_interner.get(word).as_str();
let keys: Vec<_> = restricted_fids.iter().map(|fid| (interned, *fid)).collect();
DatabaseCache::get_value_from_keys::<_, _, CboRoaringBitmapCodec>(
self.txn,
word,
&keys[..],
&mut self.db_cache.word_docids,
self.index.word_fid_docids.remap_data_type::<ByteSlice>(),
merge_cbo_roaring_bitmaps,
)
}
None => DatabaseCache::get_value::<_, _, RoaringBitmapCodec>(
self.txn,
word,
self.word_interner.get(word).as_str(),
&mut self.db_cache.word_docids,
self.index.word_docids.remap_data_type::<ByteSlice>(),
),
}
}
fn get_db_exact_word_docids(
&mut self,
word: Interned<String>,
) -> Result<Option<RoaringBitmap>> {
DatabaseCache::get_value(
DatabaseCache::get_value::<_, _, RoaringBitmapCodec>(
self.txn,
word,
self.word_interner.get(word).as_str(),
&mut self.db_cache.exact_word_docids,
self.index.exact_word_docids.remap_data_type::<ByteSlice>(),
)?
.map(|bytes| RoaringBitmapCodec::bytes_decode(bytes).ok_or(heed::Error::Decoding.into()))
.transpose()
)
}
pub fn word_prefix_docids(&mut self, prefix: Word) -> Result<Option<RoaringBitmap>> {
@ -150,30 +222,41 @@ impl<'ctx> SearchContext<'ctx> {
&mut self,
prefix: Interned<String>,
) -> Result<Option<RoaringBitmap>> {
DatabaseCache::get_value(
self.txn,
prefix,
self.word_interner.get(prefix).as_str(),
&mut self.db_cache.word_prefix_docids,
self.index.word_prefix_docids.remap_data_type::<ByteSlice>(),
)?
.map(|bytes| RoaringBitmapCodec::bytes_decode(bytes).ok_or(heed::Error::Decoding.into()))
.transpose()
match &self.restricted_fids {
Some(restricted_fids) => {
let interned = self.word_interner.get(prefix).as_str();
let keys: Vec<_> = restricted_fids.iter().map(|fid| (interned, *fid)).collect();
DatabaseCache::get_value_from_keys::<_, _, CboRoaringBitmapCodec>(
self.txn,
prefix,
&keys[..],
&mut self.db_cache.word_prefix_docids,
self.index.word_prefix_fid_docids.remap_data_type::<ByteSlice>(),
merge_cbo_roaring_bitmaps,
)
}
None => DatabaseCache::get_value::<_, _, RoaringBitmapCodec>(
self.txn,
prefix,
self.word_interner.get(prefix).as_str(),
&mut self.db_cache.word_prefix_docids,
self.index.word_prefix_docids.remap_data_type::<ByteSlice>(),
),
}
}
fn get_db_exact_word_prefix_docids(
&mut self,
prefix: Interned<String>,
) -> Result<Option<RoaringBitmap>> {
DatabaseCache::get_value(
DatabaseCache::get_value::<_, _, RoaringBitmapCodec>(
self.txn,
prefix,
self.word_interner.get(prefix).as_str(),
&mut self.db_cache.exact_word_prefix_docids,
self.index.exact_word_prefix_docids.remap_data_type::<ByteSlice>(),
)?
.map(|bytes| RoaringBitmapCodec::bytes_decode(bytes).ok_or(heed::Error::Decoding.into()))
.transpose()
)
}
pub fn get_db_word_pair_proximity_docids(
@ -182,7 +265,7 @@ impl<'ctx> SearchContext<'ctx> {
word2: Interned<String>,
proximity: u8,
) -> Result<Option<RoaringBitmap>> {
DatabaseCache::get_value(
DatabaseCache::get_value::<_, _, CboRoaringBitmapCodec>(
self.txn,
(proximity, word1, word2),
&(
@ -192,9 +275,7 @@ impl<'ctx> SearchContext<'ctx> {
),
&mut self.db_cache.word_pair_proximity_docids,
self.index.word_pair_proximity_docids.remap_data_type::<ByteSlice>(),
)?
.map(|bytes| CboRoaringBitmapCodec::bytes_decode(bytes).ok_or(heed::Error::Decoding.into()))
.transpose()
)
}
pub fn get_db_word_pair_proximity_docids_len(
@ -203,7 +284,7 @@ impl<'ctx> SearchContext<'ctx> {
word2: Interned<String>,
proximity: u8,
) -> Result<Option<u64>> {
DatabaseCache::get_value(
DatabaseCache::get_value::<_, _, CboRoaringBitmapLenCodec>(
self.txn,
(proximity, word1, word2),
&(
@ -213,11 +294,7 @@ impl<'ctx> SearchContext<'ctx> {
),
&mut self.db_cache.word_pair_proximity_docids,
self.index.word_pair_proximity_docids.remap_data_type::<ByteSlice>(),
)?
.map(|bytes| {
CboRoaringBitmapLenCodec::bytes_decode(bytes).ok_or(heed::Error::Decoding.into())
})
.transpose()
)
}
pub fn get_db_word_prefix_pair_proximity_docids(
@ -226,7 +303,7 @@ impl<'ctx> SearchContext<'ctx> {
prefix2: Interned<String>,
proximity: u8,
) -> Result<Option<RoaringBitmap>> {
DatabaseCache::get_value(
DatabaseCache::get_value::<_, _, CboRoaringBitmapCodec>(
self.txn,
(proximity, word1, prefix2),
&(
@ -236,9 +313,7 @@ impl<'ctx> SearchContext<'ctx> {
),
&mut self.db_cache.word_prefix_pair_proximity_docids,
self.index.word_prefix_pair_proximity_docids.remap_data_type::<ByteSlice>(),
)?
.map(|bytes| CboRoaringBitmapCodec::bytes_decode(bytes).ok_or(heed::Error::Decoding.into()))
.transpose()
)
}
pub fn get_db_prefix_word_pair_proximity_docids(
&mut self,
@ -246,7 +321,7 @@ impl<'ctx> SearchContext<'ctx> {
right: Interned<String>,
proximity: u8,
) -> Result<Option<RoaringBitmap>> {
DatabaseCache::get_value(
DatabaseCache::get_value::<_, _, CboRoaringBitmapCodec>(
self.txn,
(proximity, left_prefix, right),
&(
@ -256,9 +331,7 @@ impl<'ctx> SearchContext<'ctx> {
),
&mut self.db_cache.prefix_word_pair_proximity_docids,
self.index.prefix_word_pair_proximity_docids.remap_data_type::<ByteSlice>(),
)?
.map(|bytes| CboRoaringBitmapCodec::bytes_decode(bytes).ok_or(heed::Error::Decoding.into()))
.transpose()
)
}
pub fn get_db_word_fid_docids(
@ -266,15 +339,18 @@ impl<'ctx> SearchContext<'ctx> {
word: Interned<String>,
fid: u16,
) -> Result<Option<RoaringBitmap>> {
DatabaseCache::get_value(
// if the requested fid isn't in the restricted list, return None.
if self.restricted_fids.as_ref().map_or(false, |fids| !fids.contains(&fid)) {
return Ok(None);
}
DatabaseCache::get_value::<_, _, CboRoaringBitmapCodec>(
self.txn,
(word, fid),
&(self.word_interner.get(word).as_str(), fid),
&mut self.db_cache.word_fid_docids,
self.index.word_fid_docids.remap_data_type::<ByteSlice>(),
)?
.map(|bytes| CboRoaringBitmapCodec::bytes_decode(bytes).ok_or(heed::Error::Decoding.into()))
.transpose()
)
}
pub fn get_db_word_prefix_fid_docids(
@ -282,15 +358,18 @@ impl<'ctx> SearchContext<'ctx> {
word_prefix: Interned<String>,
fid: u16,
) -> Result<Option<RoaringBitmap>> {
DatabaseCache::get_value(
// if the requested fid isn't in the restricted list, return None.
if self.restricted_fids.as_ref().map_or(false, |fids| !fids.contains(&fid)) {
return Ok(None);
}
DatabaseCache::get_value::<_, _, CboRoaringBitmapCodec>(
self.txn,
(word_prefix, fid),
&(self.word_interner.get(word_prefix).as_str(), fid),
&mut self.db_cache.word_prefix_fid_docids,
self.index.word_prefix_fid_docids.remap_data_type::<ByteSlice>(),
)?
.map(|bytes| CboRoaringBitmapCodec::bytes_decode(bytes).ok_or(heed::Error::Decoding.into()))
.transpose()
)
}
pub fn get_db_word_fids(&mut self, word: Interned<String>) -> Result<Vec<u16>> {
@ -309,7 +388,7 @@ impl<'ctx> SearchContext<'ctx> {
for result in remap_key_type {
let ((_, fid), value) = result?;
// filling other caches to avoid searching for them again
self.db_cache.word_fid_docids.insert((word, fid), Some(value));
self.db_cache.word_fid_docids.insert((word, fid), Some(Cow::Borrowed(value)));
fids.push(fid);
}
entry.insert(fids.clone());
@ -335,7 +414,9 @@ impl<'ctx> SearchContext<'ctx> {
for result in remap_key_type {
let ((_, fid), value) = result?;
// filling other caches to avoid searching for them again
self.db_cache.word_prefix_fid_docids.insert((word_prefix, fid), Some(value));
self.db_cache
.word_prefix_fid_docids
.insert((word_prefix, fid), Some(Cow::Borrowed(value)));
fids.push(fid);
}
entry.insert(fids.clone());
@ -350,15 +431,13 @@ impl<'ctx> SearchContext<'ctx> {
word: Interned<String>,
position: u16,
) -> Result<Option<RoaringBitmap>> {
DatabaseCache::get_value(
DatabaseCache::get_value::<_, _, CboRoaringBitmapCodec>(
self.txn,
(word, position),
&(self.word_interner.get(word).as_str(), position),
&mut self.db_cache.word_position_docids,
self.index.word_position_docids.remap_data_type::<ByteSlice>(),
)?
.map(|bytes| CboRoaringBitmapCodec::bytes_decode(bytes).ok_or(heed::Error::Decoding.into()))
.transpose()
)
}
pub fn get_db_word_prefix_position_docids(
@ -366,15 +445,13 @@ impl<'ctx> SearchContext<'ctx> {
word_prefix: Interned<String>,
position: u16,
) -> Result<Option<RoaringBitmap>> {
DatabaseCache::get_value(
DatabaseCache::get_value::<_, _, CboRoaringBitmapCodec>(
self.txn,
(word_prefix, position),
&(self.word_interner.get(word_prefix).as_str(), position),
&mut self.db_cache.word_prefix_position_docids,
self.index.word_prefix_position_docids.remap_data_type::<ByteSlice>(),
)?
.map(|bytes| CboRoaringBitmapCodec::bytes_decode(bytes).ok_or(heed::Error::Decoding.into()))
.transpose()
)
}
pub fn get_db_word_positions(&mut self, word: Interned<String>) -> Result<Vec<u16>> {
@ -393,7 +470,9 @@ impl<'ctx> SearchContext<'ctx> {
for result in remap_key_type {
let ((_, position), value) = result?;
// filling other caches to avoid searching for them again
self.db_cache.word_position_docids.insert((word, position), Some(value));
self.db_cache
.word_position_docids
.insert((word, position), Some(Cow::Borrowed(value)));
positions.push(position);
}
entry.insert(positions.clone());
@ -424,7 +503,7 @@ impl<'ctx> SearchContext<'ctx> {
// filling other caches to avoid searching for them again
self.db_cache
.word_prefix_position_docids
.insert((word_prefix, position), Some(value));
.insert((word_prefix, position), Some(Cow::Borrowed(value)));
positions.push(position);
}
entry.insert(positions.clone());

View File

@ -0,0 +1,449 @@
{"run_id":"1683129457-574770000","line":622,"new":{"module_name":"milli__search__new__matches__tests","snapshot_name":"highlight_unicode-3","metadata":{"source":"milli/src/search/new/matches/mod.rs","assertion_line":622,"expression":"matcher.format(format_options)"},"snapshot":"<em>Westfália</em>"},"old":{"module_name":"milli__search__new__matches__tests","metadata":{},"snapshot":"<em>Westfáli</em>a"}}
{"run_id":"1683133106-100492000","line":738,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":839,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":573,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":640,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":600,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":802,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":746,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":648,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":609,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":811,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":582,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":755,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":657,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":820,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":764,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":666,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":773,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":675,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":684,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":782,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":693,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":702,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":711,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":720,"new":null,"old":null}
{"run_id":"1683133106-100492000","line":622,"new":{"module_name":"milli__search__new__matches__tests","snapshot_name":"highlight_unicode-3","metadata":{"source":"milli/src/search/new/matches/mod.rs","assertion_line":622,"expression":"matcher.format(format_options)"},"snapshot":"Westfáliaaaaaa"},"old":{"module_name":"milli__search__new__matches__tests","metadata":{},"snapshot":"<em>Westfáli</em>aaaaaaa"}}
{"run_id":"1683193451-2793000","line":654,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":616,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":590,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":851,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":814,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":751,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":759,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":662,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":625,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":823,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":599,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":832,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":671,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":768,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":680,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":777,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":689,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":786,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":698,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":795,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":707,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":716,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":725,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":734,"new":null,"old":null}
{"run_id":"1683193451-2793000","line":637,"new":{"module_name":"milli__search__new__matches__tests","snapshot_name":"highlight_unicode-3","metadata":{"source":"milli/src/search/new/matches/mod.rs","assertion_line":637,"expression":"matcher.format(format_options)"},"snapshot":"Westfáliaaaaaa"},"old":{"module_name":"milli__search__new__matches__tests","metadata":{},"snapshot":"<em>Westfáli</em>aaaaaaa"}}
{"run_id":"1683193542-499542000","line":851,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":751,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":616,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":814,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":590,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":654,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":759,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":662,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":625,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":823,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":599,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":832,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":768,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":671,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":777,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":680,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":786,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":689,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":698,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":795,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":707,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":716,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":725,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":734,"new":null,"old":null}
{"run_id":"1683193542-499542000","line":637,"new":{"module_name":"milli__search__new__matches__tests","snapshot_name":"highlight_unicode-3","metadata":{"source":"milli/src/search/new/matches/mod.rs","assertion_line":637,"expression":"matcher.format(format_options)"},"snapshot":"Westfáliaaaaaa"},"old":{"module_name":"milli__search__new__matches__tests","metadata":{},"snapshot":"<em>Westfáli</em>aaaaaaa"}}
{"run_id":"1683193590-661809000","line":814,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":851,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":590,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":751,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":616,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":654,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":662,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":759,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":625,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":823,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":599,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":832,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":671,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":768,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":680,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":777,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":689,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":786,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":698,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":795,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":707,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":716,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":725,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":734,"new":null,"old":null}
{"run_id":"1683193590-661809000","line":637,"new":{"module_name":"milli__search__new__matches__tests","snapshot_name":"highlight_unicode-3","metadata":{"source":"milli/src/search/new/matches/mod.rs","assertion_line":637,"expression":"matcher.format(format_options)"},"snapshot":"<em>Westfália</em>"},"old":{"module_name":"milli__search__new__matches__tests","metadata":{},"snapshot":"<em>Westfáli</em>a"}}
{"run_id":"1683196250-584747000","line":654,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":616,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":851,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":814,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":590,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":751,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":662,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":759,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":625,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":823,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":599,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":671,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":832,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":768,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":680,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":777,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":689,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":786,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":698,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":795,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":707,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":716,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":725,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":734,"new":null,"old":null}
{"run_id":"1683196250-584747000","line":637,"new":{"module_name":"milli__search__new__matches__tests","snapshot_name":"highlight_unicode-3","metadata":{"source":"milli/src/search/new/matches/mod.rs","assertion_line":637,"expression":"matcher.format(format_options)"},"snapshot":"<em>Westfália</em>"},"old":{"module_name":"milli__search__new__matches__tests","metadata":{},"snapshot":"<em>Westfáli</em>a"}}
{"run_id":"1683196569-36502000","line":851,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":751,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":654,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":590,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":814,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":759,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":662,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":823,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":599,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":768,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":832,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":671,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":777,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":680,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":786,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":689,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":795,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":698,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":707,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":716,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":725,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":734,"new":null,"old":null}
{"run_id":"1683196569-36502000","line":616,"new":{"module_name":"milli__search__new__matches__tests","snapshot_name":"highlight_unicode","metadata":{"source":"milli/src/search/new/matches/mod.rs","assertion_line":616,"expression":"matcher.format(format_options)"},"snapshot":"<em>Ŵôřlḑ</em>ôle"},"old":{"module_name":"milli__search__new__matches__tests","metadata":{},"snapshot":"<em>Ŵôřlḑôle</em>"}}
{"run_id":"1683196614-298348000","line":654,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":814,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":851,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":590,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":616,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":751,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":662,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":759,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":625,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":823,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":599,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":832,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":671,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":768,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":680,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":777,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":689,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":637,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":786,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":698,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":795,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":707,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":716,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":725,"new":null,"old":null}
{"run_id":"1683196614-298348000","line":734,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":751,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":590,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":654,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":616,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":814,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":851,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":662,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":759,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":625,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":823,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":599,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":671,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":832,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":768,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":680,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":777,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":689,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":786,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":637,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":698,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":795,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":707,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":716,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":725,"new":null,"old":null}
{"run_id":"1683196758-130465000","line":734,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":616,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":814,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":590,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":654,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":751,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":662,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":625,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":759,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":823,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":599,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":832,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":671,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":768,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":680,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":777,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":689,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":786,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":637,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":698,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":795,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":707,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":716,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":725,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":734,"new":null,"old":null}
{"run_id":"1683213265-505594000","line":850,"new":{"module_name":"milli__search__new__matches__tests","snapshot_name":"partial_matches","metadata":{"source":"milli/src/search/new/matches/mod.rs","assertion_line":850,"expression":"matcher.format(format_options)"},"snapshot":"_the_ do or die can't be he do and or isn't he"},"old":{"module_name":"milli__search__new__matches__tests","metadata":{},"snapshot":"_the_ _do_ _or_ die can't be he do and or isn'_t_ _he_"}}
{"run_id":"1683213465-911114000","line":751,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":654,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":814,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":590,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":616,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":759,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":662,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":625,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":823,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":599,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":832,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":768,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":671,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":777,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":680,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":786,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":689,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":637,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":698,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":795,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":707,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":716,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":725,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":734,"new":null,"old":null}
{"run_id":"1683213465-911114000","line":850,"new":{"module_name":"milli__search__new__matches__tests","snapshot_name":"partial_matches","metadata":{"source":"milli/src/search/new/matches/mod.rs","assertion_line":850,"expression":"matcher.format(format_options)"},"snapshot":"_the_ do or die can't be he do and or isn't he"},"old":{"module_name":"milli__search__new__matches__tests","metadata":{},"snapshot":"_the_ _do_ _or_ die can't be he do and or isn'_t_ _he_"}}
{"run_id":"1683213557-564653000","line":751,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":590,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":814,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":616,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":654,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":759,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":625,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":662,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":823,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":599,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":832,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":768,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":671,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":777,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":680,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":786,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":689,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":637,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":795,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":698,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":707,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":716,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":725,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":734,"new":null,"old":null}
{"run_id":"1683213557-564653000","line":850,"new":{"module_name":"milli__search__new__matches__tests","snapshot_name":"partial_matches","metadata":{"source":"milli/src/search/new/matches/mod.rs","assertion_line":850,"expression":"matcher.format(format_options)"},"snapshot":"_the_ do or die can't be he do and or isn't he thedoor"},"old":{"module_name":"milli__search__new__matches__tests","metadata":{},"snapshot":"_the_ _do_ _or_ die can't be he do and or isn'_t_ _he_ _thedoor_"}}
{"run_id":"1683213999-273520000","line":657,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":754,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":619,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":593,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":817,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":665,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":762,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":628,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":826,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":602,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":674,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":835,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":771,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":683,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":780,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":692,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":701,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":789,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":640,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":710,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":798,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":719,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":728,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":737,"new":null,"old":null}
{"run_id":"1683213999-273520000","line":853,"new":{"module_name":"milli__search__new__matches__tests","snapshot_name":"partial_matches","metadata":{"source":"milli/src/search/new/matches/mod.rs","assertion_line":853,"expression":"matcher.format(format_options)"},"snapshot":"_the_ do or die can't be he do and or isn't he thedoor"},"old":{"module_name":"milli__search__new__matches__tests","metadata":{},"snapshot":"_the_ _do_ _or_ die can't be he do and or isn'_t_ _he_ _thedoor_"}}
{"run_id":"1683710541-379812000","line":754,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":593,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":657,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":817,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":619,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":762,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":665,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":628,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":826,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":602,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":771,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":835,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":674,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":780,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":683,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":789,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":692,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":640,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":798,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":701,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":710,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":719,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":728,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":737,"new":null,"old":null}
{"run_id":"1683710541-379812000","line":853,"new":{"module_name":"milli__search__new__matches__tests","snapshot_name":"partial_matches","metadata":{"source":"milli/src/search/new/matches/mod.rs","assertion_line":853,"expression":"matcher.format(format_options)"},"snapshot":"_the_ do or die can't be he do and or isn't he _thedoor_"},"old":{"module_name":"milli__search__new__matches__tests","metadata":{},"snapshot":"_the_ _do_ _or_ die can't be he do and or isn'_t_ _he_ _thedoor_"}}
{"run_id":"1683710687-182342000","line":619,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":657,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":817,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":593,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":754,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":665,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":628,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":762,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":826,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":602,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":835,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":674,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":771,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":780,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":683,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":640,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":692,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":789,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":701,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":798,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":710,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":719,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":728,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":737,"new":null,"old":null}
{"run_id":"1683710687-182342000","line":853,"new":{"module_name":"milli__search__new__matches__tests","snapshot_name":"partial_matches","metadata":{"source":"milli/src/search/new/matches/mod.rs","assertion_line":853,"expression":"matcher.format(format_options)"},"snapshot":"_the_ do or die can't be he do and or isn't he _thedoor_"},"old":{"module_name":"milli__search__new__matches__tests","metadata":{},"snapshot":"_the_ _do_ _or_ die can't be he do and or isn'_t_ _he_ _thedoor_"}}
{"run_id":"1684141548-57871000","line":654,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":662,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":671,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":680,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":689,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":698,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":707,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":716,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":725,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":734,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":590,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":599,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":751,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":759,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":768,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":777,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":786,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":795,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":616,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":625,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":637,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":851,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":814,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":823,"new":null,"old":null}
{"run_id":"1684141548-57871000","line":832,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":654,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":662,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":671,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":680,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":689,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":698,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":707,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":716,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":725,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":734,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":590,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":599,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":751,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":759,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":768,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":777,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":786,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":795,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":616,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":625,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":637,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":851,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":814,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":823,"new":null,"old":null}
{"run_id":"1684141761-300166000","line":832,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":654,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":662,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":671,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":680,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":689,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":698,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":707,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":716,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":725,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":734,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":590,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":599,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":751,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":759,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":768,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":777,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":786,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":795,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":616,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":625,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":637,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":851,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":814,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":823,"new":null,"old":null}
{"run_id":"1684227379-943236000","line":832,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":654,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":662,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":671,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":680,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":689,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":698,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":707,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":716,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":725,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":734,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":590,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":599,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":751,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":759,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":768,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":777,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":786,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":795,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":616,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":625,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":637,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":851,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":814,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":823,"new":null,"old":null}
{"run_id":"1686671229-287954000","line":832,"new":null,"old":null}

View File

@ -56,6 +56,7 @@ pub struct SearchContext<'ctx> {
pub phrase_interner: DedupInterner<Phrase>,
pub term_interner: Interner<QueryTerm>,
pub phrase_docids: PhraseDocIdsCache,
pub restricted_fids: Option<Vec<u16>>,
}
impl<'ctx> SearchContext<'ctx> {
@ -68,8 +69,18 @@ impl<'ctx> SearchContext<'ctx> {
phrase_interner: <_>::default(),
term_interner: <_>::default(),
phrase_docids: <_>::default(),
restricted_fids: None,
}
}
pub fn searchable_attributes(&mut self, searchable_attributes: &'ctx [String]) -> Result<()> {
let fids_map = self.index.fields_ids_map(self.txn)?;
let restricted_fids =
searchable_attributes.iter().filter_map(|name| fids_map.id(name)).collect();
self.restricted_fids = Some(restricted_fids);
Ok(())
}
}
#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]

View File

@ -4,7 +4,8 @@ pub use self::delete_documents::{DeleteDocuments, DeletionStrategy, DocumentDele
pub use self::facet::bulk::FacetsUpdateBulk;
pub use self::facet::incremental::FacetsUpdateIncrementalInner;
pub use self::index_documents::{
DocumentAdditionResult, DocumentId, IndexDocuments, IndexDocumentsConfig, IndexDocumentsMethod,
merge_cbo_roaring_bitmaps, merge_roaring_bitmaps, DocumentAdditionResult, DocumentId,
IndexDocuments, IndexDocumentsConfig, IndexDocumentsMethod, MergeFn,
};
pub use self::indexer_config::IndexerConfig;
pub use self::prefix_word_pairs::{