2018-10-03 22:21:33 +08:00
|
|
|
use std::str::from_utf8_unchecked;
|
|
|
|
use std::io::{self, Write};
|
2018-10-10 00:23:35 +08:00
|
|
|
use structopt::StructOpt;
|
|
|
|
use std::path::PathBuf;
|
2018-10-03 22:21:33 +08:00
|
|
|
|
|
|
|
use elapsed::measure_time;
|
|
|
|
use rocksdb::{DB, DBOptions, IngestExternalFileOptions};
|
2018-10-21 22:40:41 +08:00
|
|
|
use pentium::rank::{criterion, Config, RankedStream};
|
|
|
|
use pentium::{automaton, DocumentId, Metadata};
|
2018-10-03 22:21:33 +08:00
|
|
|
|
2018-10-10 00:23:35 +08:00
|
|
|
#[derive(Debug, StructOpt)]
|
|
|
|
pub struct CommandConsole {
|
|
|
|
/// Meta file name (e.g. relaxed-colden).
|
|
|
|
#[structopt(parse(from_os_str))]
|
|
|
|
pub meta_name: PathBuf,
|
|
|
|
}
|
2018-10-03 22:21:33 +08:00
|
|
|
|
|
|
|
pub struct ConsoleSearch {
|
|
|
|
metadata: Metadata,
|
|
|
|
db: DB,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ConsoleSearch {
|
|
|
|
pub fn from_command(command: CommandConsole) -> io::Result<ConsoleSearch> {
|
2018-10-10 00:23:35 +08:00
|
|
|
let map_file = command.meta_name.with_extension("map");
|
|
|
|
let idx_file = command.meta_name.with_extension("idx");
|
|
|
|
let sst_file = command.meta_name.with_extension("sst");
|
2018-10-03 22:21:33 +08:00
|
|
|
|
|
|
|
let metadata = unsafe { Metadata::from_paths(map_file, idx_file).unwrap() };
|
|
|
|
|
|
|
|
let rocksdb = "rocksdb/storage";
|
|
|
|
let db = DB::open_default(rocksdb).unwrap();
|
2018-10-10 00:23:35 +08:00
|
|
|
let sst_file = sst_file.to_str().unwrap();
|
|
|
|
db.ingest_external_file(&IngestExternalFileOptions::new(), &[sst_file]).unwrap();
|
2018-10-03 22:21:33 +08:00
|
|
|
drop(db);
|
|
|
|
let db = DB::open_for_read_only(DBOptions::default(), rocksdb, false).unwrap();
|
|
|
|
|
2018-10-21 22:42:19 +08:00
|
|
|
Ok(ConsoleSearch { metadata, db })
|
2018-10-03 22:21:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn serve(self) {
|
|
|
|
loop {
|
|
|
|
print!("Searching for: ");
|
|
|
|
io::stdout().flush().unwrap();
|
|
|
|
|
|
|
|
let mut query = String::new();
|
|
|
|
io::stdin().read_line(&mut query).unwrap();
|
|
|
|
|
|
|
|
if query.is_empty() { break }
|
|
|
|
|
2018-10-21 22:42:19 +08:00
|
|
|
let (elapsed, _) = measure_time(|| search(&self.metadata, &self.db, &query));
|
2018-10-03 22:21:33 +08:00
|
|
|
println!("Finished in {}", elapsed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-21 22:42:19 +08:00
|
|
|
fn search(metadata: &Metadata, database: &DB, query: &str) {
|
2018-10-03 22:21:33 +08:00
|
|
|
let mut automatons = Vec::new();
|
2018-10-21 22:42:19 +08:00
|
|
|
for query in query.split_whitespace().map(str::to_lowercase) {
|
|
|
|
let lev = automaton::build_prefix_dfa(&query);
|
2018-10-03 22:21:33 +08:00
|
|
|
automatons.push(lev);
|
|
|
|
}
|
|
|
|
|
2018-10-18 23:08:51 +08:00
|
|
|
let distinct_by_title_first_four_chars = |id: &DocumentId| {
|
|
|
|
let title_key = format!("{}-title", id);
|
|
|
|
match database.get(title_key.as_bytes()) {
|
|
|
|
Ok(Some(value)) => {
|
|
|
|
value.to_utf8().map(|s| s.chars().take(4).collect::<String>())
|
|
|
|
},
|
|
|
|
Ok(None) => None,
|
|
|
|
Err(err) => {
|
|
|
|
eprintln!("{:?}", err);
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// "Sony" "PlayStation 4 500GB"
|
2018-10-17 19:35:34 +08:00
|
|
|
let config = Config {
|
|
|
|
metadata: metadata,
|
|
|
|
automatons: automatons,
|
|
|
|
criteria: criterion::default(),
|
2018-10-18 23:08:51 +08:00
|
|
|
distinct: (distinct_by_title_first_four_chars, 1),
|
2018-10-17 19:35:34 +08:00
|
|
|
};
|
|
|
|
let stream = RankedStream::new(config);
|
2018-10-10 22:57:21 +08:00
|
|
|
|
2018-10-18 23:08:51 +08:00
|
|
|
let documents = stream.retrieve_distinct_documents(0..20);
|
|
|
|
// let documents = stream.retrieve_documents(0..20);
|
2018-10-11 20:04:41 +08:00
|
|
|
|
|
|
|
for document in documents {
|
2018-10-10 22:57:21 +08:00
|
|
|
let id_key = format!("{}-id", document.id);
|
2018-10-10 00:23:35 +08:00
|
|
|
let id = database.get(id_key.as_bytes()).unwrap().unwrap();
|
|
|
|
let id = unsafe { from_utf8_unchecked(&id) };
|
|
|
|
print!("{} ", id);
|
2018-10-03 22:21:33 +08:00
|
|
|
|
2018-10-10 22:57:21 +08:00
|
|
|
let title_key = format!("{}-title", document.id);
|
2018-10-03 22:21:33 +08:00
|
|
|
let title = database.get(title_key.as_bytes()).unwrap().unwrap();
|
|
|
|
let title = unsafe { from_utf8_unchecked(&title) };
|
2018-10-10 00:23:35 +08:00
|
|
|
println!("{:?}", title);
|
2018-10-03 22:21:33 +08:00
|
|
|
}
|
|
|
|
}
|
2018-10-10 00:23:35 +08:00
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let command = CommandConsole::from_args();
|
|
|
|
let console = ConsoleSearch::from_command(command).unwrap();
|
|
|
|
console.serve()
|
|
|
|
}
|