use self::symboltable::SymbolTable;
use annis::db::AnnotationStorage;
use annis::db::Match;
use annis::errors::*;
use annis::types::{AnnoKey, AnnoKeyID, Annotation};
use annis::types::{Edge, NodeID};
use annis::util;
use annis::util::memory_estimation;
use bincode;
use itertools::Itertools;
use malloc_size_of::MallocSizeOf;
use rand;
use regex;
use regex_syntax;
use rustc_hash::{FxHashMap, FxHashSet};
use serde;
use serde::de::DeserializeOwned;
use std;
use std::collections::BTreeMap;
use std::collections::Bound::*;
use std::hash::Hash;
use std::path::PathBuf;
#[derive(Serialize, Deserialize, Clone, Debug, Default, MallocSizeOf)]
struct SparseAnnotation {
key: usize,
val: usize,
}
#[derive(Serialize, Deserialize, Clone, Default, MallocSizeOf)]
pub struct AnnoStorage<T: Ord + Hash + MallocSizeOf + Default> {
by_container: FxHashMap<T, Vec<SparseAnnotation>>,
by_anno: FxHashMap<usize, FxHashMap<usize, Vec<T>>>,
#[with_malloc_size_of_func = "memory_estimation::size_of_btreemap"]
anno_key_sizes: BTreeMap<AnnoKey, usize>,
anno_keys: SymbolTable<AnnoKey>,
anno_values: SymbolTable<String>,
#[with_malloc_size_of_func = "memory_estimation::size_of_btreemap"]
histogram_bounds: BTreeMap<usize, Vec<String>>,
largest_item: Option<T>,
total_number_of_annos: usize,
}
impl<T: Ord + Hash + Clone + serde::Serialize + DeserializeOwned + MallocSizeOf + Default>
AnnoStorage<T>
{
pub fn new() -> AnnoStorage<T> {
AnnoStorage {
by_container: FxHashMap::default(),
by_anno: FxHashMap::default(),
anno_keys: SymbolTable::new(),
anno_values: SymbolTable::new(),
anno_key_sizes: BTreeMap::new(),
histogram_bounds: BTreeMap::new(),
largest_item: None,
total_number_of_annos: 0,
}
}
fn create_sparse_anno(&mut self, orig: Annotation) -> SparseAnnotation {
SparseAnnotation {
key: self.anno_keys.insert(orig.key),
val: self.anno_values.insert(orig.val),
}
}
fn create_annotation_from_sparse(&self, orig: &SparseAnnotation) -> Option<Annotation> {
let key = self.anno_keys.get_value(orig.key)?;
let val = self.anno_values.get_value(orig.val)?;
Some(Annotation {
key: key.clone(),
val: val.clone(),
})
}
fn remove_element_from_by_anno(&mut self, anno: &SparseAnnotation, item: &T) {
let remove_anno_key = if let Some(mut annos_for_key) = self.by_anno.get_mut(&anno.key) {
let remove_anno_val = if let Some(items_for_anno) = annos_for_key.get_mut(&anno.val) {
items_for_anno.retain(|i| i != item);
items_for_anno.is_empty()
} else {
false
};
if remove_anno_val {
annos_for_key.remove(&anno.val);
annos_for_key.is_empty()
} else {
false
}
} else {
false
};
if remove_anno_key {
self.by_anno.remove(&anno.key);
}
}
pub fn insert(&mut self, item: T, anno: Annotation) {
let orig_anno_key = anno.key.clone();
let anno = self.create_sparse_anno(anno);
let existing_anno = {
let existing_item_entry = self.by_container.entry(item.clone()).or_insert(Vec::new());
let existing_entry_idx =
existing_item_entry.binary_search_by_key(&anno.key, |a| a.key.clone());
if let Ok(existing_entry_idx) = existing_entry_idx {
let orig_anno = existing_item_entry[existing_entry_idx].clone();
if orig_anno.val == anno.val {
return;
}
existing_item_entry[existing_entry_idx] = anno.clone();
Some(orig_anno)
} else if let Err(insertion_idx) = existing_entry_idx {
existing_item_entry.insert(insertion_idx, anno.clone());
None
} else {
None
}
};
if let Some(ref existing_anno) = existing_anno {
self.remove_element_from_by_anno(existing_anno, &item);
}
self.by_anno
.entry(anno.key.clone())
.or_insert(FxHashMap::default())
.entry(anno.val.clone())
.or_insert(Vec::default())
.push(item.clone());
if existing_anno.is_none() {
self.total_number_of_annos += 1;
if let Some(largest_item) = self.largest_item.clone() {
if largest_item < item {
self.largest_item = Some(item.clone());
}
} else {
self.largest_item = Some(item.clone());
}
let anno_key_entry = self
.anno_key_sizes
.entry(orig_anno_key.clone())
.or_insert(0);
*anno_key_entry = *anno_key_entry + 1;
}
}
fn check_and_remove_value_symbol(&mut self, value_id: usize) {
let mut still_used = false;
for (_, values) in self.by_anno.iter() {
if values.contains_key(&value_id) {
still_used = true;
break;
}
}
if !still_used {
self.anno_values.remove(value_id);
}
}
pub fn remove_annotation_for_item(&mut self, item: &T, key: &AnnoKey) -> Option<String> {
let mut result = None;
let orig_key = key;
let key = self.anno_keys.get_symbol(key)?;
if let Some(mut all_annos) = self.by_container.remove(item) {
let anno_idx = all_annos.binary_search_by_key(&key, |a| a.key);
if let Ok(anno_idx) = anno_idx {
self.remove_element_from_by_anno(&all_annos[anno_idx], item);
let old_value = all_annos[anno_idx].val.clone();
all_annos.remove(anno_idx);
let new_key_count: usize =
if let Some(num_of_keys) = self.anno_key_sizes.get_mut(orig_key) {
*num_of_keys -= 1;
num_of_keys.clone()
} else {
0
};
if new_key_count == 0 {
self.by_anno.remove(&key);
self.anno_key_sizes.remove(&orig_key);
self.anno_keys.remove(key);
}
self.check_and_remove_value_symbol(old_value);
self.total_number_of_annos -= 1;
result = Some(old_value);
}
if !all_annos.is_empty() {
self.by_container.insert(item.clone(), all_annos);
}
}
if let Some(result) = result {
return self.anno_values.get_value(result).cloned();
}
return None;
}
pub fn get_value_for_item(&self, item: &T, key: &AnnoKey) -> Option<&str> {
let key = self.anno_keys.get_symbol(key)?;
if let Some(all_annos) = self.by_container.get(item) {
let idx = all_annos.binary_search_by_key(&key, |a| a.key);
if let Ok(idx) = idx {
if let Some(val) = self.anno_values.get_value(all_annos[idx].val) {
return Some(&val[..]);
}
}
}
return None;
}
pub fn get_value_for_item_by_id(&self, item: &T, key_id: AnnoKeyID) -> Option<&str> {
if let Some(all_annos) = self.by_container.get(item) {
let idx = all_annos.binary_search_by_key(&key_id, |a| a.key);
if let Ok(idx) = idx {
if let Some(val) = self.anno_values.get_value(all_annos[idx].val) {
return Some(&val[..]);
}
}
}
return None;
}
pub fn find_annotations_for_item(
&self,
item: &T,
ns: Option<String>,
name: Option<String>,
) -> Vec<AnnoKeyID> {
if let Some(name) = name {
if let Some(ns) = ns {
let key = AnnoKey { ns, name };
if let Some(key_id) = self.get_key_id(&key) {
if self.get_value_for_item_by_id(item, key_id).is_some() {
return vec![key_id];
}
}
return vec![];
} else {
let res: Vec<AnnoKeyID> = self
.get_qnames(&name)
.into_iter()
.filter_map(|key| self.get_key_id(&key))
.filter(|key_id| self.get_value_for_item_by_id(item, *key_id).is_some())
.collect();
return res;
}
} else {
if let Some(annos) = self.by_container.get(item) {
return annos.iter().map(|sparse_anno| sparse_anno.key).collect();
} else {
return vec![];
}
}
}
pub fn get_all_keys_for_item(&self, item: &T) -> Vec<AnnoKey> {
if let Some(all_annos) = self.by_container.get(item) {
let mut result: Vec<AnnoKey> = Vec::with_capacity(all_annos.len());
for a in all_annos.iter() {
if let Some(key) = self.anno_keys.get_value(a.key) {
result.push(key.clone());
}
}
return result;
}
return Vec::new();
}
fn get_annotations_for_item_impl(&self, item: &T) -> Vec<Annotation> {
if let Some(all_annos) = self.by_container.get(item) {
let mut result: Vec<Annotation> = Vec::with_capacity(all_annos.len());
for a in all_annos.iter() {
if let Some(a) = self.create_annotation_from_sparse(a) {
result.push(a);
}
}
return result;
}
return Vec::new();
}
pub fn clear(&mut self) {
self.by_container.clear();
self.by_anno.clear();
self.anno_keys.clear();
self.histogram_bounds.clear();
self.largest_item = None;
self.anno_values.clear();
}
pub fn get_qnames(&self, name: &str) -> Vec<AnnoKey> {
let it = self.anno_key_sizes.range(
AnnoKey {
name: name.to_owned(),
ns: String::default(),
}..,
);
let mut result: Vec<AnnoKey> = Vec::default();
for (k, _) in it {
if k.name == name {
result.push(k.clone());
} else {
break;
}
}
return result;
}
pub fn get_key_id(&self, key: &AnnoKey) -> Option<AnnoKeyID> {
self.anno_keys.get_symbol(key)
}
pub fn get_key_value(&self, key_id: AnnoKeyID) -> Option<AnnoKey> {
self.anno_keys.get_value(key_id).cloned()
}
fn get_all_values_impl(&self, key: &AnnoKey, most_frequent_first: bool) -> Vec<&str> {
if let Some(key) = self.anno_keys.get_symbol(key) {
if let Some(values_for_key) = self.by_anno.get(&key) {
if most_frequent_first {
let result = values_for_key
.iter()
.filter_map(|(val, items)| {
let val = self.anno_values.get_value(*val)?;
Some((items.len(), val))
}).sorted();
return result.into_iter().rev().map(|(_, val)| &val[..]).collect();
} else {
return values_for_key
.iter()
.filter_map(|(val, _items)| self.anno_values.get_value(*val))
.map(|val| &val[..])
.collect();
}
}
}
return vec![];
}
fn matching_items<'a>(
&'a self,
namespace: Option<String>,
name: String,
value: Option<String>,
) -> Box<Iterator<Item = (&T, AnnoKeyID)> + 'a> {
let key_ranges: Vec<AnnoKey> = if let Some(ns) = namespace {
vec![AnnoKey { ns, name }]
} else {
self.get_qnames(&name)
};
let values: Vec<(AnnoKeyID, &FxHashMap<usize, Vec<T>>)> = key_ranges
.into_iter()
.filter_map(|key| {
let key_id = self.anno_keys.get_symbol(&key)?;
if let Some(values_for_key) = self.by_anno.get(&key_id) {
Some((key_id, values_for_key))
} else {
None
}
}).collect();
if let Some(value) = value {
let target_value_symbol = self.anno_values.get_symbol(&value);
if let Some(target_value_symbol) = target_value_symbol {
let it = values
.into_iter()
.filter_map(move |(key_id, values)| if let Some(items) = values.get(&target_value_symbol) {
Some((items, key_id))
} else {
None
})
.flat_map(|(items, key_id)| items.iter().zip(std::iter::repeat(key_id)));
return Box::new(it);
} else {
return Box::new(std::iter::empty());
}
} else {
let it = values
.into_iter()
.flat_map(|(key_id, values)| values.iter().zip(std::iter::repeat(key_id)))
.flat_map(move | ((_, items), key_id) | {
items.iter().zip(std::iter::repeat(key_id))
});
return Box::new(it);
}
}
fn number_of_annotations_by_name_impl(&self, ns: Option<String>, name: String) -> usize {
let qualified_keys = match ns {
Some(ns) => self.anno_key_sizes.range((
Included(AnnoKey {
name: name.clone(),
ns: ns.clone(),
}),
Included(AnnoKey { name, ns }),
)),
None => self.anno_key_sizes.range(
AnnoKey {
name: name.clone(),
ns: String::default(),
}..AnnoKey {
name,
ns: std::char::MAX.to_string(),
},
),
};
let mut result = 0;
for (_anno_key, anno_size) in qualified_keys {
result += anno_size;
}
return result;
}
fn guess_max_count_impl(
&self,
ns: Option<String>,
name: String,
lower_val: &str,
upper_val: &str,
) -> usize {
let qualified_keys = match ns {
Some(ns) => vec![AnnoKey { name, ns }],
None => self.get_qnames(&name),
};
let mut universe_size: usize = 0;
let mut sum_histogram_buckets: usize = 0;
let mut count_matches: usize = 0;
for anno_key in qualified_keys.into_iter() {
if let Some(anno_size) = self.anno_key_sizes.get(&anno_key) {
universe_size += *anno_size;
if let Some(anno_key) = self.anno_keys.get_symbol(&anno_key) {
if let Some(histo) = self.histogram_bounds.get(&anno_key) {
if histo.len() >= 2 {
sum_histogram_buckets += histo.len() - 1;
for i in 0..histo.len() - 1 {
let bucket_begin = &histo[i];
let bucket_end = &histo[i + 1];
if bucket_begin <= &String::from(upper_val)
&& &String::from(lower_val) <= bucket_end
{
count_matches += 1;
}
}
}
}
}
}
}
if sum_histogram_buckets > 0 {
let selectivity: f64 = (count_matches as f64) / (sum_histogram_buckets as f64);
return (selectivity * (universe_size as f64)).round() as usize;
} else {
return 0;
}
}
fn guess_max_count_regex_impl(&self, ns: Option<String>, name: String, pattern: &str) -> usize {
let full_match_pattern = util::regex_full_match(pattern);
let parsed = regex_syntax::Parser::new().parse(&full_match_pattern);
if let Ok(parsed) = parsed {
let expr: regex_syntax::hir::Hir = parsed;
let prefix_set = regex_syntax::hir::literal::Literals::prefixes(&expr);
let val_prefix = std::str::from_utf8(prefix_set.longest_common_prefix());
if val_prefix.is_ok() {
let lower_val = val_prefix.unwrap();
let mut upper_val = String::from(lower_val);
upper_val.push(std::char::MAX);
return self.guess_max_count_impl(ns, name, &lower_val, &upper_val);
}
}
return 0;
}
pub fn get_largest_item(&self) -> Option<T> {
self.largest_item.clone()
}
pub fn calculate_statistics(&mut self) {
let max_histogram_buckets = 250;
let max_sampled_annotations = 2500;
self.histogram_bounds.clear();
for (anno_key, _num_of_annos) in &self.anno_key_sizes {
if let Some(anno_key) = self.anno_keys.get_symbol(anno_key) {
let mut rng = rand::thread_rng();
if let Some(values_for_key) = self.by_anno.get(&anno_key) {
let sampled_anno_values: Vec<usize> = values_for_key
.iter()
.flat_map(|(val, items)| {
let v = vec![val.clone(); items.len()];
v.into_iter()
}).collect();
let sampled_anno_indexes: FxHashSet<usize> = rand::seq::sample_indices(
&mut rng,
sampled_anno_values.len(),
std::cmp::min(sampled_anno_values.len(), max_sampled_annotations),
).into_iter()
.collect();
let mut sampled_anno_values: Vec<String> = sampled_anno_values
.into_iter()
.enumerate()
.filter(|x| sampled_anno_indexes.contains(&x.0))
.filter_map(|x| self.anno_values.get_value(x.1).cloned())
.collect();
sampled_anno_values.sort();
let num_hist_bounds = if sampled_anno_values.len() < (max_histogram_buckets + 1)
{
sampled_anno_values.len()
} else {
max_histogram_buckets + 1
};
let hist = self
.histogram_bounds
.entry(anno_key.clone())
.or_insert(std::vec::Vec::new());
if num_hist_bounds >= 2 {
hist.resize(num_hist_bounds, String::from(""));
let delta: usize = (sampled_anno_values.len() - 1) / (num_hist_bounds - 1);
let delta_fraction: usize =
(sampled_anno_values.len() - 1) % (num_hist_bounds - 1);
let mut pos = 0;
let mut pos_fraction = 0;
for i in 0..num_hist_bounds {
hist[i] = sampled_anno_values[pos].clone();
pos += delta;
pos_fraction += delta_fraction;
if pos_fraction >= (num_hist_bounds - 1) {
pos += 1;
pos_fraction -= num_hist_bounds - 1;
}
}
}
}
}
}
}
pub fn load_from_file(&mut self, path: &str) -> Result<()> {
self.clear();
let path = PathBuf::from(path);
let f = std::fs::File::open(path.clone()).chain_err(|| {
format!(
"Could not load string storage from file {}",
path.to_string_lossy()
)
})?;
let mut reader = std::io::BufReader::new(f);
*self = bincode::deserialize_from(&mut reader)?;
self.anno_keys.after_deserialization();
self.anno_values.after_deserialization();
Ok(())
}
}
impl AnnotationStorage<NodeID> for AnnoStorage<NodeID> {
fn get_annotations_for_item(&self, item: &NodeID) -> Vec<Annotation> {
self.get_annotations_for_item_impl(item)
}
fn number_of_annotations(&self) -> usize {
self.total_number_of_annos
}
fn number_of_annotations_by_name(&self, ns: Option<String>, name: String) -> usize {
self.number_of_annotations_by_name_impl(ns, name)
}
fn exact_anno_search<'a>(
&'a self,
namespace: Option<String>,
name: String,
value: Option<String>,
) -> Box<Iterator<Item = Match> + 'a> {
let it =
self.matching_items(namespace, name, value)
.filter_map(move |(node, anno_key_id)| {
Some(Match {
node: *node,
anno_key: anno_key_id,
})
});
return Box::new(it);
}
fn regex_anno_search<'a>(
&'a self,
namespace: Option<String>,
name: String,
pattern: &str,
) -> Box<Iterator<Item = Match> + 'a> {
let full_match_pattern = util::regex_full_match(pattern);
let compiled_result = regex::Regex::new(&full_match_pattern);
if let Ok(re) = compiled_result {
let it = self
.matching_items(namespace, name, None)
.filter(move |(node, anno_key_id)| {
if let Some(val) = self.get_value_for_item_by_id(node, *anno_key_id) {
re.is_match(val.as_ref())
} else {
false
}
}).filter_map(move |(node, anno_key_id)| {
Some(Match {
node: *node,
anno_key: anno_key_id,
})
});
return Box::new(it);
} else {
return Box::new(std::iter::empty());
}
}
fn guess_max_count(
&self,
ns: Option<String>,
name: String,
lower_val: &str,
upper_val: &str,
) -> usize {
self.guess_max_count_impl(ns, name, lower_val, upper_val)
}
fn guess_max_count_regex(&self, ns: Option<String>, name: String, pattern: &str) -> usize {
self.guess_max_count_regex_impl(ns, name, pattern)
}
fn get_all_values(&self, key: &AnnoKey, most_frequent_first: bool) -> Vec<&str> {
self.get_all_values_impl(key, most_frequent_first)
}
fn annotation_keys(&self) -> Vec<AnnoKey> {
return self.anno_key_sizes.keys().cloned().collect();
}
}
impl AnnotationStorage<Edge> for AnnoStorage<Edge> {
fn get_annotations_for_item(&self, item: &Edge) -> Vec<Annotation> {
self.get_annotations_for_item_impl(item)
}
fn number_of_annotations(&self) -> usize {
self.total_number_of_annos
}
fn number_of_annotations_by_name(&self, ns: Option<String>, name: String) -> usize {
self.number_of_annotations_by_name_impl(ns, name)
}
fn exact_anno_search<'a>(
&'a self,
namespace: Option<String>,
name: String,
value: Option<String>,
) -> Box<Iterator<Item = Match> + 'a> {
let it =
self.matching_items(namespace, name, value)
.filter_map(move |(edge, anno_key_id)| {
Some(Match {
node: edge.source.clone(),
anno_key: anno_key_id,
})
});
return Box::new(it);
}
fn regex_anno_search<'a>(
&'a self,
namespace: Option<String>,
name: String,
pattern: &str,
) -> Box<Iterator<Item = Match> + 'a> {
let full_match_pattern = util::regex_full_match(pattern);
let compiled_result = regex::Regex::new(&full_match_pattern);
if let Ok(re) = compiled_result {
let it = self
.matching_items(namespace, name, None)
.filter(move |(node, anno_key_id)| {
if let Some(val) = self.get_value_for_item_by_id(node, *anno_key_id) {
re.is_match(val.as_ref())
} else {
false
}
}).filter_map(move |(edge, anno_key_id)| {
Some(Match {
node: edge.source.clone(),
anno_key: anno_key_id,
})
});
return Box::new(it);
} else {
return Box::new(std::iter::empty());
}
}
fn guess_max_count(
&self,
ns: Option<String>,
name: String,
lower_val: &str,
upper_val: &str,
) -> usize {
self.guess_max_count_impl(ns, name, lower_val, upper_val)
}
fn guess_max_count_regex(&self, ns: Option<String>, name: String, pattern: &str) -> usize {
self.guess_max_count_regex_impl(ns, name, pattern)
}
fn annotation_keys(&self) -> Vec<AnnoKey> {
return self.anno_key_sizes.keys().cloned().collect();
}
fn get_all_values(&self, key: &AnnoKey, most_frequent_first: bool) -> Vec<&str> {
self.get_all_values_impl(key, most_frequent_first)
}
}
mod symboltable;
#[cfg(test)]
mod tests;