Refactor Meilisearch, update to latest SDK, and implement faceted search (#44)

* feat(indexing): Reindex curseforge & local database at an interval

* fix(indexing): Use strings for meilisearch primary key

Fixes #17 by prefixing curseforge ids with "curse-" and local ids
with "local-".

* feat(indexing): Add newly created mods to the index more quickly

* feat(indexing): Implement faceted search, update to meilisearch master

Fixes #9, but only uses faceted search for categories.  It should
be reasonably simple to add support for versions, but it may not
be as useful due to the large number of versions and the large
number of supported versions for each mod.

* feat(indexing): Allow skipping initial indexing

Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
This commit is contained in:
Aeledfyr
2020-07-27 18:54:10 -05:00
committed by GitHub
parent 7914e89212
commit ff28ea8fa8
13 changed files with 441 additions and 201 deletions

View File

@@ -3,6 +3,7 @@ use crate::file_hosting::{FileHost, FileHostingError};
use crate::models::error::ApiError;
use crate::models::mods::{GameVersion, ModId, VersionId, VersionType};
use crate::models::teams::TeamMember;
use crate::search::indexing::queue::CreationQueue;
use actix_multipart::{Field, Multipart};
use actix_web::http::StatusCode;
use actix_web::web::Data;
@@ -10,6 +11,7 @@ use actix_web::{post, HttpResponse};
use futures::stream::StreamExt;
use serde::{Deserialize, Serialize};
use sqlx::postgres::PgPool;
use std::sync::Arc;
use thiserror::Error;
#[derive(Error, Debug)]
@@ -124,7 +126,8 @@ async fn undo_uploads(
pub async fn mod_create(
payload: Multipart,
client: Data<PgPool>,
file_host: Data<std::sync::Arc<dyn FileHost + Send + Sync>>,
file_host: Data<Arc<dyn FileHost + Send + Sync>>,
indexing_queue: Data<Arc<CreationQueue>>,
) -> Result<HttpResponse, CreateError> {
let mut transaction = client.begin().await?;
let mut uploaded_files = Vec::new();
@@ -134,6 +137,7 @@ pub async fn mod_create(
&mut transaction,
&***file_host,
&mut uploaded_files,
&***indexing_queue,
)
.await;
@@ -159,6 +163,7 @@ async fn mod_create_inner(
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
file_host: &dyn FileHost,
uploaded_files: &mut Vec<UploadedFile>,
indexing_queue: &CreationQueue,
) -> Result<HttpResponse, CreateError> {
let cdn_url = dotenv::var("CDN_URL")?;
@@ -377,6 +382,45 @@ async fn mod_create_inner(
initial_versions: created_versions,
};
let versions_list = mod_builder
.initial_versions
.iter()
.flat_map(|v| {
v.game_versions.iter().map(|id| id.0.to_string())
// TODO: proper version identifiers, once game versions
// have been implemented
})
.collect::<std::collections::HashSet<String>>()
.into_iter()
.collect::<Vec<_>>();
let now = chrono::Utc::now();
let timestamp = now.timestamp();
let formatted = now.to_string();
let index_mod = crate::search::UploadSearchMod {
mod_id: format!("local-{}", mod_id),
title: mod_builder.title.clone(),
description: mod_builder.description.clone(),
categories: create_data.categories.clone(),
versions: versions_list,
page_url: mod_builder.body_url.clone(),
icon_url: mod_builder.icon_url.clone().unwrap(),
// TODO: Author/team info, latest version info
author: String::new(),
author_url: String::new(),
latest_version: String::new(),
downloads: 0,
date_created: formatted.clone(),
created_timestamp: timestamp,
// TODO: store and return modified time
date_modified: formatted,
modified_timestamp: timestamp,
empty: std::borrow::Cow::Borrowed("{}{}{}"),
};
indexing_queue.add(index_mod);
let _mod_id = mod_builder.insert(&mut *transaction).await?;
// TODO: respond with the new mod info, or with just the new mod id.

View File

@@ -6,5 +6,6 @@ use actix_web::{get, web, HttpResponse};
pub async fn mod_search(
web::Query(info): web::Query<SearchRequest>,
) -> Result<HttpResponse, SearchError> {
Ok(HttpResponse::Ok().json(search_for_mod(&info)?))
let results = search_for_mod(&info).await?;
Ok(HttpResponse::Ok().json(results))
}