Simplify graph-based ranking rule impl

This commit is contained in:
Loïc Lecrenier 2023-03-19 15:03:57 +01:00
parent dd491320e5
commit 825f742000
7 changed files with 77 additions and 103 deletions

View File

@ -88,9 +88,8 @@ pub struct GraphBasedRankingRuleState<G: RankingRuleGraphTrait> {
conditions_cache: ConditionDocIdsCache<G>, conditions_cache: ConditionDocIdsCache<G>,
/// Cache used to optimistically discard paths that resolve to no documents. /// Cache used to optimistically discard paths that resolve to no documents.
dead_ends_cache: DeadEndsCache<G::Condition>, dead_ends_cache: DeadEndsCache<G::Condition>,
/// A structure giving the list of possible costs from each node to the end node, /// A structure giving the list of possible costs from each node to the end node
/// along with a set of unavoidable edges that must be traversed to achieve that distance. all_distances: MappedInterner<Vec<u16>, QueryNode>,
all_distances: MappedInterner<Vec<(u16, SmallBitmap<G::Condition>)>, QueryNode>,
/// An index in the first element of `all_distances`, giving the cost of the next bucket /// An index in the first element of `all_distances`, giving the cost of the next bucket
cur_distance_idx: usize, cur_distance_idx: usize,
} }
@ -108,7 +107,7 @@ impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBase
) -> Result<()> { ) -> Result<()> {
let graph = RankingRuleGraph::build(ctx, query_graph.clone())?; let graph = RankingRuleGraph::build(ctx, query_graph.clone())?;
let condition_docids_cache = ConditionDocIdsCache::default(); let condition_docids_cache = ConditionDocIdsCache::default();
let dead_end_path_cache = DeadEndsCache::new(&graph.conditions_interner); let dead_ends_cache = DeadEndsCache::new(&graph.conditions_interner);
// Then pre-compute the cost of all paths from each node to the end node // Then pre-compute the cost of all paths from each node to the end node
let all_distances = graph.initialize_distances_with_necessary_edges(); let all_distances = graph.initialize_distances_with_necessary_edges();
@ -116,7 +115,7 @@ impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBase
let state = GraphBasedRankingRuleState { let state = GraphBasedRankingRuleState {
graph, graph,
conditions_cache: condition_docids_cache, conditions_cache: condition_docids_cache,
dead_ends_cache: dead_end_path_cache, dead_ends_cache,
all_distances, all_distances,
cur_distance_idx: 0, cur_distance_idx: 0,
}; };
@ -149,7 +148,7 @@ impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBase
} }
// Retrieve the cost of the paths to compute // Retrieve the cost of the paths to compute
let (cost, _) = let cost =
state.all_distances.get(state.graph.query_graph.root_node)[state.cur_distance_idx]; state.all_distances.get(state.graph.query_graph.root_node)[state.cur_distance_idx];
state.cur_distance_idx += 1; state.cur_distance_idx += 1;
@ -158,7 +157,7 @@ impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBase
let GraphBasedRankingRuleState { let GraphBasedRankingRuleState {
graph, graph,
conditions_cache: condition_docids_cache, conditions_cache: condition_docids_cache,
dead_ends_cache: dead_end_path_cache, dead_ends_cache,
all_distances, all_distances,
cur_distance_idx: _, cur_distance_idx: _,
} = &mut state; } = &mut state;
@ -174,15 +173,15 @@ impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBase
// For each path of the given cost, we will compute its associated // For each path of the given cost, we will compute its associated
// document ids. // document ids.
// In case the path does not resolve to any document id, we try to figure out why // In case the path does not resolve to any document id, we try to figure out why
// and update the `dead_end_path_cache` accordingly. // and update the `dead_ends_cache` accordingly.
// Updating the dead_end_path_cache helps speed up the execution of `visit_paths_of_cost` and reduces // Updating the dead_ends_cache helps speed up the execution of `visit_paths_of_cost` and reduces
// the number of future candidate paths given by that same function. // the number of future candidate paths given by that same function.
graph.visit_paths_of_cost( graph.visit_paths_of_cost(
graph.query_graph.root_node, graph.query_graph.root_node,
cost, cost,
all_distances, all_distances,
dead_end_path_cache, dead_ends_cache,
|path, graph, dead_end_path_cache| { |path, graph, dead_ends_cache| {
if universe.is_empty() { if universe.is_empty() {
return Ok(ControlFlow::Break(())); return Ok(ControlFlow::Break(()));
} }
@ -211,7 +210,7 @@ impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBase
// and caches accordingly and skip to the next candidate path. // and caches accordingly and skip to the next candidate path.
if condition_docids.is_empty() { if condition_docids.is_empty() {
// 1. Store in the cache that this edge is empty for this universe // 1. Store in the cache that this edge is empty for this universe
dead_end_path_cache.forbid_condition(latest_condition); dead_ends_cache.forbid_condition(latest_condition);
// 2. remove all the edges with this condition from the ranking rule graph // 2. remove all the edges with this condition from the ranking rule graph
graph.remove_edges_with_condition(latest_condition); graph.remove_edges_with_condition(latest_condition);
// 3. Also remove the entry from the condition_docids_cache, since we don't need it anymore // 3. Also remove the entry from the condition_docids_cache, since we don't need it anymore
@ -226,7 +225,7 @@ impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBase
let len_prefix = subpath_docids.len() - 1; let len_prefix = subpath_docids.len() - 1;
// First, we know that this path is empty, and thus any path // First, we know that this path is empty, and thus any path
// that is a superset of it will also be empty. // that is a superset of it will also be empty.
dead_end_path_cache.forbid_condition_after_prefix( dead_ends_cache.forbid_condition_after_prefix(
visited_conditions[..len_prefix].iter().copied(), visited_conditions[..len_prefix].iter().copied(),
latest_condition, latest_condition,
); );
@ -244,7 +243,7 @@ impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBase
}; };
subprefix.push(*past_condition); subprefix.push(*past_condition);
if condition_docids.is_disjoint(subpath_docids) { if condition_docids.is_disjoint(subpath_docids) {
dead_end_path_cache.forbid_condition_after_prefix( dead_ends_cache.forbid_condition_after_prefix(
subprefix.iter().copied(), subprefix.iter().copied(),
latest_condition, latest_condition,
); );
@ -253,8 +252,8 @@ impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBase
// keep the same prefix and check the intersection with // keep the same prefix and check the intersection with
// all the remaining conditions // all the remaining conditions
let mut forbidden = dead_end_path_cache.forbidden.clone(); let mut forbidden = dead_ends_cache.forbidden.clone();
let mut cursor = dead_end_path_cache; let mut cursor = dead_ends_cache;
for &c in visited_conditions[..len_prefix].iter() { for &c in visited_conditions[..len_prefix].iter() {
cursor = cursor.advance(c).unwrap(); cursor = cursor.advance(c).unwrap();
forbidden.union(&cursor.forbidden); forbidden.union(&cursor.forbidden);
@ -301,7 +300,7 @@ impl<'ctx, G: RankingRuleGraphTrait> RankingRule<'ctx, QueryGraph> for GraphBase
G::log_state( G::log_state(
&original_graph, &original_graph,
&good_paths, &good_paths,
dead_end_path_cache, dead_ends_cache,
original_universe, original_universe,
all_distances, all_distances,
cost, cost,

View File

@ -44,17 +44,17 @@ pub enum SearchEvents {
ProximityState { ProximityState {
graph: RankingRuleGraph<ProximityGraph>, graph: RankingRuleGraph<ProximityGraph>,
paths: Vec<Vec<Interned<ProximityCondition>>>, paths: Vec<Vec<Interned<ProximityCondition>>>,
dead_end_path_cache: DeadEndsCache<ProximityCondition>, dead_ends_cache: DeadEndsCache<ProximityCondition>,
universe: RoaringBitmap, universe: RoaringBitmap,
distances: MappedInterner<Vec<(u16, SmallBitmap<ProximityCondition>)>, QueryNode>, distances: MappedInterner<Vec<u16>, QueryNode>,
cost: u16, cost: u16,
}, },
TypoState { TypoState {
graph: RankingRuleGraph<TypoGraph>, graph: RankingRuleGraph<TypoGraph>,
paths: Vec<Vec<Interned<TypoCondition>>>, paths: Vec<Vec<Interned<TypoCondition>>>,
dead_end_path_cache: DeadEndsCache<TypoCondition>, dead_ends_cache: DeadEndsCache<TypoCondition>,
universe: RoaringBitmap, universe: RoaringBitmap,
distances: MappedInterner<Vec<(u16, SmallBitmap<TypoCondition>)>, QueryNode>, distances: MappedInterner<Vec<u16>, QueryNode>,
cost: u16, cost: u16,
}, },
RankingRuleSkipBucket { RankingRuleSkipBucket {
@ -170,15 +170,15 @@ impl SearchLogger<QueryGraph> for DetailedSearchLogger {
&mut self, &mut self,
query_graph: &RankingRuleGraph<ProximityGraph>, query_graph: &RankingRuleGraph<ProximityGraph>,
paths_map: &[Vec<Interned<ProximityCondition>>], paths_map: &[Vec<Interned<ProximityCondition>>],
dead_end_path_cache: &DeadEndsCache<ProximityCondition>, dead_ends_cache: &DeadEndsCache<ProximityCondition>,
universe: &RoaringBitmap, universe: &RoaringBitmap,
distances: &MappedInterner<Vec<(u16, SmallBitmap<ProximityCondition>)>, QueryNode>, distances: &MappedInterner<Vec<u16>, QueryNode>,
cost: u16, cost: u16,
) { ) {
self.events.push(SearchEvents::ProximityState { self.events.push(SearchEvents::ProximityState {
graph: query_graph.clone(), graph: query_graph.clone(),
paths: paths_map.to_vec(), paths: paths_map.to_vec(),
dead_end_path_cache: dead_end_path_cache.clone(), dead_ends_cache: dead_ends_cache.clone(),
universe: universe.clone(), universe: universe.clone(),
distances: distances.clone(), distances: distances.clone(),
cost, cost,
@ -189,15 +189,15 @@ impl SearchLogger<QueryGraph> for DetailedSearchLogger {
&mut self, &mut self,
query_graph: &RankingRuleGraph<TypoGraph>, query_graph: &RankingRuleGraph<TypoGraph>,
paths_map: &[Vec<Interned<TypoCondition>>], paths_map: &[Vec<Interned<TypoCondition>>],
dead_end_path_cache: &DeadEndsCache<TypoCondition>, dead_ends_cache: &DeadEndsCache<TypoCondition>,
universe: &RoaringBitmap, universe: &RoaringBitmap,
distances: &MappedInterner<Vec<(u16, SmallBitmap<TypoCondition>)>, QueryNode>, distances: &MappedInterner<Vec<u16>, QueryNode>,
cost: u16, cost: u16,
) { ) {
self.events.push(SearchEvents::TypoState { self.events.push(SearchEvents::TypoState {
graph: query_graph.clone(), graph: query_graph.clone(),
paths: paths_map.to_vec(), paths: paths_map.to_vec(),
dead_end_path_cache: dead_end_path_cache.clone(), dead_ends_cache: dead_ends_cache.clone(),
universe: universe.clone(), universe: universe.clone(),
distances: distances.clone(), distances: distances.clone(),
cost, cost,
@ -357,7 +357,7 @@ results.{cur_ranking_rule}{cur_activated_id} {{
SearchEvents::ProximityState { SearchEvents::ProximityState {
graph, graph,
paths, paths,
dead_end_path_cache, dead_ends_cache,
universe, universe,
distances, distances,
cost, cost,
@ -373,7 +373,7 @@ results.{cur_ranking_rule}{cur_activated_id} {{
ctx, ctx,
graph, graph,
paths, paths,
dead_end_path_cache, dead_ends_cache,
distances.clone(), distances.clone(),
&mut new_file, &mut new_file,
); );
@ -390,7 +390,7 @@ results.{cur_ranking_rule}{cur_activated_id} {{
SearchEvents::TypoState { SearchEvents::TypoState {
graph, graph,
paths, paths,
dead_end_path_cache, dead_ends_cache,
universe, universe,
distances, distances,
cost, cost,
@ -406,7 +406,7 @@ results.{cur_ranking_rule}{cur_activated_id} {{
ctx, ctx,
graph, graph,
paths, paths,
dead_end_path_cache, dead_ends_cache,
distances.clone(), distances.clone(),
&mut new_file, &mut new_file,
); );
@ -429,7 +429,7 @@ results.{cur_ranking_rule}{cur_activated_id} {{
ctx: &mut SearchContext, ctx: &mut SearchContext,
node_idx: Interned<QueryNode>, node_idx: Interned<QueryNode>,
node: &QueryNode, node: &QueryNode,
distances: &[(u16, SmallBitmap<R::Condition>)], distances: &[u16],
file: &mut File, file: &mut File,
) { ) {
match &node.data { match &node.data {
@ -490,9 +490,8 @@ shape: class"
let p = ctx.word_interner.get(*use_prefix_db); let p = ctx.word_interner.get(*use_prefix_db);
writeln!(file, "use prefix DB : {p}").unwrap(); writeln!(file, "use prefix DB : {p}").unwrap();
} }
for (d, edges) in distances.iter() { for d in distances.iter() {
writeln!(file, "\"distance {d}\" : {:?}", edges.iter().collect::<Vec<_>>()) writeln!(file, "\"d_{d}\" : distance").unwrap();
.unwrap();
} }
writeln!(file, "}}").unwrap(); writeln!(file, "}}").unwrap();
@ -527,8 +526,8 @@ shape: class"
ctx: &mut SearchContext, ctx: &mut SearchContext,
graph: &RankingRuleGraph<R>, graph: &RankingRuleGraph<R>,
paths: &[Vec<Interned<R::Condition>>], paths: &[Vec<Interned<R::Condition>>],
dead_end_paths_cache: &DeadEndsCache<R::Condition>, _dead_ends_cache: &DeadEndsCache<R::Condition>,
distances: MappedInterner<Vec<(u16, SmallBitmap<R::Condition>)>, QueryNode>, distances: MappedInterner<Vec<u16>, QueryNode>,
file: &mut File, file: &mut File,
) { ) {
writeln!(file, "direction: right").unwrap(); writeln!(file, "direction: right").unwrap();

View File

@ -8,7 +8,6 @@ use super::query_graph::QueryNode;
use super::ranking_rule_graph::{ use super::ranking_rule_graph::{
DeadEndsCache, ProximityCondition, ProximityGraph, RankingRuleGraph, TypoCondition, TypoGraph, DeadEndsCache, ProximityCondition, ProximityGraph, RankingRuleGraph, TypoCondition, TypoGraph,
}; };
use super::small_bitmap::SmallBitmap;
use super::{RankingRule, RankingRuleQueryTrait}; use super::{RankingRule, RankingRuleQueryTrait};
/// Trait for structure logging the execution of a search query. /// Trait for structure logging the execution of a search query.
@ -66,9 +65,9 @@ pub trait SearchLogger<Q: RankingRuleQueryTrait> {
&mut self, &mut self,
query_graph: &RankingRuleGraph<ProximityGraph>, query_graph: &RankingRuleGraph<ProximityGraph>,
paths: &[Vec<Interned<ProximityCondition>>], paths: &[Vec<Interned<ProximityCondition>>],
dead_end_path_cache: &DeadEndsCache<ProximityCondition>, dead_ends_cache: &DeadEndsCache<ProximityCondition>,
universe: &RoaringBitmap, universe: &RoaringBitmap,
distances: &MappedInterner<Vec<(u16, SmallBitmap<ProximityCondition>)>, QueryNode>, distances: &MappedInterner<Vec<u16>, QueryNode>,
cost: u16, cost: u16,
); );
@ -77,9 +76,9 @@ pub trait SearchLogger<Q: RankingRuleQueryTrait> {
&mut self, &mut self,
query_graph: &RankingRuleGraph<TypoGraph>, query_graph: &RankingRuleGraph<TypoGraph>,
paths: &[Vec<Interned<TypoCondition>>], paths: &[Vec<Interned<TypoCondition>>],
dead_end_path_cache: &DeadEndsCache<TypoCondition>, dead_ends_cache: &DeadEndsCache<TypoCondition>,
universe: &RoaringBitmap, universe: &RoaringBitmap,
distances: &MappedInterner<Vec<(u16, SmallBitmap<TypoCondition>)>, QueryNode>, distances: &MappedInterner<Vec<u16>, QueryNode>,
cost: u16, cost: u16,
); );
} }
@ -137,9 +136,9 @@ impl<Q: RankingRuleQueryTrait> SearchLogger<Q> for DefaultSearchLogger {
&mut self, &mut self,
_query_graph: &RankingRuleGraph<ProximityGraph>, _query_graph: &RankingRuleGraph<ProximityGraph>,
_paths_map: &[Vec<Interned<ProximityCondition>>], _paths_map: &[Vec<Interned<ProximityCondition>>],
_dead_end_path_cache: &DeadEndsCache<ProximityCondition>, _dead_ends_cache: &DeadEndsCache<ProximityCondition>,
_universe: &RoaringBitmap, _universe: &RoaringBitmap,
_distances: &MappedInterner<Vec<(u16, SmallBitmap<ProximityCondition>)>, QueryNode>, _distances: &MappedInterner<Vec<u16>, QueryNode>,
_cost: u16, _cost: u16,
) { ) {
} }
@ -148,9 +147,9 @@ impl<Q: RankingRuleQueryTrait> SearchLogger<Q> for DefaultSearchLogger {
&mut self, &mut self,
_query_graph: &RankingRuleGraph<TypoGraph>, _query_graph: &RankingRuleGraph<TypoGraph>,
_paths: &[Vec<Interned<TypoCondition>>], _paths: &[Vec<Interned<TypoCondition>>],
_dead_end_path_cache: &DeadEndsCache<TypoCondition>, _dead_ends_cache: &DeadEndsCache<TypoCondition>,
_universe: &RoaringBitmap, _universe: &RoaringBitmap,
_distances: &MappedInterner<Vec<(u16, SmallBitmap<TypoCondition>)>, QueryNode>, _distances: &MappedInterner<Vec<u16>, QueryNode>,
_cost: u16, _cost: u16,
) { ) {
} }

View File

@ -1,7 +1,6 @@
#![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_arguments)]
use std::collections::btree_map::Entry; use std::collections::{BTreeSet, VecDeque};
use std::collections::{BTreeMap, VecDeque};
use std::ops::ControlFlow; use std::ops::ControlFlow;
use super::{DeadEndsCache, RankingRuleGraph, RankingRuleGraphTrait}; use super::{DeadEndsCache, RankingRuleGraph, RankingRuleGraphTrait};
@ -15,8 +14,8 @@ impl<G: RankingRuleGraphTrait> RankingRuleGraph<G> {
&mut self, &mut self,
from: Interned<QueryNode>, from: Interned<QueryNode>,
cost: u16, cost: u16,
all_distances: &MappedInterner<Vec<(u16, SmallBitmap<G::Condition>)>, QueryNode>, all_distances: &MappedInterner<Vec<u16>, QueryNode>,
dead_end_path_cache: &mut DeadEndsCache<G::Condition>, dead_ends_cache: &mut DeadEndsCache<G::Condition>,
mut visit: impl FnMut( mut visit: impl FnMut(
&[Interned<G::Condition>], &[Interned<G::Condition>],
&mut Self, &mut Self,
@ -27,11 +26,11 @@ impl<G: RankingRuleGraphTrait> RankingRuleGraph<G> {
from, from,
cost, cost,
all_distances, all_distances,
dead_end_path_cache, dead_ends_cache,
&mut visit, &mut visit,
&mut vec![], &mut vec![],
&mut SmallBitmap::for_interned_values_in(&self.conditions_interner), &mut SmallBitmap::for_interned_values_in(&self.conditions_interner),
dead_end_path_cache.forbidden.clone(), dead_ends_cache.forbidden.clone(),
)?; )?;
Ok(()) Ok(())
} }
@ -39,8 +38,8 @@ impl<G: RankingRuleGraphTrait> RankingRuleGraph<G> {
&mut self, &mut self,
from: Interned<QueryNode>, from: Interned<QueryNode>,
cost: u16, cost: u16,
all_distances: &MappedInterner<Vec<(u16, SmallBitmap<G::Condition>)>, QueryNode>, all_distances: &MappedInterner<Vec<u16>, QueryNode>,
dead_end_path_cache: &mut DeadEndsCache<G::Condition>, dead_ends_cache: &mut DeadEndsCache<G::Condition>,
visit: &mut impl FnMut( visit: &mut impl FnMut(
&[Interned<G::Condition>], &[Interned<G::Condition>],
&mut Self, &mut Self,
@ -62,7 +61,7 @@ impl<G: RankingRuleGraphTrait> RankingRuleGraph<G> {
None => { None => {
if edge.dest_node == self.query_graph.end_node { if edge.dest_node == self.query_graph.end_node {
any_valid = true; any_valid = true;
let control_flow = visit(prev_conditions, self, dead_end_path_cache)?; let control_flow = visit(prev_conditions, self, dead_ends_cache)?;
match control_flow { match control_flow {
ControlFlow::Continue(_) => {} ControlFlow::Continue(_) => {}
ControlFlow::Break(_) => return Ok(true), ControlFlow::Break(_) => return Ok(true),
@ -73,7 +72,7 @@ impl<G: RankingRuleGraphTrait> RankingRuleGraph<G> {
edge.dest_node, edge.dest_node,
cost - edge.cost as u16, cost - edge.cost as u16,
all_distances, all_distances,
dead_end_path_cache, dead_ends_cache,
visit, visit,
prev_conditions, prev_conditions,
cur_path, cur_path,
@ -83,12 +82,10 @@ impl<G: RankingRuleGraphTrait> RankingRuleGraph<G> {
} }
Some(condition) => { Some(condition) => {
if forbidden_conditions.contains(condition) if forbidden_conditions.contains(condition)
|| !all_distances.get(edge.dest_node).iter().any( || all_distances
|(next_cost, necessary_conditions)| { .get(edge.dest_node)
(*next_cost == cost - edge.cost as u16) .iter()
&& !forbidden_conditions.intersects(necessary_conditions) .all(|next_cost| *next_cost != cost - edge.cost as u16)
},
)
{ {
continue; continue;
} }
@ -96,14 +93,14 @@ impl<G: RankingRuleGraphTrait> RankingRuleGraph<G> {
prev_conditions.push(condition); prev_conditions.push(condition);
let mut new_forbidden_conditions = forbidden_conditions.clone(); let mut new_forbidden_conditions = forbidden_conditions.clone();
if let Some(next_forbidden) = if let Some(next_forbidden) =
dead_end_path_cache.forbidden_conditions_after_prefix(prev_conditions) dead_ends_cache.forbidden_conditions_after_prefix(prev_conditions)
{ {
new_forbidden_conditions.union(&next_forbidden); new_forbidden_conditions.union(&next_forbidden);
} }
let next_any_valid = if edge.dest_node == self.query_graph.end_node { let next_any_valid = if edge.dest_node == self.query_graph.end_node {
any_valid = true; any_valid = true;
let control_flow = visit(prev_conditions, self, dead_end_path_cache)?; let control_flow = visit(prev_conditions, self, dead_ends_cache)?;
match control_flow { match control_flow {
ControlFlow::Continue(_) => {} ControlFlow::Continue(_) => {}
ControlFlow::Break(_) => return Ok(true), ControlFlow::Break(_) => return Ok(true),
@ -114,7 +111,7 @@ impl<G: RankingRuleGraphTrait> RankingRuleGraph<G> {
edge.dest_node, edge.dest_node,
cost - edge.cost as u16, cost - edge.cost as u16,
all_distances, all_distances,
dead_end_path_cache, dead_ends_cache,
visit, visit,
prev_conditions, prev_conditions,
cur_path, cur_path,
@ -129,8 +126,8 @@ impl<G: RankingRuleGraphTrait> RankingRuleGraph<G> {
any_valid |= next_any_valid; any_valid |= next_any_valid;
if next_any_valid { if next_any_valid {
forbidden_conditions = dead_end_path_cache forbidden_conditions =
.forbidden_conditions_for_all_prefixes_up_to(prev_conditions); dead_ends_cache.forbidden_conditions_for_all_prefixes_up_to(prev_conditions);
if cur_path.intersects(&forbidden_conditions) { if cur_path.intersects(&forbidden_conditions) {
break 'edges_loop; break 'edges_loop;
} }
@ -140,16 +137,13 @@ impl<G: RankingRuleGraphTrait> RankingRuleGraph<G> {
Ok(any_valid) Ok(any_valid)
} }
pub fn initialize_distances_with_necessary_edges( pub fn initialize_distances_with_necessary_edges(&self) -> MappedInterner<Vec<u16>, QueryNode> {
&self,
) -> MappedInterner<Vec<(u16, SmallBitmap<G::Condition>)>, QueryNode> {
let mut distances_to_end = self.query_graph.nodes.map(|_| vec![]); let mut distances_to_end = self.query_graph.nodes.map(|_| vec![]);
let mut enqueued = SmallBitmap::new(self.query_graph.nodes.len()); let mut enqueued = SmallBitmap::new(self.query_graph.nodes.len());
let mut node_stack = VecDeque::new(); let mut node_stack = VecDeque::new();
*distances_to_end.get_mut(self.query_graph.end_node) = *distances_to_end.get_mut(self.query_graph.end_node) = vec![0];
vec![(0, SmallBitmap::for_interned_values_in(&self.conditions_interner))];
for prev_node in self.query_graph.nodes.get(self.query_graph.end_node).predecessors.iter() { for prev_node in self.query_graph.nodes.get(self.query_graph.end_node).predecessors.iter() {
node_stack.push_back(prev_node); node_stack.push_back(prev_node);
@ -157,35 +151,20 @@ impl<G: RankingRuleGraphTrait> RankingRuleGraph<G> {
} }
while let Some(cur_node) = node_stack.pop_front() { while let Some(cur_node) = node_stack.pop_front() {
let mut self_distances = BTreeMap::<u16, SmallBitmap<G::Condition>>::new(); let mut self_distances = BTreeSet::<u16>::new();
let cur_node_edges = &self.edges_of_node.get(cur_node); let cur_node_edges = &self.edges_of_node.get(cur_node);
for edge_idx in cur_node_edges.iter() { for edge_idx in cur_node_edges.iter() {
let edge = self.edges_store.get(edge_idx).as_ref().unwrap(); let edge = self.edges_store.get(edge_idx).as_ref().unwrap();
let succ_node = edge.dest_node; let succ_node = edge.dest_node;
let succ_distances = distances_to_end.get(succ_node); let succ_distances = distances_to_end.get(succ_node);
for (succ_distance, succ_necessary_conditions) in succ_distances { for succ_distance in succ_distances {
let mut potential_necessary_edges = self_distances.insert(edge.cost as u16 + succ_distance);
SmallBitmap::for_interned_values_in(&self.conditions_interner);
for condition in
edge.condition.into_iter().chain(succ_necessary_conditions.iter())
{
potential_necessary_edges.insert(condition);
}
match self_distances.entry(edge.cost as u16 + succ_distance) {
Entry::Occupied(mut prev_necessary_edges) => {
prev_necessary_edges.get_mut().intersection(&potential_necessary_edges);
}
Entry::Vacant(entry) => {
entry.insert(potential_necessary_edges);
}
}
} }
} }
let distances_to_end_cur_node = distances_to_end.get_mut(cur_node); let distances_to_end_cur_node = distances_to_end.get_mut(cur_node);
for (cost, necessary_edges) in self_distances.iter() { for cost in self_distances.iter() {
distances_to_end_cur_node.push((*cost, necessary_edges.clone())); distances_to_end_cur_node.push(*cost);
} }
*distances_to_end.get_mut(cur_node) = self_distances.into_iter().collect(); *distances_to_end.get_mut(cur_node) = self_distances.into_iter().collect();
for prev_node in self.query_graph.nodes.get(cur_node).predecessors.iter() { for prev_node in self.query_graph.nodes.get(cur_node).predecessors.iter() {

View File

@ -112,9 +112,9 @@ pub trait RankingRuleGraphTrait: Sized {
fn log_state( fn log_state(
graph: &RankingRuleGraph<Self>, graph: &RankingRuleGraph<Self>,
paths: &[Vec<Interned<Self::Condition>>], paths: &[Vec<Interned<Self::Condition>>],
dead_end_path_cache: &DeadEndsCache<Self::Condition>, dead_ends_cache: &DeadEndsCache<Self::Condition>,
universe: &RoaringBitmap, universe: &RoaringBitmap,
distances: &MappedInterner<Vec<(u16, SmallBitmap<Self::Condition>)>, QueryNode>, distances: &MappedInterner<Vec<u16>, QueryNode>,
cost: u16, cost: u16,
logger: &mut dyn SearchLogger<QueryGraph>, logger: &mut dyn SearchLogger<QueryGraph>,
); );

View File

@ -6,11 +6,10 @@ use std::iter::FromIterator;
use roaring::RoaringBitmap; use roaring::RoaringBitmap;
use super::{RankingRuleGraph, RankingRuleGraphTrait, DeadEndsCache}; use super::{DeadEndsCache, RankingRuleGraph, RankingRuleGraphTrait};
use crate::search::new::interner::{DedupInterner, Interned, MappedInterner}; use crate::search::new::interner::{DedupInterner, Interned, MappedInterner};
use crate::search::new::logger::SearchLogger; use crate::search::new::logger::SearchLogger;
use crate::search::new::query_term::{Phrase, QueryTerm}; use crate::search::new::query_term::{Phrase, QueryTerm};
use crate::search::new::small_bitmap::SmallBitmap;
use crate::search::new::{QueryGraph, QueryNode, SearchContext}; use crate::search::new::{QueryGraph, QueryNode, SearchContext};
use crate::Result; use crate::Result;
@ -66,13 +65,13 @@ impl RankingRuleGraphTrait for ProximityGraph {
fn log_state( fn log_state(
graph: &RankingRuleGraph<Self>, graph: &RankingRuleGraph<Self>,
paths: &[Vec<Interned<ProximityCondition>>], paths: &[Vec<Interned<ProximityCondition>>],
dead_end_path_cache: &DeadEndsCache<Self::Condition>, dead_ends_cache: &DeadEndsCache<Self::Condition>,
universe: &RoaringBitmap, universe: &RoaringBitmap,
distances: &MappedInterner<Vec<(u16, SmallBitmap<ProximityCondition>)>, QueryNode>, distances: &MappedInterner<Vec<u16>, QueryNode>,
cost: u16, cost: u16,
logger: &mut dyn SearchLogger<QueryGraph>, logger: &mut dyn SearchLogger<QueryGraph>,
) { ) {
logger.log_proximity_state(graph, paths, dead_end_path_cache, universe, distances, cost); logger.log_proximity_state(graph, paths, dead_ends_cache, universe, distances, cost);
} }
fn label_for_condition<'ctx>( fn label_for_condition<'ctx>(

View File

@ -5,7 +5,6 @@ use crate::search::new::interner::{DedupInterner, Interned, MappedInterner};
use crate::search::new::logger::SearchLogger; use crate::search::new::logger::SearchLogger;
use crate::search::new::query_graph::QueryNodeData; use crate::search::new::query_graph::QueryNodeData;
use crate::search::new::query_term::{LocatedQueryTerm, Phrase, QueryTerm}; use crate::search::new::query_term::{LocatedQueryTerm, Phrase, QueryTerm};
use crate::search::new::small_bitmap::SmallBitmap;
use crate::search::new::{QueryGraph, QueryNode, SearchContext}; use crate::search::new::{QueryGraph, QueryNode, SearchContext};
use crate::Result; use crate::Result;
use std::collections::HashSet; use std::collections::HashSet;
@ -136,13 +135,13 @@ impl RankingRuleGraphTrait for TypoGraph {
fn log_state( fn log_state(
graph: &RankingRuleGraph<Self>, graph: &RankingRuleGraph<Self>,
paths: &[Vec<Interned<TypoCondition>>], paths: &[Vec<Interned<TypoCondition>>],
dead_end_path_cache: &DeadEndsCache<TypoCondition>, dead_ends_cache: &DeadEndsCache<TypoCondition>,
universe: &RoaringBitmap, universe: &RoaringBitmap,
distances: &MappedInterner<Vec<(u16, SmallBitmap<TypoCondition>)>, QueryNode>, distances: &MappedInterner<Vec<u16>, QueryNode>,
cost: u16, cost: u16,
logger: &mut dyn SearchLogger<QueryGraph>, logger: &mut dyn SearchLogger<QueryGraph>,
) { ) {
logger.log_typo_state(graph, paths, dead_end_path_cache, universe, distances, cost); logger.log_typo_state(graph, paths, dead_ends_cache, universe, distances, cost);
} }
fn label_for_condition<'ctx>( fn label_for_condition<'ctx>(