Remove unnecessary cloning of DefineStatementAnalyzer (#4379)
This commit is contained in:
parent
209c145ad0
commit
c471dc0317
5 changed files with 65 additions and 74 deletions
|
@ -13,8 +13,7 @@ pub async fn analyze(
|
||||||
(az, val): (Value, Value),
|
(az, val): (Value, Value),
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
if let (Some(opt), Value::Strand(az), Value::Strand(val)) = (opt, az, val) {
|
if let (Some(opt), Value::Strand(az), Value::Strand(val)) = (opt, az, val) {
|
||||||
// TODO: @emmanuel-keller this `into()` is expansive and clones the value
|
let az = Analyzer::new(ctx.tx().get_db_analyzer(opt.ns()?, opt.db()?, &az).await?);
|
||||||
let az: Analyzer = ctx.tx().get_db_analyzer(opt.ns()?, opt.db()?, &az).await?.into();
|
|
||||||
az.analyze(stk, ctx, opt, val.0).await
|
az.analyze(stk, ctx, opt, val.0).await
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::None)
|
Ok(Value::None)
|
||||||
|
|
|
@ -20,13 +20,13 @@ pub(super) enum Filter {
|
||||||
Uppercase,
|
Uppercase,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SqlFilter> for Filter {
|
impl From<&SqlFilter> for Filter {
|
||||||
fn from(f: SqlFilter) -> Self {
|
fn from(f: &SqlFilter) -> Self {
|
||||||
match f {
|
match f {
|
||||||
SqlFilter::Ascii => Filter::Ascii,
|
SqlFilter::Ascii => Filter::Ascii,
|
||||||
SqlFilter::EdgeNgram(min, max) => Filter::EdgeNgram(min, max),
|
SqlFilter::EdgeNgram(min, max) => Filter::EdgeNgram(*min, *max),
|
||||||
SqlFilter::Lowercase => Filter::Lowercase,
|
SqlFilter::Lowercase => Filter::Lowercase,
|
||||||
SqlFilter::Ngram(min, max) => Filter::Ngram(min, max),
|
SqlFilter::Ngram(min, max) => Filter::Ngram(*min, *max),
|
||||||
SqlFilter::Snowball(l) => {
|
SqlFilter::Snowball(l) => {
|
||||||
let a = match l {
|
let a = match l {
|
||||||
Language::Arabic => Stemmer::create(Algorithm::Arabic),
|
Language::Arabic => Stemmer::create(Algorithm::Arabic),
|
||||||
|
@ -55,9 +55,9 @@ impl From<SqlFilter> for Filter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Filter {
|
impl Filter {
|
||||||
pub(super) fn from(fs: Option<Vec<SqlFilter>>) -> Option<Vec<Filter>> {
|
pub(super) fn from(fs: &Option<Vec<SqlFilter>>) -> Option<Vec<Filter>> {
|
||||||
if let Some(fs) = fs {
|
if let Some(fs) = fs {
|
||||||
let r = fs.into_iter().map(|f| f.into()).collect();
|
let r = fs.iter().map(|f| f.into()).collect();
|
||||||
Some(r)
|
Some(r)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -8,7 +8,6 @@ use crate::idx::ft::offsets::{Offset, OffsetRecords};
|
||||||
use crate::idx::ft::postings::TermFrequency;
|
use crate::idx::ft::postings::TermFrequency;
|
||||||
use crate::idx::ft::terms::{TermId, TermLen, Terms};
|
use crate::idx::ft::terms::{TermId, TermLen, Terms};
|
||||||
use crate::sql::statements::DefineAnalyzerStatement;
|
use crate::sql::statements::DefineAnalyzerStatement;
|
||||||
use crate::sql::tokenizer::Tokenizer as SqlTokenizer;
|
|
||||||
use crate::sql::Value;
|
use crate::sql::Value;
|
||||||
use crate::sql::{Function, Strand};
|
use crate::sql::{Function, Strand};
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
|
@ -16,34 +15,14 @@ use reblessive::tree::Stk;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
mod filter;
|
mod filter;
|
||||||
mod tokenizer;
|
mod tokenizer;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub(crate) struct Analyzer {
|
pub(crate) struct Analyzer {
|
||||||
function: Option<String>,
|
az: Arc<DefineAnalyzerStatement>,
|
||||||
tokenizers: Option<Vec<SqlTokenizer>>,
|
filters: Arc<Option<Vec<Filter>>>,
|
||||||
filters: Option<Vec<Filter>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DefineAnalyzerStatement> for Analyzer {
|
|
||||||
fn from(az: DefineAnalyzerStatement) -> Self {
|
|
||||||
Self {
|
|
||||||
function: az.function.map(|i| i.0),
|
|
||||||
tokenizers: az.tokenizers,
|
|
||||||
filters: Filter::from(az.filters),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: @emmanuel-keller we probably don't need to clone the value here
|
|
||||||
impl From<Arc<DefineAnalyzerStatement>> for Analyzer {
|
|
||||||
fn from(az: Arc<DefineAnalyzerStatement>) -> Self {
|
|
||||||
Self {
|
|
||||||
function: az.function.clone().map(|i| i.0),
|
|
||||||
tokenizers: az.tokenizers.clone(),
|
|
||||||
filters: Filter::from(az.filters.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::idx) type TermsList = Vec<Option<(TermId, TermLen)>>;
|
pub(in crate::idx) type TermsList = Vec<Option<(TermId, TermLen)>>;
|
||||||
|
@ -70,6 +49,13 @@ impl TermsSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Analyzer {
|
impl Analyzer {
|
||||||
|
pub(crate) fn new(az: Arc<DefineAnalyzerStatement>) -> Self {
|
||||||
|
Self {
|
||||||
|
filters: Arc::new(Filter::from(&az.filters)),
|
||||||
|
az,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) async fn extract_querying_terms(
|
pub(super) async fn extract_querying_terms(
|
||||||
&self,
|
&self,
|
||||||
stk: &mut Stk,
|
stk: &mut Stk,
|
||||||
|
@ -280,7 +266,7 @@ impl Analyzer {
|
||||||
stage: FilteringStage,
|
stage: FilteringStage,
|
||||||
mut input: String,
|
mut input: String,
|
||||||
) -> Result<Tokens, Error> {
|
) -> Result<Tokens, Error> {
|
||||||
if let Some(function_name) = self.function.clone() {
|
if let Some(function_name) = self.az.function.as_ref().map(|i| i.0.clone()) {
|
||||||
let fns = Function::Custom(function_name.clone(), vec![Value::Strand(Strand(input))]);
|
let fns = Function::Custom(function_name.clone(), vec![Value::Strand(Strand(input))]);
|
||||||
let val = fns.compute(stk, ctx, opt, None).await?;
|
let val = fns.compute(stk, ctx, opt, None).await?;
|
||||||
if let Value::Strand(val) = val {
|
if let Value::Strand(val) = val {
|
||||||
|
@ -292,7 +278,7 @@ impl Analyzer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(t) = &self.tokenizers {
|
if let Some(t) = &self.az.tokenizers {
|
||||||
if !input.is_empty() {
|
if !input.is_empty() {
|
||||||
let t = Tokenizer::tokenize(t, input);
|
let t = Tokenizer::tokenize(t, input);
|
||||||
return Filter::apply_filters(t, &self.filters, stage);
|
return Filter::apply_filters(t, &self.filters, stage);
|
||||||
|
@ -336,7 +322,7 @@ mod tests {
|
||||||
let Some(Statement::Define(DefineStatement::Analyzer(az))) = stmt.0 .0.pop() else {
|
let Some(Statement::Define(DefineStatement::Analyzer(az))) = stmt.0 .0.pop() else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
let a: Analyzer = az.into();
|
let a = Analyzer::new(Arc::new(az));
|
||||||
|
|
||||||
let mut stack = reblessive::TreeStack::new();
|
let mut stack = reblessive::TreeStack::new();
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ use tokio::sync::RwLock;
|
||||||
pub(crate) type MatchRef = u8;
|
pub(crate) type MatchRef = u8;
|
||||||
|
|
||||||
pub(crate) struct FtIndex {
|
pub(crate) struct FtIndex {
|
||||||
analyzer: Arc<Analyzer>,
|
analyzer: Analyzer,
|
||||||
state_key: Key,
|
state_key: Key,
|
||||||
index_key_base: IndexKeyBase,
|
index_key_base: IndexKeyBase,
|
||||||
state: State,
|
state: State,
|
||||||
|
@ -106,14 +106,13 @@ impl FtIndex {
|
||||||
tt: TransactionType,
|
tt: TransactionType,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let tx = ctx.tx();
|
let tx = ctx.tx();
|
||||||
// TODO: @emmanuel-keller we probably don't need to clone the value here
|
let az = tx.get_db_analyzer(opt.ns()?, opt.db()?, az).await?;
|
||||||
let az = tx.get_db_analyzer(opt.ns()?, opt.db()?, az).await?.as_ref().to_owned();
|
|
||||||
Self::with_analyzer(ctx.get_index_stores(), &tx, az, index_key_base, p, tt).await
|
Self::with_analyzer(ctx.get_index_stores(), &tx, az, index_key_base, p, tt).await
|
||||||
}
|
}
|
||||||
async fn with_analyzer(
|
async fn with_analyzer(
|
||||||
ixs: &IndexStores,
|
ixs: &IndexStores,
|
||||||
txn: &Transaction,
|
txn: &Transaction,
|
||||||
az: DefineAnalyzerStatement,
|
az: Arc<DefineAnalyzerStatement>,
|
||||||
index_key_base: IndexKeyBase,
|
index_key_base: IndexKeyBase,
|
||||||
p: &SearchParams,
|
p: &SearchParams,
|
||||||
tt: TransactionType,
|
tt: TransactionType,
|
||||||
|
@ -165,7 +164,7 @@ impl FtIndex {
|
||||||
index_key_base,
|
index_key_base,
|
||||||
bm25,
|
bm25,
|
||||||
highlighting: p.hl,
|
highlighting: p.hl,
|
||||||
analyzer: Arc::new(az.into()),
|
analyzer: Analyzer::new(az),
|
||||||
doc_ids,
|
doc_ids,
|
||||||
doc_lengths,
|
doc_lengths,
|
||||||
postings,
|
postings,
|
||||||
|
@ -183,7 +182,7 @@ impl FtIndex {
|
||||||
self.terms.clone()
|
self.terms.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn analyzer(&self) -> Arc<Analyzer> {
|
pub(super) fn analyzer(&self) -> Analyzer {
|
||||||
self.analyzer.clone()
|
self.analyzer.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,18 +582,13 @@ mod tests {
|
||||||
pub(super) async fn tx_fti<'a>(
|
pub(super) async fn tx_fti<'a>(
|
||||||
ds: &Datastore,
|
ds: &Datastore,
|
||||||
tt: TransactionType,
|
tt: TransactionType,
|
||||||
az: &DefineAnalyzerStatement,
|
az: Arc<DefineAnalyzerStatement>,
|
||||||
order: u32,
|
order: u32,
|
||||||
hl: bool,
|
hl: bool,
|
||||||
) -> (Context<'a>, Options, FtIndex) {
|
) -> (Context<'a>, Options, FtIndex) {
|
||||||
let mut ctx = Context::default();
|
let mut ctx = Context::default();
|
||||||
let tx = ds.transaction(tt, Optimistic).await.unwrap();
|
let tx = ds.transaction(tt, Optimistic).await.unwrap();
|
||||||
let fti = FtIndex::with_analyzer(
|
let p = SearchParams {
|
||||||
ctx.get_index_stores(),
|
|
||||||
&tx,
|
|
||||||
az.clone(),
|
|
||||||
IndexKeyBase::default(),
|
|
||||||
&SearchParams {
|
|
||||||
az: az.name.clone(),
|
az: az.name.clone(),
|
||||||
doc_ids_order: order,
|
doc_ids_order: order,
|
||||||
doc_lengths_order: order,
|
doc_lengths_order: order,
|
||||||
|
@ -606,7 +600,13 @@ mod tests {
|
||||||
doc_lengths_cache: 100,
|
doc_lengths_cache: 100,
|
||||||
postings_cache: 100,
|
postings_cache: 100,
|
||||||
terms_cache: 100,
|
terms_cache: 100,
|
||||||
},
|
};
|
||||||
|
let fti = FtIndex::with_analyzer(
|
||||||
|
ctx.get_index_stores(),
|
||||||
|
&tx,
|
||||||
|
az,
|
||||||
|
IndexKeyBase::default(),
|
||||||
|
&p,
|
||||||
tt,
|
tt,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -629,6 +629,7 @@ mod tests {
|
||||||
let Statement::Define(DefineStatement::Analyzer(az)) = q.0 .0.pop().unwrap() else {
|
let Statement::Define(DefineStatement::Analyzer(az)) = q.0 .0.pop().unwrap() else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
|
let az = Arc::new(az);
|
||||||
let mut stack = reblessive::TreeStack::new();
|
let mut stack = reblessive::TreeStack::new();
|
||||||
|
|
||||||
let btree_order = 5;
|
let btree_order = 5;
|
||||||
|
@ -641,7 +642,7 @@ mod tests {
|
||||||
.enter(|stk| async {
|
.enter(|stk| async {
|
||||||
// Add one document
|
// Add one document
|
||||||
let (ctx, opt, mut fti) =
|
let (ctx, opt, mut fti) =
|
||||||
tx_fti(&ds, TransactionType::Write, &az, btree_order, false).await;
|
tx_fti(&ds, TransactionType::Write, az.clone(), btree_order, false).await;
|
||||||
fti.index_document(stk, &ctx, &opt, &doc1, vec![Value::from("hello the world")])
|
fti.index_document(stk, &ctx, &opt, &doc1, vec![Value::from("hello the world")])
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -654,7 +655,7 @@ mod tests {
|
||||||
.enter(|stk| async {
|
.enter(|stk| async {
|
||||||
// Add two documents
|
// Add two documents
|
||||||
let (ctx, opt, mut fti) =
|
let (ctx, opt, mut fti) =
|
||||||
tx_fti(&ds, TransactionType::Write, &az, btree_order, false).await;
|
tx_fti(&ds, TransactionType::Write, az.clone(), btree_order, false).await;
|
||||||
fti.index_document(stk, &ctx, &opt, &doc2, vec![Value::from("a yellow hello")])
|
fti.index_document(stk, &ctx, &opt, &doc2, vec![Value::from("a yellow hello")])
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -669,7 +670,7 @@ mod tests {
|
||||||
stack
|
stack
|
||||||
.enter(|stk| async {
|
.enter(|stk| async {
|
||||||
let (ctx, opt, fti) =
|
let (ctx, opt, fti) =
|
||||||
tx_fti(&ds, TransactionType::Read, &az, btree_order, false).await;
|
tx_fti(&ds, TransactionType::Read, az.clone(), btree_order, false).await;
|
||||||
// Check the statistics
|
// Check the statistics
|
||||||
let statistics = fti.statistics(&ctx).await.unwrap();
|
let statistics = fti.statistics(&ctx).await.unwrap();
|
||||||
assert_eq!(statistics.terms.keys_count, 7);
|
assert_eq!(statistics.terms.keys_count, 7);
|
||||||
|
@ -709,14 +710,14 @@ mod tests {
|
||||||
.enter(|stk| async {
|
.enter(|stk| async {
|
||||||
// Reindex one document
|
// Reindex one document
|
||||||
let (ctx, opt, mut fti) =
|
let (ctx, opt, mut fti) =
|
||||||
tx_fti(&ds, TransactionType::Write, &az, btree_order, false).await;
|
tx_fti(&ds, TransactionType::Write, az.clone(), btree_order, false).await;
|
||||||
fti.index_document(stk, &ctx, &opt, &doc3, vec![Value::from("nobar foo")])
|
fti.index_document(stk, &ctx, &opt, &doc3, vec![Value::from("nobar foo")])
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
finish(&ctx, fti).await;
|
finish(&ctx, fti).await;
|
||||||
|
|
||||||
let (ctx, opt, fti) =
|
let (ctx, opt, fti) =
|
||||||
tx_fti(&ds, TransactionType::Read, &az, btree_order, false).await;
|
tx_fti(&ds, TransactionType::Read, az.clone(), btree_order, false).await;
|
||||||
|
|
||||||
// We can still find 'foo'
|
// We can still find 'foo'
|
||||||
let (hits, scr) = search(stk, &ctx, &opt, &fti, "foo").await;
|
let (hits, scr) = search(stk, &ctx, &opt, &fti, "foo").await;
|
||||||
|
@ -736,7 +737,7 @@ mod tests {
|
||||||
{
|
{
|
||||||
// Remove documents
|
// Remove documents
|
||||||
let (ctx, _, mut fti) =
|
let (ctx, _, mut fti) =
|
||||||
tx_fti(&ds, TransactionType::Write, &az, btree_order, false).await;
|
tx_fti(&ds, TransactionType::Write, az.clone(), btree_order, false).await;
|
||||||
fti.remove_document(&ctx, &doc1).await.unwrap();
|
fti.remove_document(&ctx, &doc1).await.unwrap();
|
||||||
fti.remove_document(&ctx, &doc2).await.unwrap();
|
fti.remove_document(&ctx, &doc2).await.unwrap();
|
||||||
fti.remove_document(&ctx, &doc3).await.unwrap();
|
fti.remove_document(&ctx, &doc3).await.unwrap();
|
||||||
|
@ -746,7 +747,7 @@ mod tests {
|
||||||
stack
|
stack
|
||||||
.enter(|stk| async {
|
.enter(|stk| async {
|
||||||
let (ctx, opt, fti) =
|
let (ctx, opt, fti) =
|
||||||
tx_fti(&ds, TransactionType::Read, &az, btree_order, false).await;
|
tx_fti(&ds, TransactionType::Read, az.clone(), btree_order, false).await;
|
||||||
let (hits, _) = search(stk, &ctx, &opt, &fti, "hello").await;
|
let (hits, _) = search(stk, &ctx, &opt, &fti, "hello").await;
|
||||||
assert!(hits.is_none());
|
assert!(hits.is_none());
|
||||||
let (hits, _) = search(stk, &ctx, &opt, &fti, "foo").await;
|
let (hits, _) = search(stk, &ctx, &opt, &fti, "foo").await;
|
||||||
|
@ -767,6 +768,7 @@ mod tests {
|
||||||
let Statement::Define(DefineStatement::Analyzer(az)) = q.0 .0.pop().unwrap() else {
|
let Statement::Define(DefineStatement::Analyzer(az)) = q.0 .0.pop().unwrap() else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
|
let az = Arc::new(az);
|
||||||
let mut stack = reblessive::TreeStack::new();
|
let mut stack = reblessive::TreeStack::new();
|
||||||
|
|
||||||
let doc1: Thing = ("t", "doc1").into();
|
let doc1: Thing = ("t", "doc1").into();
|
||||||
|
@ -778,7 +780,7 @@ mod tests {
|
||||||
stack
|
stack
|
||||||
.enter(|stk| async {
|
.enter(|stk| async {
|
||||||
let (ctx, opt, mut fti) =
|
let (ctx, opt, mut fti) =
|
||||||
tx_fti(&ds, TransactionType::Write, &az, btree_order, hl).await;
|
tx_fti(&ds, TransactionType::Write, az.clone(), btree_order, hl).await;
|
||||||
fti.index_document(
|
fti.index_document(
|
||||||
stk,
|
stk,
|
||||||
&ctx,
|
&ctx,
|
||||||
|
@ -823,7 +825,7 @@ mod tests {
|
||||||
stack
|
stack
|
||||||
.enter(|stk| async {
|
.enter(|stk| async {
|
||||||
let (ctx, opt, fti) =
|
let (ctx, opt, fti) =
|
||||||
tx_fti(&ds, TransactionType::Read, &az, btree_order, hl).await;
|
tx_fti(&ds, TransactionType::Read, az.clone(), btree_order, hl).await;
|
||||||
|
|
||||||
let statistics = fti.statistics(&ctx).await.unwrap();
|
let statistics = fti.statistics(&ctx).await.unwrap();
|
||||||
assert_eq!(statistics.terms.keys_count, 17);
|
assert_eq!(statistics.terms.keys_count, 17);
|
||||||
|
@ -894,7 +896,7 @@ mod tests {
|
||||||
test_ft_index_bm_25(true).await;
|
test_ft_index_bm_25(true).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn concurrent_task(ds: Arc<Datastore>, az: DefineAnalyzerStatement) {
|
async fn concurrent_task(ds: Arc<Datastore>, az: Arc<DefineAnalyzerStatement>) {
|
||||||
let btree_order = 5;
|
let btree_order = 5;
|
||||||
let doc1: Thing = ("t", "doc1").into();
|
let doc1: Thing = ("t", "doc1").into();
|
||||||
let content1 = Value::from(Array::from(vec!["Enter a search term", "Welcome", "Docusaurus blogging features are powered by the blog plugin.", "Simply add Markdown files (or folders) to the blog directory.", "blog", "Regular blog authors can be added to authors.yml.", "authors.yml", "The blog post date can be extracted from filenames, such as:", "2019-05-30-welcome.md", "2019-05-30-welcome/index.md", "A blog post folder can be convenient to co-locate blog post images:", "The blog supports tags as well!", "And if you don't want a blog: just delete this directory, and use blog: false in your Docusaurus config.", "blog: false", "MDX Blog Post", "Blog posts support Docusaurus Markdown features, such as MDX.", "Use the power of React to create interactive blog posts.", "Long Blog Post", "This is the summary of a very long blog post,", "Use a <!-- truncate --> comment to limit blog post size in the list view.", "<!--", "truncate", "-->", "First Blog Post", "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet"]));
|
let content1 = Value::from(Array::from(vec!["Enter a search term", "Welcome", "Docusaurus blogging features are powered by the blog plugin.", "Simply add Markdown files (or folders) to the blog directory.", "blog", "Regular blog authors can be added to authors.yml.", "authors.yml", "The blog post date can be extracted from filenames, such as:", "2019-05-30-welcome.md", "2019-05-30-welcome/index.md", "A blog post folder can be convenient to co-locate blog post images:", "The blog supports tags as well!", "And if you don't want a blog: just delete this directory, and use blog: false in your Docusaurus config.", "blog: false", "MDX Blog Post", "Blog posts support Docusaurus Markdown features, such as MDX.", "Use the power of React to create interactive blog posts.", "Long Blog Post", "This is the summary of a very long blog post,", "Use a <!-- truncate --> comment to limit blog post size in the list view.", "<!--", "truncate", "-->", "First Blog Post", "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet"]));
|
||||||
|
@ -904,7 +906,7 @@ mod tests {
|
||||||
while start.elapsed().as_secs() < 3 {
|
while start.elapsed().as_secs() < 3 {
|
||||||
stack
|
stack
|
||||||
.enter(|stk| {
|
.enter(|stk| {
|
||||||
remove_insert_task(stk, ds.as_ref(), &az, btree_order, &doc1, &content1)
|
remove_insert_task(stk, ds.as_ref(), az.clone(), btree_order, &doc1, &content1)
|
||||||
})
|
})
|
||||||
.finish()
|
.finish()
|
||||||
.await;
|
.await;
|
||||||
|
@ -917,6 +919,7 @@ mod tests {
|
||||||
let Statement::Define(DefineStatement::Analyzer(az)) = q.0 .0.pop().unwrap() else {
|
let Statement::Define(DefineStatement::Analyzer(az)) = q.0 .0.pop().unwrap() else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
|
let az = Arc::new(az);
|
||||||
concurrent_task(ds.clone(), az.clone()).await;
|
concurrent_task(ds.clone(), az.clone()).await;
|
||||||
let task1 = tokio::spawn(concurrent_task(ds.clone(), az.clone()));
|
let task1 = tokio::spawn(concurrent_task(ds.clone(), az.clone()));
|
||||||
let task2 = tokio::spawn(concurrent_task(ds.clone(), az.clone()));
|
let task2 = tokio::spawn(concurrent_task(ds.clone(), az.clone()));
|
||||||
|
@ -926,7 +929,7 @@ mod tests {
|
||||||
async fn remove_insert_task(
|
async fn remove_insert_task(
|
||||||
stk: &mut Stk,
|
stk: &mut Stk,
|
||||||
ds: &Datastore,
|
ds: &Datastore,
|
||||||
az: &DefineAnalyzerStatement,
|
az: Arc<DefineAnalyzerStatement>,
|
||||||
btree_order: u32,
|
btree_order: u32,
|
||||||
rid: &Thing,
|
rid: &Thing,
|
||||||
content: &Value,
|
content: &Value,
|
||||||
|
@ -945,13 +948,15 @@ mod tests {
|
||||||
let Statement::Define(DefineStatement::Analyzer(az)) = q.0 .0.pop().unwrap() else {
|
let Statement::Define(DefineStatement::Analyzer(az)) = q.0 .0.pop().unwrap() else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
|
let az = Arc::new(az);
|
||||||
let doc: Thing = ("t", "doc1").into();
|
let doc: Thing = ("t", "doc1").into();
|
||||||
let content = Value::from(Array::from(vec!["Enter a search term","Welcome","Docusaurus blogging features are powered by the blog plugin.","Simply add Markdown files (or folders) to the blog directory.","blog","Regular blog authors can be added to authors.yml.","authors.yml","The blog post date can be extracted from filenames, such as:","2019-05-30-welcome.md","2019-05-30-welcome/index.md","A blog post folder can be convenient to co-locate blog post images:","The blog supports tags as well!","And if you don't want a blog: just delete this directory, and use blog: false in your Docusaurus config.","blog: false","MDX Blog Post","Blog posts support Docusaurus Markdown features, such as MDX.","Use the power of React to create interactive blog posts.","Long Blog Post","This is the summary of a very long blog post,","Use a <!-- truncate --> comment to limit blog post size in the list view.","<!--","truncate","-->","First Blog Post","Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet"]));
|
let content = Value::from(Array::from(vec!["Enter a search term","Welcome","Docusaurus blogging features are powered by the blog plugin.","Simply add Markdown files (or folders) to the blog directory.","blog","Regular blog authors can be added to authors.yml.","authors.yml","The blog post date can be extracted from filenames, such as:","2019-05-30-welcome.md","2019-05-30-welcome/index.md","A blog post folder can be convenient to co-locate blog post images:","The blog supports tags as well!","And if you don't want a blog: just delete this directory, and use blog: false in your Docusaurus config.","blog: false","MDX Blog Post","Blog posts support Docusaurus Markdown features, such as MDX.","Use the power of React to create interactive blog posts.","Long Blog Post","This is the summary of a very long blog post,","Use a <!-- truncate --> comment to limit blog post size in the list view.","<!--","truncate","-->","First Blog Post","Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet"]));
|
||||||
|
|
||||||
for i in 0..5 {
|
for i in 0..5 {
|
||||||
debug!("Attempt {i}");
|
debug!("Attempt {i}");
|
||||||
{
|
{
|
||||||
let (ctx, opt, mut fti) = tx_fti(&ds, TransactionType::Write, &az, 5, false).await;
|
let (ctx, opt, mut fti) =
|
||||||
|
tx_fti(&ds, TransactionType::Write, az.clone(), 5, false).await;
|
||||||
stack
|
stack
|
||||||
.enter(|stk| fti.index_document(stk, &ctx, &opt, &doc, vec![content.clone()]))
|
.enter(|stk| fti.index_document(stk, &ctx, &opt, &doc, vec![content.clone()]))
|
||||||
.finish()
|
.finish()
|
||||||
|
@ -961,19 +966,20 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let (ctx, _, fti) = tx_fti(&ds, TransactionType::Read, &az, 5, false).await;
|
let (ctx, _, fti) = tx_fti(&ds, TransactionType::Read, az.clone(), 5, false).await;
|
||||||
let s = fti.statistics(&ctx).await.unwrap();
|
let s = fti.statistics(&ctx).await.unwrap();
|
||||||
assert_eq!(s.terms.keys_count, 113);
|
assert_eq!(s.terms.keys_count, 113);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let (ctx, _, mut fti) = tx_fti(&ds, TransactionType::Write, &az, 5, false).await;
|
let (ctx, _, mut fti) =
|
||||||
|
tx_fti(&ds, TransactionType::Write, az.clone(), 5, false).await;
|
||||||
fti.remove_document(&ctx, &doc).await.unwrap();
|
fti.remove_document(&ctx, &doc).await.unwrap();
|
||||||
finish(&ctx, fti).await;
|
finish(&ctx, fti).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let (ctx, _, fti) = tx_fti(&ds, TransactionType::Read, &az, 5, false).await;
|
let (ctx, _, fti) = tx_fti(&ds, TransactionType::Read, az.clone(), 5, false).await;
|
||||||
let s = fti.statistics(&ctx).await.unwrap();
|
let s = fti.statistics(&ctx).await.unwrap();
|
||||||
assert_eq!(s.terms.keys_count, 0);
|
assert_eq!(s.terms.keys_count, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -702,7 +702,7 @@ struct FtEntry(Arc<Inner>);
|
||||||
struct Inner {
|
struct Inner {
|
||||||
index_option: IndexOption,
|
index_option: IndexOption,
|
||||||
doc_ids: Arc<RwLock<DocIds>>,
|
doc_ids: Arc<RwLock<DocIds>>,
|
||||||
analyzer: Arc<Analyzer>,
|
analyzer: Analyzer,
|
||||||
query_terms_set: TermsSet,
|
query_terms_set: TermsSet,
|
||||||
query_terms_list: TermsList,
|
query_terms_list: TermsList,
|
||||||
terms: Arc<RwLock<Terms>>,
|
terms: Arc<RwLock<Terms>>,
|
||||||
|
|
Loading…
Reference in a new issue