lb_tantivy/query/term_query/
term_query.rs1use std::fmt;
2
3use super::term_weight::TermWeight;
4use crate::query::bm25::Bm25Weight;
5use crate::query::{EnableScoring, Explanation, Query, Weight};
6use crate::schema::IndexRecordOption;
7use crate::Term;
8
9#[derive(Clone)]
58pub struct TermQuery {
59 term: Term,
60 index_record_option: IndexRecordOption,
61}
62
63impl fmt::Debug for TermQuery {
64 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65 write!(f, "TermQuery({:?})", self.term)
66 }
67}
68
69impl TermQuery {
70 pub fn new(term: Term, segment_postings_options: IndexRecordOption) -> TermQuery {
72 TermQuery {
73 term,
74 index_record_option: segment_postings_options,
75 }
76 }
77
78 pub fn term(&self) -> &Term {
80 &self.term
81 }
82
83 pub fn specialized_weight(
89 &self,
90 enable_scoring: EnableScoring<'_>,
91 ) -> crate::Result<TermWeight> {
92 let schema = enable_scoring.schema();
93 let field_entry = schema.get_field_entry(self.term.field());
94 if !field_entry.is_indexed() {
95 let error_msg = format!("Field {:?} is not indexed.", field_entry.name());
96 return Err(crate::TantivyError::SchemaError(error_msg));
97 }
98 let bm25_weight = match enable_scoring {
99 EnableScoring::Enabled {
100 statistics_provider,
101 ..
102 } => Bm25Weight::for_terms(statistics_provider, &[self.term.clone()])?,
103 EnableScoring::Disabled { .. } => {
104 Bm25Weight::new(Explanation::new("<no score>", 1.0f32), 1.0f32)
105 }
106 };
107 let scoring_enabled = enable_scoring.is_scoring_enabled();
108 let index_record_option = if scoring_enabled {
109 self.index_record_option
110 } else {
111 IndexRecordOption::Basic
112 };
113
114 Ok(TermWeight::new(
115 self.term.clone(),
116 index_record_option,
117 bm25_weight,
118 scoring_enabled,
119 ))
120 }
121}
122
123impl Query for TermQuery {
124 fn weight(&self, enable_scoring: EnableScoring<'_>) -> crate::Result<Box<dyn Weight>> {
125 Ok(Box::new(self.specialized_weight(enable_scoring)?))
126 }
127 fn query_terms<'a>(&'a self, visitor: &mut dyn FnMut(&'a Term, bool)) {
128 visitor(&self.term, false);
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use std::net::{IpAddr, Ipv6Addr};
135 use std::str::FromStr;
136
137 use columnar::MonotonicallyMappableToU128;
138
139 use crate::collector::{Count, TopDocs};
140 use crate::query::{Query, QueryParser, TermQuery};
141 use crate::schema::{IndexRecordOption, IntoIpv6Addr, Schema, INDEXED, STORED};
142 use crate::{Index, IndexWriter, Term};
143
144 #[test]
145 fn search_ip_test() {
146 let mut schema_builder = Schema::builder();
147 let ip_field = schema_builder.add_ip_addr_field("ip", INDEXED | STORED);
148 let schema = schema_builder.build();
149 let index = Index::create_in_ram(schema);
150 let ip_addr_1 = IpAddr::from_str("127.0.0.1").unwrap().into_ipv6_addr();
151 let ip_addr_2 = Ipv6Addr::from_u128(10);
152
153 {
154 let mut index_writer: IndexWriter = index.writer_for_tests().unwrap();
155 index_writer
156 .add_document(doc!(
157 ip_field => ip_addr_1
158 ))
159 .unwrap();
160 index_writer
161 .add_document(doc!(
162 ip_field => ip_addr_2
163 ))
164 .unwrap();
165
166 index_writer.commit().unwrap();
167 }
168 let reader = index.reader().unwrap();
169 let searcher = reader.searcher();
170
171 let assert_single_hit = |query| {
172 let (_top_docs, count) = searcher
173 .search(&query, &(TopDocs::with_limit(2), Count))
174 .unwrap();
175 assert_eq!(count, 1);
176 };
177 let query_from_text = |text: String| {
178 QueryParser::for_index(&index, vec![ip_field])
179 .parse_query(&text)
180 .unwrap()
181 };
182
183 let query_from_ip = |ip_addr| -> Box<dyn Query> {
184 Box::new(TermQuery::new(
185 Term::from_field_ip_addr(ip_field, ip_addr),
186 IndexRecordOption::Basic,
187 ))
188 };
189
190 assert_single_hit(query_from_ip(ip_addr_1));
191 assert_single_hit(query_from_ip(ip_addr_2));
192 assert_single_hit(query_from_text("127.0.0.1".to_string()));
193 assert_single_hit(query_from_text("\"127.0.0.1\"".to_string()));
194 assert_single_hit(query_from_text(format!("\"{ip_addr_1}\"")));
195 assert_single_hit(query_from_text(format!("\"{ip_addr_2}\"")));
196 }
197}