Move business logic out of cantine
- Id
- 38e2fd3442197e4ebe48d3d7b1aa0d41bc5b7773
- Author
- Caio
- Commit time
- 2019-12-06T15:48:12+01:00
Modified crates/cantine/src/index.rs
self,
query::{AllQuery, BooleanQuery, Occur, Query},
schema::{Field, Schema, SchemaBuilder, Value, FAST, STORED, TEXT},
- tokenizer::TokenizerManager,
- DocId, Document, Index, IndexReader, Result, Searcher, SegmentReader, TantivyError,
+ DocId, Document, Index, Result, Searcher, SegmentReader, TantivyError,
};
use crate::model::{
}
impl TryFrom<&Schema> for IndexFields {
- // TODO better error
type Error = TantivyError;
fn try_from(schema: &Schema) -> Result<Self> {
}
pub struct Cantine {
- reader: IndexReader,
fields: IndexFields,
query_parser: QueryParser,
}
);
impl Cantine {
- pub fn open<P: AsRef<Path>>(base_path: P) -> Result<Self> {
+ pub fn open<P: AsRef<Path>>(base_path: P) -> Result<(Index, Self)> {
let index = Index::open_in_dir(base_path.as_ref())?;
+ let cantine = Self::try_from(&index)?;
- let fields = IndexFields::try_from(&index.schema()).unwrap();
- let reader = index.reader()?;
-
- let query_parser = QueryParser::new(
- fields.fulltext,
- TokenizerManager::default().get("en_stem").unwrap(),
- true,
- );
-
- Ok(Self {
- fields,
- reader,
- query_parser,
- })
+ Ok((index, cantine))
}
pub fn interpret_query(&self, query: &SearchQuery) -> Result<Box<dyn Query>> {
Ok(items)
}
- fn basic_search(
+ pub fn search(
&self,
searcher: &Searcher,
interpreted_query: &dyn Query,
}
}
- fn compute_aggregations(
+ pub fn aggregate_features(
&self,
searcher: &Searcher,
interpreted_query: &dyn Query,
Ok(searcher.search(interpreted_query, &collector)?)
}
+}
- pub fn search(
- &self,
- query: SearchQuery,
- agg_threshold: Option<usize>,
- ) -> Result<CantineSearchResult> {
- let searcher = self.reader.searcher();
+impl TryFrom<&Index> for Cantine {
+ type Error = TantivyError;
+ fn try_from(index: &Index) -> Result<Self> {
+ let fields = IndexFields::try_from(&index.schema())?;
- let interpreted_query = self.interpret_query(&query)?;
- let limit = query.num_items.unwrap_or(10) as usize;
+ let query_parser = QueryParser::new(
+ fields.fulltext,
+ index.tokenizer_for_field(fields.fulltext)?,
+ true,
+ );
- let (total_found, items, after) = self.basic_search(
- &searcher,
- &interpreted_query,
- limit,
- query.sort.unwrap_or(Sort::Relevance),
- query.after.unwrap_or(SearchCursor::START),
- )?;
-
- let agg = if let Some(agg_query) = query.agg {
- if total_found <= agg_threshold.unwrap_or(std::usize::MAX) {
- Some(self.compute_aggregations(&searcher, &interpreted_query, agg_query)?)
- } else {
- None
- }
- } else {
- None
- };
-
- Ok((total_found, items, after, agg))
+ Ok(Self {
+ fields,
+ query_parser,
+ })
}
}
Modified crates/cantine/src/bin/query.rs
use serde_json;
use structopt::StructOpt;
-use tantivy::Result;
+use tantivy::{Result, Searcher};
use cantine::{
database::BincodeDatabase,
index::Cantine,
- model::{Recipe, SearchResult},
+ model::{Recipe, SearchCursor, SearchQuery, SearchResult, Sort},
};
/// Queries data generated via `load`
agg_threshold: Option<usize>,
}
+fn search(
+ database: &BincodeDatabase<Recipe>,
+ searcher: &Searcher,
+ cantine: &Cantine,
+ query: SearchQuery,
+ agg_threshold: Option<usize>,
+) -> Result<SearchResult> {
+ let interpreted_query = cantine.interpret_query(&query)?;
+ let limit = query.num_items.unwrap_or(10) as usize;
+
+ let (total_found, recipe_ids, after) = cantine.search(
+ &searcher,
+ &interpreted_query,
+ limit,
+ query.sort.unwrap_or(Sort::Relevance),
+ query.after.unwrap_or(SearchCursor::START),
+ )?;
+
+ let agg = if let Some(agg_query) = query.agg {
+ if total_found <= agg_threshold.unwrap_or(std::usize::MAX) {
+ Some(cantine.aggregate_features(&searcher, &interpreted_query, agg_query)?)
+ } else {
+ None
+ }
+ } else {
+ None
+ };
+
+ let mut items = Vec::with_capacity(recipe_ids.len());
+ for recipe_id in recipe_ids {
+ let recipe: Recipe = database
+ .get_by_id(recipe_id)
+ .expect("db operational")
+ .expect("item in the index always present in the db");
+ items.push(recipe.into());
+ }
+
+ Ok(SearchResult {
+ total_found,
+ items,
+ agg,
+ after,
+ })
+}
+
pub fn main() -> Result<()> {
let options = QueryOptions::from_args();
- let cantine = Cantine::open(options.base_path.join("tantivy"))?;
+ let (index, cantine) = Cantine::open(options.base_path.join("tantivy"))?;
let database = BincodeDatabase::open(options.base_path.join("database")).unwrap();
let stdin = stdin();
let reader = BufReader::new(stdin.lock());
+
+ let index_reader = index.reader()?;
+ let searcher = index_reader.searcher();
for line in reader.lines() {
let line = line.unwrap();
let query = serde_json::from_str(line.as_str()).expect("valid SearchQuery json");
eprintln!("Executing query {:?}", &query);
- let (total_found, recipe_ids, after, agg) = cantine.search(query, options.agg_threshold)?;
-
- let mut items = Vec::new();
- for recipe_id in recipe_ids {
- let recipe: Recipe = database
- .get_by_id(recipe_id)
- .expect("db operational")
- .expect("item in the index always present in the db");
- items.push(recipe.into());
- }
-
- let result = SearchResult {
- total_found,
- items,
- agg,
- after,
- };
+ let result = search(&database, &searcher, &cantine, query, options.agg_threshold)?;
println!("{}", serde_json::to_string(&result).unwrap());
}