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 // Sort out the space, and create a SpaceDB per reference space
let mut space_dbs = vec![]; let mut space_dbs = vec![];
// 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 { for space in spaces {
// Filter the points of this space, and encode them before creating the index. // Filter the points of this space, and encode them before creating the index.
let filtered = space_objects let mut filtered = space_objects
.iter() .iter()
.filter_map(|object| { .filter(|object| object.space_id() == space.name())
if object.space_id() == space.name() { // Clone only the selected objects, not all of them!
let position: Vec<f64> = object.position().into(); .cloned()
Some(SpaceSetObject::new( .collect::<Vec<_>>();
space.name(),
space.encode(&position).unwrap(), for object in filtered.iter_mut() {
*object.value(), let position: Vec<f64> = object.position().into();
)) object.set_position(space.encode(&position).unwrap());
} else { }
None
}
})
.collect();
space_dbs.push(SpaceDB::new(&space, filtered, scales.clone(), max_elements)) 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 { pub fn name(&self) -> &String {
&self.title &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> { fn check_exactly_one<'t, T>(list: &[&'t T], name: &str, value: &str) -> Result<&'t T, String> {
if list.len() > 1 { if list.len() > 1 {
Err(format!( Err(format!(

View File

@@ -1,11 +1,9 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher; use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap; use std::collections::HashMap;
use std::collections::HashSet;
use std::hash::Hash; use std::hash::Hash;
use std::hash::Hasher; use std::hash::Hasher;
use super::space::Coordinate;
use super::space::Position; use super::space::Position;
use super::space::Shape; use super::space::Shape;
use super::space::Space; use super::space::Space;
@@ -18,7 +16,6 @@ use super::CoreQueryParameters;
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SpaceDB { pub struct SpaceDB {
reference_space: String, reference_space: String,
values: Vec<Coordinate>,
resolutions: Vec<SpaceIndex>, resolutions: Vec<SpaceIndex>,
} }
@@ -33,21 +30,6 @@ impl SpaceDB {
const DIMENSIONS: usize = 3; const DIMENSIONS: usize = 3;
const CELL_BITS: usize = 10; 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. // Build the set of SpaceIndices.
let mut resolutions = vec![]; let mut resolutions = vec![];
let mut indices = vec![]; let mut indices = vec![];
@@ -108,9 +90,6 @@ impl SpaceDB {
} else { } else {
// Generate scales, following max_elements // Generate scales, following max_elements
if let Some(max_elements) = 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; let mut count = 0;
// The next index should contain at most half the number of // 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 // Generate coarser indices, until we reach the expect max_element
// values or we can't define bigger bit shift. // values or we can't define bigger bit shift.
loop { loop {
// Make sure we do not shift more position than available // Make sure we do not shift more position than available as well.
let shift = if count >= 31 { 31 } else { count }; if space_objects.len() <= max_elements || count > 31 {
break;
}
let shift = count;
count += 1; count += 1;
space_objects = space_objects space_objects = space_objects
.into_iter() .into_iter()
@@ -162,10 +145,6 @@ impl SpaceDB {
vec![count, count, count], vec![count, count, count],
shift, 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. // 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 { SpaceDB {
reference_space: reference_space.name().clone(), reference_space: reference_space.name().clone(),
values,
resolutions, resolutions,
} }
} }
@@ -227,11 +205,6 @@ impl SpaceDB {
self.resolutions.len() - 1 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 { fn resolution_from_volume(&self, volume: f64) -> usize {
for i in 0..self.resolutions.len() { for i in 0..self.resolutions.len() {
if volume <= self.resolutions[i].threshold() { 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 // Search by Id, a.k.a values
// The results are in encoded space coordinates. // The results are in encoded space coordinates.
pub fn get_by_id( pub fn get_by_id(
@@ -317,33 +283,26 @@ impl SpaceDB {
parameters: &CoreQueryParameters, parameters: &CoreQueryParameters,
) -> Result<Vec<(Position)>, String> { ) -> Result<Vec<(Position)>, String> {
// Is that ID referenced in the current space? // Is that ID referenced in the current space?
if let Ok(offset) = self.values.binary_search(&id.into()) { let index = self.resolution(parameters);
let index = self.resolution(parameters);
// Convert the view port to the encoded space coordinates // Convert the view port to the encoded space coordinates
let space = parameters.db.space(&self.reference_space)?; let space = parameters.db.space(&self.reference_space)?;
let view_port = parameters.view_port(space); let view_port = parameters.view_port(space);
// Select the objects // Select the objects
let objects = self.resolutions[index] let objects =
.find_by_value(&SpaceFields::new(self.name().into(), offset.into())); self.resolutions[index].find_by_value(&SpaceFields::new(self.name().into(), id.into()));
let results = if let Some(view_port) = view_port { let results = if let Some(view_port) = view_port {
objects objects
.into_iter() .into_iter()
.filter(|position| view_port.contains(position)) .filter(|position| view_port.contains(position))
.collect::<Vec<_>>() .collect::<Vec<_>>()
} else {
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 { } else {
Ok(vec![]) objects
} };
Ok(results)
} }
// Search by positions defining a volume. // Search by positions defining a volume.
@@ -352,7 +311,7 @@ impl SpaceDB {
&self, &self,
positions: &[Position], positions: &[Position],
parameters: &CoreQueryParameters, parameters: &CoreQueryParameters,
) -> Result<Vec<(Position, SpaceFields)>, String> { ) -> Result<Vec<(Position, &SpaceFields)>, String> {
let index = self.resolution(parameters); let index = self.resolution(parameters);
// FIXME: Should I do it here, or add the assumption this is a clean list? // 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); //let view_port = parameters.view_port(space);
// Select the objects // Select the objects
let mut results = positions let results = positions
.iter() .iter()
.flat_map(|position| { .flat_map(|position| {
self.resolutions[index] self.resolutions[index]
.find(position) .find(position)
.into_iter() .into_iter()
.map(move |fields| (position.clone(), fields.clone())) .map(move |fields| (position.clone(), fields))
}) })
.collect(); .collect();
// Decode the Value reference
self.decode_value(&mut results);
Ok(results) Ok(results)
} }
@@ -387,7 +343,7 @@ impl SpaceDB {
&self, &self,
shape: &Shape, shape: &Shape,
parameters: &CoreQueryParameters, parameters: &CoreQueryParameters,
) -> Result<Vec<(Position, SpaceFields)>, String> { ) -> Result<Vec<(Position, &SpaceFields)>, String> {
let index = self.resolution(parameters); let index = self.resolution(parameters);
// Convert the view port to the encoded space coordinates // Convert the view port to the encoded space coordinates
@@ -395,14 +351,7 @@ impl SpaceDB {
let view_port = parameters.view_port(space); let view_port = parameters.view_port(space);
// Select the objects // Select the objects
let mut results = self.resolutions[index] let results = self.resolutions[index].find_by_shape(&shape, &view_port)?;
.find_by_shape(&shape, &view_port)?
.into_iter()
.map(|(position, fields)| (position, fields.clone()))
.collect();
// Decode the Value reference
self.decode_value(&mut results);
Ok(results) Ok(results)
} }