Compact results

This commit is contained in:
Dawid Ciężarkiewicz 2020-05-10 23:59:43 -07:00
parent 9833122928
commit fac7a4d5ac
3 changed files with 69 additions and 8 deletions

View File

@ -6,24 +6,30 @@ use async_trait::async_trait;
use log::info;
use std::collections::{HashMap, HashSet};
/// Indexing wrapper over `page::Store`
///
/// `Index` keeps track of page data neccessary
/// to quickly look them up by a tag query.
#[derive(Default)]
pub struct Index<T> {
page_ids_by_tag: HashMap<String, HashSet<Id>>,
tags_by_page_id: HashMap<Id, Vec<Tag>>,
tags_by_page_id: HashMap<Id, HashSet<Tag>>,
title_by_page_id: HashMap<Id, String>,
store: T,
}
/// Basic page info
#[derive(Debug, Clone)]
pub struct PageInfo {
pub id: Id,
pub title: String,
}
/// Results of tag query lookup
#[derive(Default, Debug, Clone)]
pub struct FindResults {
pub matching_pages: Vec<PageInfo>,
pub matching_tags: Vec<page::Tag>,
pub matching_tags: Vec<Tag>,
}
impl FindResults {
@ -32,6 +38,14 @@ impl FindResults {
}
}
/// More compact (post-processed) `FindResults`
pub struct CompactResults {
// all tags that were not already filtered on
pub tags: Vec<(Tag, usize)>,
// all pages that can't be reached by one of the `tags`
pub pages: Vec<PageInfo>,
}
impl<T> Index<T>
where
T: page::StoreMut,
@ -49,6 +63,7 @@ where
Ok(s)
}
/// Index the inner `Store`
async fn index_inner(&mut self) -> Result<()> {
let mut count = 0;
let ids = self.store.iter().await?.collect::<Vec<page::Id>>();
@ -60,9 +75,44 @@ where
info!("Indexed {} pages", count);
Ok(())
}
/// Compact the results to a shorter form
pub fn compact_results(&self, results: FindResults) -> CompactResults {
let matching_tags: HashSet<String> = results.matching_tags.iter().cloned().collect();
let mut unmatched_tags: HashMap<Tag, usize> = Default::default();
for page_info in &results.matching_pages {
for page_tag in &self.tags_by_page_id[&page_info.id] {
if !matching_tags.contains(page_tag.as_str()) {
*unmatched_tags.entry(page_tag.to_owned()).or_default() += 1;
}
}
}
let unmatched_tags_set: HashSet<Tag> = unmatched_tags.keys().cloned().collect();
let mut pages: Vec<PageInfo> = results
.matching_pages
.into_iter()
.filter(|page_info| {
unmatched_tags_set
.intersection(&self.tags_by_page_id[&page_info.id])
.next()
.is_none()
})
.collect();
pages.sort_by(|a, b| a.title.cmp(&b.title));
let mut tags: Vec<_> = unmatched_tags.into_iter().collect();
tags.sort_by(|a, b| a.1.cmp(&b.1).reverse().then_with(|| a.0.cmp(&b.0)));
CompactResults { tags, pages }
}
}
impl<T> Index<T> {
/// Lookup pages with a list of tags
pub fn find(&self, tags: &[TagRef]) -> FindResults {
let mut matching_pages: Vec<PageInfo> = vec![];
let mut matching_tags: Vec<String> = vec![];
@ -146,7 +196,7 @@ impl<T> Index<T> {
.tags_by_page_id
.get(&id)
.cloned()
.unwrap_or_else(|| vec![])
.unwrap_or_else(|| HashSet::new())
{
self.page_ids_by_tag
.get_mut(&tag)

View File

@ -8,7 +8,7 @@ use warp::{path::FullPath, Filter};
use serde_derive::Deserialize;
use page::StoreMut;
use page::{StoreMut, Tag};
/// Command line options
mod cli;
@ -157,7 +157,10 @@ fn render_page_view(page: &page::Parsed) -> impl RenderOnce {
}
}
fn render_post_list(posts: impl Iterator<Item = index::PageInfo> + 'static) -> impl RenderOnce {
fn render_post_list(
unmatched_tags: impl Iterator<Item = (Tag, usize)>,
posts: impl Iterator<Item = index::PageInfo> + 'static,
) -> impl RenderOnce {
owned_html! {
div(class="pure-menu pure-menu-horizontal") {
form(action="..", method="get", class="pure-menu-item") {
@ -173,6 +176,11 @@ fn render_post_list(posts: impl Iterator<Item = index::PageInfo> + 'static) -> i
}
}
ul {
@ for tag in unmatched_tags {
li {
a(href=format!("./{}", tag.0)) : format!("{} ({})", tag.0, tag.1)
}
}
@ for post in posts {
li {
a(href=format!("?id={}", post.id)) : post.title
@ -358,8 +366,10 @@ async fn handle_get(
query.edit.is_some(),
))))
} else {
let compact_results = read.compact_results(results);
Ok(warp_reply_from_render(render_html_page(render_post_list(
results.matching_pages.into_iter(),
compact_results.tags.into_iter(),
compact_results.pages.into_iter(),
))))
}
}

View File

@ -3,6 +3,7 @@ pub mod store;
#[allow(unused)]
use anyhow::Result;
use lazy_static::lazy_static;
use std::collections::HashSet;
pub use store::{InMemoryStore, Store, StoreMut};
use digest::Digest;
@ -23,7 +24,7 @@ pub struct Parsed {
pub source_body: String,
pub html: String,
pub headers: Headers,
pub tags: Vec<Tag>,
pub tags: HashSet<Tag>,
pub title: String,
}
@ -165,7 +166,7 @@ impl Parsed {
html: html_output,
source_body: body,
source: Source(source),
tags,
tags: tags.into_iter().collect(),
title,
}
}