mirror of
https://github.com/quickwit-oss/tantivy.git
synced 2026-10-06 03:42:36 +00:00
Add RegexPhraseQuery::from_regexes (#3138)
RegexQuery can be built from a compiled Regex, but RegexPhraseQuery always compiled its patterns with Regex::new and its default DFA state limit. from_regexes takes the compiled regexes directly, so a caller can build them with its own limits, or reuse ones it already compiled.
This commit is contained in:
@@ -96,6 +96,36 @@ impl RegexPhraseQuery {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `RegexPhraseQuery` from already compiled regexes, e.g. built with a
|
||||
/// non-default state limit.
|
||||
///
|
||||
/// Each term is `(offset, pattern, regex)`, where `regex` is the compilation of
|
||||
/// `pattern`; the pattern is what [`RegexPhraseQuery::phrase_terms`] returns.
|
||||
pub fn from_regexes(
|
||||
field: Field,
|
||||
mut terms: Vec<(usize, String, Arc<Regex>)>,
|
||||
slop: u32,
|
||||
) -> RegexPhraseQuery {
|
||||
assert!(
|
||||
terms.len() > 1,
|
||||
"A phrase query is required to have strictly more than one term."
|
||||
);
|
||||
terms.sort_by_key(|&(offset, _, _)| offset);
|
||||
let (phrase_terms, regexes): (Vec<_>, Vec<_>) = terms
|
||||
.into_iter()
|
||||
.map(|(offset, pattern, regex)| ((offset, pattern), regex))
|
||||
.unzip();
|
||||
let compiled = OnceCell::new();
|
||||
let _ = compiled.set(regexes);
|
||||
RegexPhraseQuery {
|
||||
field,
|
||||
phrase_terms,
|
||||
slop,
|
||||
max_expansions: 1 << 14,
|
||||
regexes: CompiledRegexes(compiled),
|
||||
}
|
||||
}
|
||||
|
||||
/// Slop allowed for the phrase.
|
||||
///
|
||||
/// The query will match if its terms are separated by `slop` terms at most.
|
||||
|
||||
@@ -382,6 +382,37 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_phrase_from_regexes_uses_the_given_automata() -> crate::Result<()> {
|
||||
use std::sync::Arc;
|
||||
|
||||
use tantivy_fst::Regex;
|
||||
|
||||
use crate::collector::Count;
|
||||
|
||||
let index = create_index(&["a b", "aa b", "b a", "a c"])?;
|
||||
let text_field = index.schema().get_field("text").unwrap();
|
||||
let searcher = index.reader()?.searcher();
|
||||
let regex_a = Arc::new(Regex::new("a.*").unwrap());
|
||||
let regex_b = Arc::new(Regex::new("b").unwrap());
|
||||
let from_regexes = RegexPhraseQuery::from_regexes(
|
||||
text_field,
|
||||
vec![
|
||||
(1, "b".into(), regex_b.clone()),
|
||||
(0, "a.*".into(), regex_a.clone()),
|
||||
],
|
||||
0,
|
||||
);
|
||||
let regexes = from_regexes.regexes()?;
|
||||
assert!(Arc::ptr_eq(®exes[0], ®ex_a));
|
||||
assert!(Arc::ptr_eq(®exes[1], ®ex_b));
|
||||
|
||||
let from_patterns = RegexPhraseQuery::new(text_field, vec!["a.*".into(), "b".into()]);
|
||||
assert_eq!(searcher.search(&from_regexes, &Count)?, 2);
|
||||
assert_eq!(searcher.search(&from_patterns, &Count)?, 2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_phrase_count() -> crate::Result<()> {
|
||||
let index = create_index(&["a c", "a a b d a b c", " a b"])?;
|
||||
|
||||
Reference in New Issue
Block a user