///|
/// Phrase query whose final token is expanded from the segment term
/// dictionary. This is the primitive behind search-as-you-type query strings.
pub struct PhrasePrefixQuery {
field_id : FieldId
exact_texts : ReadOnlyArray[String]
final_prefix : String
slop : Int
max_expansions : Int
}
///|
pub fn PhrasePrefixQuery::new(
field_id : FieldId,
exact_texts : Array[String],
final_prefix : String,
) -> PhrasePrefixQuery {
{
field_id,
exact_texts: ReadOnlyArray::from_array(exact_texts.copy()),
final_prefix,
slop: 0,
max_expansions: 64,
}
}
///|
pub fn PhrasePrefixQuery::with_options(
self : PhrasePrefixQuery,
slop : Int,
max_expansions : Int,
) -> PhrasePrefixQuery {
guard slop >= 0 else { abort("phrase-prefix slop must be non-negative") }
guard max_expansions > 0 else {
abort("phrase-prefix expansion limit must be positive")
}
{
field_id: self.field_id,
exact_texts: self.exact_texts,
final_prefix: self.final_prefix,
slop,
max_expansions,
}
}
///|
priv struct PhrasePrefixWeight {
query : PhrasePrefixQuery
statistics : SearchStatistics
}
///|
impl Weight for PhrasePrefixWeight with fn scorer(self, segment) {
let clauses : Array[BooleanClause] = []
let expanded = segment
.term_dictionary()
.terms_with_prefix(self.query.field_id, self.query.final_prefix)
let mut count = 0
for term in expanded {
if count >= self.query.max_expansions {
break
}
let texts : Array[String] = []
for text in self.query.exact_texts {
texts.push(text)
}
texts.push(term.text)
clauses.push(
BooleanClause::new(
Should,
PhraseQuery::new(self.query.field_id, texts).with_slop(self.query.slop),
),
)
count += 1
}
Query::weight(BooleanQuery::new(clauses), self.statistics).scorer(segment)
}
///|
pub impl Query for PhrasePrefixQuery with fn weight(self, statistics) {
PhrasePrefixWeight::{ query: self, statistics } as &Weight
}