mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-11-27 04:25:06 +08:00
Reworked the best proximity algo a little bit
This commit is contained in:
parent
302866ad73
commit
37a48489da
@ -3,8 +3,6 @@ use std::time::Instant;
|
|||||||
|
|
||||||
use pathfinding::directed::astar::astar_bag;
|
use pathfinding::directed::astar::astar_bag;
|
||||||
|
|
||||||
use crate::SmallVec16;
|
|
||||||
|
|
||||||
const ONE_ATTRIBUTE: u32 = 1000;
|
const ONE_ATTRIBUTE: u32 = 1000;
|
||||||
const MAX_DISTANCE: u32 = 8;
|
const MAX_DISTANCE: u32 = 8;
|
||||||
|
|
||||||
@ -28,47 +26,57 @@ fn extract_position(position: u32) -> (u32, u32) {
|
|||||||
(position / ONE_ATTRIBUTE, position % ONE_ATTRIBUTE)
|
(position / ONE_ATTRIBUTE, position % ONE_ATTRIBUTE)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
struct Path(SmallVec16<u32>);
|
enum Node {
|
||||||
|
// Is this node is the first node.
|
||||||
|
Uninit,
|
||||||
|
Init {
|
||||||
|
// The layer where this node located.
|
||||||
|
layer: usize,
|
||||||
|
// The position where this node is located.
|
||||||
|
position: u32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
impl Path {
|
impl Node {
|
||||||
// TODO we must skip the successors that have already been sent
|
// TODO we must skip the successors that have already been seen
|
||||||
// TODO we must skip the successors that doesn't return any documents
|
// TODO we must skip the successors that doesn't return any documents
|
||||||
// this way we are able to skip entire paths
|
// this way we are able to skip entire paths
|
||||||
fn successors(&self, positions: &[Vec<u32>], best_proximity: u32) -> Vec<(Path, u32)> {
|
fn successors(&self, positions: &[Vec<u32>], best_proximity: u32) -> Vec<(Node, u32)> {
|
||||||
let next_positions = match positions.get(self.0.len()) {
|
match self {
|
||||||
Some(positions) => positions,
|
Node::Uninit => {
|
||||||
None => return vec![],
|
positions[0].iter().map(|p| (Node::Init { layer: 0, position: *p }, 0)).collect()
|
||||||
};
|
},
|
||||||
|
// We reached the highest layer
|
||||||
next_positions.iter()
|
n @ Node::Init { .. } if n.is_complete(positions) => vec![],
|
||||||
.filter_map(|p| {
|
Node::Init { layer, position } => {
|
||||||
let mut path = self.clone();
|
let layer = layer + 1;
|
||||||
path.0.push(*p);
|
positions[layer].iter().filter_map(|p| {
|
||||||
let proximity = path.proximity();
|
let proximity = positions_proximity(*position, *p);
|
||||||
if path.is_complete(positions) && proximity < best_proximity {
|
let node = Node::Init { layer, position: *p };
|
||||||
None
|
// We do not produce the nodes we have already seen in previous iterations loops.
|
||||||
} else {
|
if node.is_complete(positions) && proximity < best_proximity {
|
||||||
Some((path, proximity))
|
None
|
||||||
}
|
} else {
|
||||||
})
|
Some((node, proximity))
|
||||||
.inspect(|p| eprintln!("{:?}", p))
|
}
|
||||||
.collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fn proximity(&self) -> u32 {
|
|
||||||
self.0.windows(2).map(|ps| positions_proximity(ps[0], ps[1])).sum::<u32>()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn heuristic(&self, positions: &[Vec<u32>]) -> u32 {
|
|
||||||
let remaining = (positions.len() - self.0.len()) as u32;
|
|
||||||
self.proximity() + remaining * MAX_DISTANCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_complete(&self, positions: &[Vec<u32>]) -> bool {
|
fn is_complete(&self, positions: &[Vec<u32>]) -> bool {
|
||||||
let res = positions.len() == self.0.len();
|
match self {
|
||||||
eprintln!("is_complete: {:?} {}", self, res);
|
Node::Uninit => false,
|
||||||
res
|
Node::Init { layer, .. } => *layer == positions.len() - 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn position(&self) -> Option<u32> {
|
||||||
|
match self {
|
||||||
|
Node::Uninit => None,
|
||||||
|
Node::Init { position, .. } => Some(*position),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,13 +101,11 @@ impl Iterator for BestProximity {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We start with nothing
|
|
||||||
let start = Path::default();
|
|
||||||
let result = astar_bag(
|
let result = astar_bag(
|
||||||
&start,
|
&Node::Uninit, // start
|
||||||
|p| p.successors(&self.positions, self.best_proximity),
|
|n| n.successors(&self.positions, self.best_proximity),
|
||||||
|p| p.heuristic(&self.positions),
|
|_| 0, // heuristic
|
||||||
|p| p.is_complete(&self.positions), // success
|
|n| n.is_complete(&self.positions), // success
|
||||||
);
|
);
|
||||||
|
|
||||||
eprintln!("BestProximity::next() took {:.02?}", before.elapsed());
|
eprintln!("BestProximity::next() took {:.02?}", before.elapsed());
|
||||||
@ -108,9 +114,7 @@ impl Iterator for BestProximity {
|
|||||||
Some((paths, proximity)) => {
|
Some((paths, proximity)) => {
|
||||||
self.best_proximity = proximity + 1;
|
self.best_proximity = proximity + 1;
|
||||||
// We retrieve the last path that we convert into a Vec
|
// We retrieve the last path that we convert into a Vec
|
||||||
let paths: Vec<_> = paths.map(|p| {
|
let paths: Vec<_> = paths.map(|p| p.iter().filter_map(Node::position).collect()).collect();
|
||||||
p.last().unwrap().0.to_vec()
|
|
||||||
}).collect();
|
|
||||||
eprintln!("result: {} {:?}", proximity, paths);
|
eprintln!("result: {} {:?}", proximity, paths);
|
||||||
Some((proximity, paths))
|
Some((proximity, paths))
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user