Remove sub-arrays for Values.

This prevents using references and forces extra allocations during
queries as we have to adapt the values.

Also remove is_empty() as it si currently unused, and needs to be
adapted.
This commit is contained in:
2019-11-07 16:00:35 +01:00
parent 82050d6b75
commit 85d322877e
3 changed files with 45 additions and 116 deletions

View File

@@ -90,23 +90,27 @@ impl Core {
// Sort out the space, and create a SpaceDB per reference space
let mut space_dbs = vec![];
for space in spaces {
// Filter the points of this space, and encode them before creating the index.
let filtered = space_objects
.iter()
.filter_map(|object| {
if object.space_id() == space.name() {
let position: Vec<f64> = object.position().into();
Some(SpaceSetObject::new(
space.name(),
space.encode(&position).unwrap(),
*object.value(),
))
// We cannot return less that the total number of individual Ids stored
// in the index for a full-volume query.
let max_elements = if let Some(elem) = max_elements {
Some(elem.max(properties.len()))
} else {
None
};
for space in spaces {
// Filter the points of this space, and encode them before creating the index.
let mut filtered = space_objects
.iter()
.filter(|object| object.space_id() == space.name())
// Clone only the selected objects, not all of them!
.cloned()
.collect::<Vec<_>>();
for object in filtered.iter_mut() {
let position: Vec<f64> = object.position().into();
object.set_position(space.encode(&position).unwrap());
}
})
.collect();
space_dbs.push(SpaceDB::new(&space, filtered, scales.clone(), max_elements))
}
@@ -119,18 +123,6 @@ impl Core {
}
}
// Check if the given space_id is referenced in the current core.
pub fn is_empty(&self, space_id: &str) -> bool {
for s in &self.space_db {
if s.name() == space_id {
return s.is_empty();
}
}
// Not found, so the space is empty.
true
}
pub fn name(&self) -> &String {
&self.title
}

View File

@@ -93,18 +93,6 @@ impl DataBase {
}
}
// Check if the given space_id is referenced in the DB.
fn is_empty(&self, id: &str) -> bool {
for s in self.cores.keys() {
let core: &Core = self.cores.find(s)[0];
if !core.is_empty(id) {
return false;
}
}
true
}
fn check_exactly_one<'t, T>(list: &[&'t T], name: &str, value: &str) -> Result<&'t T, String> {
if list.len() > 1 {
Err(format!(

View File

@@ -1,11 +1,9 @@
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::collections::HashSet;
use std::hash::Hash;
use std::hash::Hasher;
use super::space::Coordinate;
use super::space::Position;
use super::space::Shape;
use super::space::Space;
@@ -18,7 +16,6 @@ use super::CoreQueryParameters;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SpaceDB {
reference_space: String,
values: Vec<Coordinate>,
resolutions: Vec<SpaceIndex>,
}
@@ -33,21 +30,6 @@ impl SpaceDB {
const DIMENSIONS: usize = 3;
const CELL_BITS: usize = 10;
let mut values = space_objects
.iter()
.map(|object| *object.value())
.collect::<HashSet<_>>()
.drain()
.collect::<Vec<_>>();
values.sort_unstable_by_key(|&c| c.u64());
space_objects.iter_mut().for_each(|object| {
// Update the values to point into the local (shorter) mapping array.
let val = values.binary_search(object.value()).unwrap();
object.set_value(val.into());
});
// Build the set of SpaceIndices.
let mut resolutions = vec![];
let mut indices = vec![];
@@ -108,9 +90,6 @@ impl SpaceDB {
} else {
// Generate scales, following max_elements
if let Some(max_elements) = max_elements {
// We cannot return less that the total number of individual Ids stored
// in the index for a full-volume query.
let max_elements = max_elements.max(values.len());
let mut count = 0;
// The next index should contain at most half the number of
@@ -127,8 +106,12 @@ impl SpaceDB {
// Generate coarser indices, until we reach the expect max_element
// values or we can't define bigger bit shift.
loop {
// Make sure we do not shift more position than available
let shift = if count >= 31 { 31 } else { count };
// Make sure we do not shift more position than available as well.
if space_objects.len() <= max_elements || count > 31 {
break;
}
let shift = count;
count += 1;
space_objects = space_objects
.into_iter()
@@ -162,10 +145,6 @@ impl SpaceDB {
vec![count, count, count],
shift,
));
if space_objects.len() <= max_elements || count == std::u32::MAX {
break;
}
}
// Generate indices as long as max is smaller than the number of point located in the whole space.
@@ -206,7 +185,6 @@ impl SpaceDB {
SpaceDB {
reference_space: reference_space.name().clone(),
values,
resolutions,
}
}
@@ -227,11 +205,6 @@ impl SpaceDB {
self.resolutions.len() - 1
}
// Is this Space DB empty?
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
fn resolution_from_volume(&self, volume: f64) -> usize {
for i in 0..self.resolutions.len() {
if volume <= self.resolutions[i].threshold() {
@@ -302,13 +275,6 @@ impl SpaceDB {
}
}
// Convert the value back to caller's references
fn decode_value(&self, objects: &mut Vec<(Position, SpaceFields)>) {
for (_, fields) in objects.iter_mut() {
fields.set_value(self.values[fields.value().u64() as usize]);
}
}
// Search by Id, a.k.a values
// The results are in encoded space coordinates.
pub fn get_by_id(
@@ -317,7 +283,6 @@ impl SpaceDB {
parameters: &CoreQueryParameters,
) -> Result<Vec<(Position)>, String> {
// Is that ID referenced in the current space?
if let Ok(offset) = self.values.binary_search(&id.into()) {
let index = self.resolution(parameters);
// Convert the view port to the encoded space coordinates
@@ -325,8 +290,8 @@ impl SpaceDB {
let view_port = parameters.view_port(space);
// Select the objects
let objects = self.resolutions[index]
.find_by_value(&SpaceFields::new(self.name().into(), offset.into()));
let objects =
self.resolutions[index].find_by_value(&SpaceFields::new(self.name().into(), id.into()));
let results = if let Some(view_port) = view_port {
objects
@@ -337,13 +302,7 @@ impl SpaceDB {
objects
};
// Convert the Value back to caller's references
// Here we do not use decode() as we have a single id value to manage.
Ok(results)
} else {
Ok(vec![])
}
}
// Search by positions defining a volume.
@@ -352,7 +311,7 @@ impl SpaceDB {
&self,
positions: &[Position],
parameters: &CoreQueryParameters,
) -> Result<Vec<(Position, SpaceFields)>, String> {
) -> Result<Vec<(Position, &SpaceFields)>, String> {
let index = self.resolution(parameters);
// FIXME: Should I do it here, or add the assumption this is a clean list?
@@ -361,19 +320,16 @@ impl SpaceDB {
//let view_port = parameters.view_port(space);
// Select the objects
let mut results = positions
let results = positions
.iter()
.flat_map(|position| {
self.resolutions[index]
.find(position)
.into_iter()
.map(move |fields| (position.clone(), fields.clone()))
.map(move |fields| (position.clone(), fields))
})
.collect();
// Decode the Value reference
self.decode_value(&mut results);
Ok(results)
}
@@ -387,7 +343,7 @@ impl SpaceDB {
&self,
shape: &Shape,
parameters: &CoreQueryParameters,
) -> Result<Vec<(Position, SpaceFields)>, String> {
) -> Result<Vec<(Position, &SpaceFields)>, String> {
let index = self.resolution(parameters);
// Convert the view port to the encoded space coordinates
@@ -395,14 +351,7 @@ impl SpaceDB {
let view_port = parameters.view_port(space);
// Select the objects
let mut results = self.resolutions[index]
.find_by_shape(&shape, &view_port)?
.into_iter()
.map(|(position, fields)| (position, fields.clone()))
.collect();
// Decode the Value reference
self.decode_value(&mut results);
let results = self.resolutions[index].find_by_shape(&shape, &view_port)?;
Ok(results)
}